@@ -44,6 +44,61 @@ resource "tencentcloud_postgresql_instance" "foo" {
4444}
4545```
4646
47+ Create a multi available zone bucket
48+
49+ ```hcl
50+ variable "availability_zone" {
51+ default = "ap-guangzhou-6"
52+ }
53+
54+ variable "standby_availability_zone" {
55+ default = "ap-guangzhou-7"
56+ }
57+
58+ # create vpc
59+ resource "tencentcloud_vpc" "vpc" {
60+ name = "guagua_vpc_instance_test"
61+ cidr_block = "10.0.0.0/16"
62+ }
63+
64+ # create vpc subnet
65+ resource "tencentcloud_subnet" "subnet" {
66+ availability_zone = var.availability_zone
67+ name = "guagua_vpc_subnet_test"
68+ vpc_id = tencentcloud_vpc.vpc.id
69+ cidr_block = "10.0.20.0/28"
70+ is_multicast = false
71+ }
72+
73+ # create postgresql
74+ resource "tencentcloud_postgresql_instance" "foo" {
75+ name = "example"
76+ availability_zone = var.availability_zone
77+ charge_type = "POSTPAID_BY_HOUR"
78+ vpc_id = tencentcloud_vpc.vpc.id
79+ subnet_id = tencentcloud_subnet.subnet.id
80+ engine_version = "10.4"
81+ root_user = "root123"
82+ root_password = "Root123$"
83+ charset = "UTF8"
84+ project_id = 0
85+ memory = 2
86+ storage = 10
87+
88+ db_node_set {
89+ role = "Primary"
90+ zone = var.availability_zone
91+ }
92+ db_node_set {
93+ zone = var.standby_availability_zone
94+ }
95+
96+ tags = {
97+ test = "tf"
98+ }
99+ }
100+ ```
101+
47102Import
48103
49104postgresql instance can be imported using the id, e.g.
@@ -143,10 +198,26 @@ func resourceTencentCloudPostgresqlInstance() *schema.Resource {
143198 },
144199 "availability_zone" : {
145200 Type : schema .TypeString ,
201+ Required : true ,
146202 ForceNew : true ,
147- Optional : true ,
148- Computed : true ,
149- Description : "Availability zone." ,
203+ Description : "Availability zone. NOTE: If value modified but included in `db_node_set`, the diff will be suppressed." ,
204+ DiffSuppressFunc : func (k , o , n string , d * schema.ResourceData ) bool {
205+ if o == "" {
206+ return false
207+ }
208+ raw , ok := d .GetOk ("db_node_set" )
209+ if ! ok {
210+ return n == o
211+ }
212+ nodeZones := raw .(* schema.Set ).List ()
213+ for i := range nodeZones {
214+ item := nodeZones [i ].(map [string ]interface {})
215+ if zone , ok := item ["zone" ].(string ); ok && zone == n {
216+ return true
217+ }
218+ }
219+ return n == o
220+ },
150221 },
151222 "root_user" : {
152223 Type : schema .TypeString ,
@@ -193,6 +264,26 @@ func resourceTencentCloudPostgresqlInstance() *schema.Resource {
193264 Computed : true ,
194265 Description : "max_standby_streaming_delay applies when WAL data is being received via streaming replication. Units are milliseconds if not specified." ,
195266 },
267+ "db_node_set" : {
268+ Type : schema .TypeSet ,
269+ Optional : true ,
270+ Description : "Specify instance node info for disaster migration." ,
271+ Elem : & schema.Resource {
272+ Schema : map [string ]* schema.Schema {
273+ "role" : {
274+ Type : schema .TypeString ,
275+ Optional : true ,
276+ Default : "Standby" ,
277+ Description : "Indicates node type, available values:`Primary`, `Standby`. Default: `Standby`." ,
278+ },
279+ "zone" : {
280+ Type : schema .TypeString ,
281+ Required : true ,
282+ Description : "Indicates the node available zone." ,
283+ },
284+ },
285+ },
286+ },
196287 // Computed values
197288 "public_access_host" : {
198289 Type : schema .TypeString ,
@@ -250,6 +341,7 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
250341 username = d .Get ("root_user" ).(string )
251342 password = d .Get ("root_password" ).(string )
252343 charset = d .Get ("charset" ).(string )
344+ nodeSet = d .Get ("db_node_set" ).(* schema.Set ).List ()
253345 )
254346
255347 var period = 1
@@ -265,8 +357,8 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
265357 requestSecurityGroup = append (requestSecurityGroup , v .(string ))
266358 }
267359
268- // get speccode with engine_version and memory
269- outErr = resource .Retry (readRetryTimeout , func () * resource.RetryError {
360+ // get specCode with engine_version and memory
361+ outErr = resource .Retry (readRetryTimeout * 5 , func () * resource.RetryError {
270362 speccodes , inErr := postgresqlService .DescribeSpecinfos (ctx , zone )
271363 if inErr != nil {
272364 return retryError (inErr )
@@ -301,6 +393,28 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
301393 return fmt .Errorf (`The "memory" value: %d is invalid, Valid values are one of: %s` , memory , strings .Join (allowMemory , `, ` ))
302394 }
303395
396+ var dbNodeSet []* postgresql.DBNode
397+ if len (nodeSet ) > 0 {
398+
399+ for i := range nodeSet {
400+ var (
401+ item = nodeSet [i ].(map [string ]interface {})
402+ role = item ["role" ].(string )
403+ zone = item ["zone" ].(string )
404+ node = & postgresql.DBNode {
405+ Role : & role ,
406+ Zone : & zone ,
407+ }
408+ )
409+ dbNodeSet = append (dbNodeSet , node )
410+ }
411+
412+ // check if availability_zone and node_set consists
413+ if include , z , nzs := checkZoneSetInclude (d ); ! include {
414+ return fmt .Errorf ("`availability_zone`: %s is not included in `db_node_set`: %s" , z , nzs )
415+ }
416+ }
417+
304418 outErr = resource .Retry (writeRetryTimeout , func () * resource.RetryError {
305419 instanceId , inErr = postgresqlService .CreatePostgresqlInstance (ctx ,
306420 name ,
@@ -316,7 +430,9 @@ func resourceTencentCloudPostgresqlInstanceCreate(d *schema.ResourceData, meta i
316430 storage ,
317431 username ,
318432 password ,
319- charset )
433+ charset ,
434+ dbNodeSet ,
435+ )
320436 if inErr != nil {
321437 return retryError (inErr )
322438 }
@@ -568,6 +684,40 @@ func resourceTencentCloudPostgresqlInstanceUpdate(d *schema.ResourceData, meta i
568684 d .SetPartial ("security_groups" )
569685 }
570686
687+ if d .HasChange ("db_node_set" ) {
688+
689+ if include , z , nzs := checkZoneSetInclude (d ); ! include {
690+ return fmt .Errorf ("`availability_zone`: %s is not included in `db_node_set`: %s" , z , nzs )
691+ }
692+
693+ nodeSet := d .Get ("db_node_set" ).(* schema.Set ).List ()
694+ request := postgresql .NewModifyDBInstanceDeploymentRequest ()
695+ request .DBInstanceId = helper .String (d .Id ())
696+ request .SwitchTag = helper .Int64 (0 )
697+ for i := range nodeSet {
698+ var (
699+ node = nodeSet [i ].(map [string ]interface {})
700+ role = node ["role" ].(string )
701+ zone = node ["zone" ].(string )
702+ )
703+ request .DBNodeSet = append (request .DBNodeSet , & postgresql.DBNode {
704+ Role : & role ,
705+ Zone : & zone ,
706+ })
707+ }
708+
709+ if err := postgresqlService .ModifyDBInstanceDeployment (ctx , request ); err != nil {
710+ return err
711+ }
712+
713+ d .SetPartial ("db_node_set" )
714+ }
715+
716+ if d .HasChange ("zone" ) {
717+ log .Printf ("[WARN] argument `zone` modified, skip process" )
718+ d .SetPartial ("zone" )
719+ }
720+
571721 if d .HasChange ("tags" ) {
572722
573723 oldValue , newValue := d .GetChange ("tags" )
@@ -622,22 +772,28 @@ func resourceTencentCloudPostgresqlInstanceRead(d *schema.ResourceData, meta int
622772 logId := getLogId (contextNil )
623773 ctx := context .WithValue (context .TODO (), logIdKey , logId )
624774
625- var outErr , inErr error
775+ var (
776+ instance * postgresql.DBInstance
777+ has bool
778+ outErr ,
779+ inErr error
780+ )
781+ // Check if import
626782 postgresqlService := PostgresqlService {client : meta .(* TencentCloudClient ).apiV3Conn }
627- instance , has , outErr := postgresqlService .DescribePostgresqlInstanceById (ctx , d .Id ())
628- if outErr != nil {
629- outErr = resource .Retry (readRetryTimeout , func () * resource.RetryError {
630- instance , has , inErr = postgresqlService .DescribePostgresqlInstanceById (ctx , d .Id ())
631- if inErr != nil {
632- ee , ok := inErr .(* sdkErrors.TencentCloudSDKError )
633- if ok && ee .GetCode () == "ResourceNotFound.InstanceNotFoundError" {
634- return nil
635- }
636- return retryError (inErr )
783+ outErr = resource .Retry (readRetryTimeout , func () * resource.RetryError {
784+ instance , has , inErr = postgresqlService .DescribePostgresqlInstanceById (ctx , d .Id ())
785+ if inErr != nil {
786+ ee , ok := inErr .(* sdkErrors.TencentCloudSDKError )
787+ if ok && ee .GetCode () == "ResourceNotFound.InstanceNotFoundError" {
788+ return nil
637789 }
638- return nil
639- })
640- }
790+ return retryError (inErr )
791+ }
792+ if IsContains (POSTGRES_RETRYABLE_STATUS , * instance .DBInstanceStatus ) {
793+ return resource .RetryableError (fmt .Errorf ("instance %s is %s, retrying" , * instance .DBInstanceId , * instance .DBInstanceStatus ))
794+ }
795+ return nil
796+ })
641797 if outErr != nil {
642798 return outErr
643799 }
@@ -708,6 +864,35 @@ func resourceTencentCloudPostgresqlInstanceRead(d *schema.ResourceData, meta int
708864 _ = d .Set ("security_groups" , sg )
709865 }
710866
867+ attrRequest := postgresql .NewDescribeDBInstanceAttributeRequest ()
868+ attrRequest .DBInstanceId = helper .String (d .Id ())
869+
870+ ins , err := postgresqlService .DescribeDBInstanceAttribute (ctx , attrRequest )
871+ if err != nil {
872+ return err
873+ }
874+ nodeSet := ins .DBNodeSet
875+ zoneSet := schema .NewSet (schema .HashString , nil )
876+ if nodeCount := len (nodeSet ); nodeCount > 0 {
877+ var dbNodeSet = make ([]interface {}, 0 , nodeCount )
878+ for i := range nodeSet {
879+ item := nodeSet [i ]
880+ node := map [string ]interface {}{
881+ "role" : item .Role ,
882+ "zone" : item .Zone ,
883+ }
884+ zoneSet .Add (* item .Zone )
885+ dbNodeSet = append (dbNodeSet , node )
886+ }
887+
888+ // skip default set (single AZ and zone includes)
889+ _ , nodeSetOk := d .GetOk ("db_node_set" )
890+ importedMaz := zoneSet .Len () > 1 && zoneSet .Contains (* instance .Zone )
891+
892+ if nodeSetOk || importedMaz {
893+ _ = d .Set ("db_node_set" , dbNodeSet )
894+ }
895+ }
711896 // computed
712897 _ = d .Set ("create_time" , instance .CreateTime )
713898 _ = d .Set ("status" , instance .DBInstanceStatus )
@@ -857,3 +1042,20 @@ func resourceTencentCLoudPostgresqlInstanceDelete(d *schema.ResourceData, meta i
8571042
8581043 return nil
8591044}
1045+
1046+ // check availability_zone included in db_node_set
1047+ func checkZoneSetInclude (d * schema.ResourceData ) (included bool , zone string , nodeZoneList []string ) {
1048+ zone = d .Get ("availability_zone" ).(string )
1049+ dbNodeSet := d .Get ("db_node_set" ).(* schema.Set ).List ()
1050+
1051+ for i := range dbNodeSet {
1052+ item := dbNodeSet [i ].(map [string ]interface {})
1053+ nodeZone := item ["zone" ].(string )
1054+ if nodeZone == zone {
1055+ included = true
1056+ }
1057+ nodeZoneList = append (nodeZoneList , nodeZone )
1058+ }
1059+
1060+ return
1061+ }
0 commit comments