Skip to content

Commit 05ce469

Browse files
authored
support postgresql modify vpc/subnetid and expose network ip (#1813)
* support postgresql attachment resource * add changelog and update doc * e2e passed tencentcloud_postgresql_instance_network_access_attachment * e2e passed tencentcloud_postgresql_readonly_group_network_access_attachment * add changelog and update doc * add e2e case for readonly group * adjust ro group logic * support postgresql: readonly instance * fix golangci-lint issues
1 parent 8383d78 commit 05ce469

11 files changed

+680
-36
lines changed

.changelog/1813.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_postgresql_instance: support to update `vpc_id` and `subnet_id`
3+
```
4+
5+
```release-note:enhancement
6+
resource/tencentcloud_postgresql_readonly_group: support to update `vpc_id` and `subnet_id`
7+
```
8+
9+
```release-note:enhancement
10+
resource/tencentcloud_postgresql_readonly_instance: support `private_access_ip` and `private_access_port` fields
11+
```

tencentcloud/resource_tc_postgresql_instance.go

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,12 @@ func resourceTencentCloudPostgresqlInstance() *schema.Resource {
268268

269269
"vpc_id": {
270270
Type: schema.TypeString,
271-
ForceNew: true,
272-
Optional: true,
271+
Required: true,
273272
Description: "ID of VPC.",
274273
},
275274
"subnet_id": {
276275
Type: schema.TypeString,
277-
ForceNew: true,
278-
Optional: true,
276+
Required: true,
279277
Description: "ID of subnet.",
280278
},
281279
"security_groups": {
@@ -807,6 +805,96 @@ func resourceTencentCloudPostgresqlInstanceUpdate(d *schema.ResourceData, meta i
807805
}
808806

809807
var outErr, inErr, checkErr error
808+
// update vpc and subnet
809+
if d.HasChange("vpc_id") || d.HasChange("subnet_id") {
810+
var (
811+
vpcOld string
812+
vpcNew string
813+
subnetOld string
814+
subnetNew string
815+
vipOld string
816+
vipNew string
817+
)
818+
819+
old, new := d.GetChange("vpc_id")
820+
if old != nil {
821+
vpcOld = old.(string)
822+
}
823+
if new != nil {
824+
vpcNew = new.(string)
825+
}
826+
827+
old, new = d.GetChange("subnet_id")
828+
if old != nil {
829+
subnetOld = old.(string)
830+
}
831+
if new != nil {
832+
subnetNew = new.(string)
833+
}
834+
835+
// Create new network first, then delete the old one
836+
request := postgresql.NewCreateDBInstanceNetworkAccessRequest()
837+
request.DBInstanceId = helper.String(instanceId)
838+
request.VpcId = helper.String(vpcNew)
839+
request.SubnetId = helper.String(subnetNew)
840+
// ip assigned by system
841+
request.IsAssignVip = helper.Bool(false)
842+
843+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
844+
result, e := meta.(*TencentCloudClient).apiV3Conn.UsePostgresqlClient().CreateDBInstanceNetworkAccess(request)
845+
if e != nil {
846+
return retryError(e)
847+
} else {
848+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
849+
}
850+
return nil
851+
})
852+
if err != nil {
853+
log.Printf("[CRITAL]%s create postgresql Instance NetworkAccess failed, reason:%+v", logId, err)
854+
return err
855+
}
856+
857+
service := PostgresqlService{client: meta.(*TencentCloudClient).apiV3Conn}
858+
// wait for new network enabled
859+
conf := BuildStateChangeConf([]string{}, []string{"opened"}, 3*readRetryTimeout, time.Second, service.PostgresqlDBInstanceNetworkAccessStateRefreshFunc(instanceId, vpcNew, subnetNew, vipOld, "", []string{}))
860+
if object, e := conf.WaitForState(); e != nil {
861+
return e
862+
} else {
863+
// find the vip assiged by system
864+
ret := object.(*postgresql.DBInstanceNetInfo)
865+
vipNew = *ret.Ip
866+
}
867+
868+
// wait unit network changing operation of instance done
869+
conf = BuildStateChangeConf([]string{}, []string{"running"}, 3*readRetryTimeout, time.Second, service.PostgresqlDBInstanceStateRefreshFunc(instanceId, []string{}))
870+
if _, e := conf.WaitForState(); e != nil {
871+
return e
872+
}
873+
874+
// delete the old one
875+
if v, ok := d.GetOk("private_access_ip"); ok {
876+
vipOld = v.(string)
877+
}
878+
if err := service.DeletePostgresqlDBInstanceNetworkAccessById(ctx, instanceId, vpcOld, subnetOld, vipOld); err != nil {
879+
return err
880+
}
881+
882+
// wait for old network removed
883+
conf = BuildStateChangeConf([]string{}, []string{"closed"}, 3*readRetryTimeout, time.Second, service.PostgresqlDBInstanceNetworkAccessStateRefreshFunc(instanceId, vpcOld, subnetOld, vipNew, vipOld, []string{}))
884+
if _, e := conf.WaitForState(); e != nil {
885+
return e
886+
}
887+
888+
// wait unit network changing operation of instance done
889+
conf = BuildStateChangeConf([]string{}, []string{"running"}, 3*readRetryTimeout, time.Second, service.PostgresqlDBInstanceStateRefreshFunc(instanceId, []string{}))
890+
if _, e := conf.WaitForState(); e != nil {
891+
return e
892+
}
893+
894+
// refresh the private ip with new one
895+
_ = d.Set("private_access_ip", vipNew)
896+
}
897+
810898
// update name
811899
if d.HasChange("name") {
812900
name := d.Get("name").(string)

tencentcloud/resource_tc_postgresql_instance_test.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,13 +422,33 @@ resource "tencentcloud_postgresql_instance" "test" {
422422
}
423423
`
424424

425-
const testAccPostgresqlInstanceUpdate string = testAccPostgresqlInstanceBasic + defaultVpcSubnets + `
425+
const testAccPGNewVpcSubnet = `
426+
resource "tencentcloud_vpc" "vpc" {
427+
cidr_block = "172.18.111.0/24"
428+
name = "test-pg-network-vpc"
429+
}
430+
431+
resource "tencentcloud_subnet" "subnet" {
432+
availability_zone = var.default_az
433+
cidr_block = "172.18.111.0/24"
434+
name = "test-pg-network-sub1"
435+
vpc_id = tencentcloud_vpc.vpc.id
436+
}
437+
438+
locals {
439+
new_vpc_id = tencentcloud_subnet.subnet.vpc_id
440+
new_subnet_id = tencentcloud_subnet.subnet.id
441+
}
442+
443+
`
444+
445+
const testAccPostgresqlInstanceUpdate string = testAccPGNewVpcSubnet + testAccPostgresqlInstanceBasic + defaultVpcSubnets + `
426446
resource "tencentcloud_postgresql_instance" "test" {
427447
name = "tf_postsql_instance_update"
428448
availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[5].name
429449
charge_type = "POSTPAID_BY_HOUR"
430-
vpc_id = local.vpc_id
431-
subnet_id = local.subnet_id
450+
vpc_id = local.new_vpc_id
451+
subnet_id = local.new_subnet_id
432452
engine_version = "13.3"
433453
root_password = "t1qaA2k1wgvfa3?ZZZ"
434454
charset = "LATIN1"
@@ -452,13 +472,13 @@ resource "tencentcloud_postgresql_instance" "test" {
452472
}
453473
`
454474

455-
const testAccPostgresqlInstanceUpgradeKernelVersion string = testAccPostgresqlInstanceBasic + defaultVpcSubnets + `
475+
const testAccPostgresqlInstanceUpgradeKernelVersion string = testAccPGNewVpcSubnet + testAccPostgresqlInstanceBasic + defaultVpcSubnets + `
456476
resource "tencentcloud_postgresql_instance" "test" {
457477
name = "tf_postsql_instance_update"
458478
availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[5].name
459479
charge_type = "POSTPAID_BY_HOUR"
460-
vpc_id = local.vpc_id
461-
subnet_id = local.subnet_id
480+
vpc_id = local.new_vpc_id
481+
subnet_id = local.new_subnet_id
462482
engine_version = "13.3"
463483
root_password = "t1qaA2k1wgvfa3?ZZZ"
464484
charset = "LATIN1"

tencentcloud/resource_tc_postgresql_readonly_group.go

Lines changed: 128 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"context"
2626
"fmt"
2727
"log"
28+
"time"
2829

2930
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
3031
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -61,7 +62,6 @@ func resourceTencentCloudPostgresqlReadonlyGroup() *schema.Resource {
6162
},
6263
"vpc_id": {
6364
Type: schema.TypeString,
64-
ForceNew: true,
6565
Required: true,
6666
Description: "VPC ID.",
6767
},
@@ -119,13 +119,13 @@ func resourceTencentCloudPostgresqlReadOnlyGroupCreate(d *schema.ResourceData, m
119119
logId := getLogId(contextNil)
120120

121121
var (
122-
request = postgresql.NewCreateReadOnlyGroupRequest()
123-
response *postgresql.CreateReadOnlyGroupResponse
124-
dbInstanceId string
122+
request = postgresql.NewCreateReadOnlyGroupRequest()
123+
response *postgresql.CreateReadOnlyGroupResponse
124+
msaterDbInstanceId string
125125
)
126126
if v, ok := d.GetOk("master_db_instance_id"); ok {
127127
request.MasterDBInstanceId = helper.String(v.(string))
128-
dbInstanceId = v.(string)
128+
msaterDbInstanceId = v.(string)
129129
}
130130
if v, ok := d.GetOk("name"); ok {
131131
request.Name = helper.String(v.(string))
@@ -189,7 +189,7 @@ func resourceTencentCloudPostgresqlReadOnlyGroupCreate(d *schema.ResourceData, m
189189
postgresqlService := PostgresqlService{client: meta.(*TencentCloudClient).apiV3Conn}
190190

191191
err = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
192-
groups, e := postgresqlService.DescribePostgresqlReadOnlyGroupById(ctx, dbInstanceId)
192+
groups, e := postgresqlService.DescribePostgresqlReadOnlyGroupById(ctx, msaterDbInstanceId)
193193
if e != nil {
194194
return retryError(e)
195195
}
@@ -238,29 +238,134 @@ func resourceTencentCloudPostgresqlReadOnlyGroupUpdate(d *schema.ResourceData, m
238238
defer logElapsed("resource.tencentcloud_postgresql_readonly_group.update")()
239239

240240
logId := getLogId(contextNil)
241+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
241242
request := postgresql.NewModifyReadOnlyGroupConfigRequest()
242243

243244
request.ReadOnlyGroupId = helper.String(d.Id())
244245

245-
if d.HasChange("name") {
246-
request.ReadOnlyGroupName = helper.String(d.Get("name").(string))
247-
}
248-
if d.HasChange("replay_lag_eliminate") {
249-
request.ReplayLagEliminate = helper.IntUint64(d.Get("replay_lag_eliminate").(int))
250-
}
251-
if d.HasChange("replay_latency_eliminate") {
252-
request.ReplayLatencyEliminate = helper.IntUint64(d.Get("replay_latency_eliminate").(int))
253-
}
254-
if d.HasChange("max_replay_lag") {
255-
request.MaxReplayLag = helper.IntUint64(d.Get("max_replay_lag").(int))
256-
}
257-
if d.HasChange("max_replay_latency") {
258-
request.MaxReplayLatency = helper.IntUint64(d.Get("max_replay_latency").(int))
259-
}
260-
if d.HasChange("min_delay_eliminate_reserve") {
261-
request.MinDelayEliminateReserve = helper.IntUint64(d.Get("min_delay_eliminate_reserve").(int))
246+
// update vpc and subnet
247+
if d.HasChange("vpc_id") || d.HasChange("subnet_id") {
248+
var (
249+
vpcOld string
250+
vpcNew string
251+
subnetOld string
252+
subnetNew string
253+
vipOld string
254+
vipNew string
255+
msaterDbInstanceId string
256+
)
257+
258+
if v, ok := d.GetOk("master_db_instance_id"); ok {
259+
msaterDbInstanceId = v.(string)
260+
}
261+
262+
old, new := d.GetChange("vpc_id")
263+
if old != nil {
264+
vpcOld = old.(string)
265+
}
266+
if new != nil {
267+
vpcNew = new.(string)
268+
}
269+
270+
old, new = d.GetChange("subnet_id")
271+
if old != nil {
272+
subnetOld = old.(string)
273+
}
274+
if new != nil {
275+
subnetNew = new.(string)
276+
}
277+
278+
service := PostgresqlService{client: meta.(*TencentCloudClient).apiV3Conn}
279+
// get the old ip before creating
280+
netInfos, err := service.DescribePostgresqlReadonlyGroupNetInfosById(ctx, msaterDbInstanceId, d.Id())
281+
if err != nil {
282+
return err
283+
}
284+
285+
var oldNetInfo *postgresql.DBInstanceNetInfo
286+
for _, info := range netInfos {
287+
if *info.NetType == "private" {
288+
if *info.VpcId == vpcOld && *info.SubnetId == subnetOld {
289+
oldNetInfo = info
290+
break
291+
}
292+
}
293+
}
294+
295+
if oldNetInfo != nil {
296+
vipOld = *oldNetInfo.Ip
297+
}
298+
299+
// Create new network first, then delete the old one
300+
request := postgresql.NewCreateReadOnlyGroupNetworkAccessRequest()
301+
request.ReadOnlyGroupId = helper.String(d.Id())
302+
request.VpcId = helper.String(vpcNew)
303+
request.SubnetId = helper.String(subnetNew)
304+
// ip assigned by system
305+
request.IsAssignVip = helper.Bool(false)
306+
307+
err = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
308+
result, e := meta.(*TencentCloudClient).apiV3Conn.UsePostgresqlClient().CreateReadOnlyGroupNetworkAccess(request)
309+
if e != nil {
310+
return retryError(e)
311+
} else {
312+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
313+
}
314+
return nil
315+
})
316+
if err != nil {
317+
log.Printf("[CRITAL]%s create postgresql ReadOnlyGroup NetworkAccess failed, reason:%+v", logId, err)
318+
return err
319+
}
320+
321+
// wait for new network enabled
322+
conf := BuildStateChangeConf([]string{}, []string{"opened"}, 3*readRetryTimeout, time.Second, service.PostgresqlReadonlyGroupNetworkAccessStateRefreshFunc(msaterDbInstanceId, d.Id(), vpcNew, subnetNew, vipOld, "", []string{}))
323+
324+
if object, e := conf.WaitForState(); e != nil {
325+
return e
326+
} else {
327+
// find the vip assiged by system
328+
ret := object.(*postgresql.DBInstanceNetInfo)
329+
vipNew = *ret.Ip
330+
}
331+
332+
log.Printf("[DEBUG]%s resourceTencentCloudPostgresqlReadOnlyGroupUpdate, msaterDbInstanceId:[%s], roGroupId:[%s], vpcOld:[%s], vpcNew:[%s], subnetOld:[%s], subnetNew:[%s], vipOld:[%s], vipNew:[%s]\n",
333+
logId, msaterDbInstanceId, d.Id(), vpcOld, vpcNew, subnetOld, subnetNew, vipOld, vipNew)
334+
335+
// wait unit network changing operation of ro group done
336+
conf = BuildStateChangeConf([]string{}, []string{"ok"}, 3*readRetryTimeout, time.Second, service.PostgresqlReadonlyGroupStateRefreshFunc(msaterDbInstanceId, d.Id(), []string{}))
337+
if _, e := conf.WaitForState(); e != nil {
338+
return e
339+
}
340+
341+
// delete the old one
342+
if err := service.DeletePostgresqlReadonlyGroupNetworkAccessById(ctx, d.Id(), vpcOld, subnetOld, vipOld); err != nil {
343+
return err
344+
}
345+
346+
// wait for old network removed
347+
conf = BuildStateChangeConf([]string{}, []string{"closed"}, 3*readRetryTimeout, time.Second, service.PostgresqlReadonlyGroupNetworkAccessStateRefreshFunc(msaterDbInstanceId, d.Id(), vpcOld, subnetOld, vipNew, vipOld, []string{}))
348+
if _, e := conf.WaitForState(); e != nil {
349+
return e
350+
}
351+
352+
// wait unit network changing operation of ro group done
353+
conf = BuildStateChangeConf([]string{}, []string{"ok"}, 3*readRetryTimeout, time.Second, service.PostgresqlReadonlyGroupStateRefreshFunc(msaterDbInstanceId, d.Id(), []string{}))
354+
if _, e := conf.WaitForState(); e != nil {
355+
return e
356+
}
357+
358+
// refresh the private ip with new one
262359
}
263360

361+
// required attributes
362+
request.ReadOnlyGroupName = helper.String(d.Get("name").(string))
363+
request.ReplayLagEliminate = helper.IntUint64(d.Get("replay_lag_eliminate").(int))
364+
request.ReplayLatencyEliminate = helper.IntUint64(d.Get("replay_latency_eliminate").(int))
365+
request.MaxReplayLag = helper.IntUint64(d.Get("max_replay_lag").(int))
366+
request.MaxReplayLatency = helper.IntUint64(d.Get("max_replay_latency").(int))
367+
request.MinDelayEliminateReserve = helper.IntUint64(d.Get("min_delay_eliminate_reserve").(int))
368+
264369
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
265370
result, e := meta.(*TencentCloudClient).apiV3Conn.UsePostgresqlClient().ModifyReadOnlyGroupConfig(request)
266371
if e != nil {

0 commit comments

Comments
 (0)