@@ -179,6 +179,64 @@ func TencentMsyqlBasicInfo() map[string]*schema.Schema {
179179 Optional : true ,
180180 Description : "Switch the method of accessing new instances, default is `0`. Supported values include: `0` - switch immediately, `1` - switch in time window." ,
181181 },
182+ "cluster_topology" : {
183+ Type : schema .TypeList ,
184+ Optional : true ,
185+ MaxItems : 1 ,
186+ Description : "Cluster Edition node topology configuration. Note: If you purchased a cluster edition instance, this parameter is required. You need to set the RW and RO node topology of the cluster edition instance. The RO node range is 1-5. Please set at least 1 RO node." ,
187+ Elem : & schema.Resource {
188+ Schema : map [string ]* schema.Schema {
189+ "read_write_node" : {
190+ Type : schema .TypeList ,
191+ Optional : true ,
192+ MaxItems : 1 ,
193+ Description : "RW Node Topology." ,
194+ Elem : & schema.Resource {
195+ Schema : map [string ]* schema.Schema {
196+ "zone" : {
197+ Type : schema .TypeString ,
198+ Required : true ,
199+ Description : "The availability zone where the RW node is located." ,
200+ },
201+ "node_id" : {
202+ Type : schema .TypeString ,
203+ Optional : true ,
204+ Computed : true ,
205+ Description : "When upgrading a cluster instance, if you want to adjust the availability zone of a read-only node, you need to specify the node ID." ,
206+ },
207+ },
208+ },
209+ },
210+ "read_only_nodes" : {
211+ Type : schema .TypeSet ,
212+ Optional : true ,
213+ Description : "RO Node Topology." ,
214+ Elem : & schema.Resource {
215+ Schema : map [string ]* schema.Schema {
216+ "is_random_zone" : {
217+ Type : schema .TypeBool ,
218+ Optional : true ,
219+ Computed : true ,
220+ Description : "Whether to distribute in random availability zones. Enter `true` to specify a random availability zone. Otherwise, use the availability zone specified by Zone." ,
221+ },
222+ "zone" : {
223+ Type : schema .TypeString ,
224+ Optional : true ,
225+ Computed : true ,
226+ Description : "Specifies the availability zone where the node is distributed." ,
227+ },
228+ "node_id" : {
229+ Type : schema .TypeString ,
230+ Optional : true ,
231+ Computed : true ,
232+ Description : "When upgrading a cluster instance, if you want to adjust the availability zone of a read-only node, you need to specify the node ID." ,
233+ },
234+ },
235+ },
236+ },
237+ },
238+ },
239+ },
182240 // Computed values
183241 "intranet_ip" : {
184242 Type : schema .TypeString ,
@@ -560,6 +618,64 @@ func mysqlMasterInstanceRoleSet(ctx context.Context, requestInter interface{}, d
560618 } else {
561619 requestByUse .ProtectMode = & slaveSyncMode
562620 }
621+
622+ if v , ok := d .GetOk ("cluster_topology" ); ok {
623+ clusterTopologyList := v .([]interface {})
624+ if len (clusterTopologyList ) > 0 {
625+ clusterTopology := clusterTopologyList [0 ].(map [string ]interface {})
626+ tmpObj := cdb.ClusterTopology {}
627+ if readWriteNodeList , ok := clusterTopology ["read_write_node" ].([]interface {}); ok {
628+ if len (readWriteNodeList ) > 0 {
629+ item := readWriteNodeList [0 ].(map [string ]interface {})
630+ readWriteNode := cdb.ReadWriteNode {}
631+ if item ["zone" ] != nil && item ["zone" ].(string ) != "" {
632+ readWriteNode .Zone = helper .String (item ["zone" ].(string ))
633+ }
634+
635+ if item ["node_id" ] != nil && item ["node_id" ].(string ) != "" {
636+ readWriteNode .NodeId = helper .String (item ["node_id" ].(string ))
637+ }
638+
639+ tmpObj .ReadWriteNode = & readWriteNode
640+ }
641+ }
642+
643+ if readOnlyNodesSet , ok := clusterTopology ["read_only_nodes" ].(* schema.Set ); ok {
644+ readOnlyNodes := readOnlyNodesSet .List ()
645+ if len (readOnlyNodes ) > 0 {
646+ requestRoList := make ([]* cdb.ReadonlyNode , 0 , len (readOnlyNodes ))
647+ for _ , v := range readOnlyNodes {
648+ item := v .(map [string ]interface {})
649+ readonlyNode := cdb.ReadonlyNode {}
650+ if item ["is_random_zone" ] != nil {
651+ if item ["is_random_zone" ].(bool ) == true {
652+ readonlyNode .IsRandomZone = helper .String ("YES" )
653+ }
654+ }
655+
656+ if item ["zone" ] != nil && item ["zone" ].(string ) != "" {
657+ readonlyNode .Zone = helper .String (item ["zone" ].(string ))
658+ }
659+
660+ if item ["node_id" ] != nil && item ["node_id" ].(string ) != "" {
661+ readonlyNode .NodeId = helper .String (item ["node_id" ].(string ))
662+ }
663+
664+ requestRoList = append (requestRoList , & readonlyNode )
665+ }
666+
667+ tmpObj .ReadOnlyNodes = requestRoList
668+ }
669+ }
670+
671+ if okByMonth {
672+ requestByMonth .ClusterTopology = & tmpObj
673+ } else {
674+ requestByUse .ClusterTopology = & tmpObj
675+ }
676+ }
677+ }
678+
563679 return nil
564680}
565681
@@ -869,6 +985,60 @@ func tencentMsyqlBasicInfoRead(ctx context.Context, d *schema.ResourceData, meta
869985 }
870986 _ = d .Set ("status" , mysqlInfo .Status )
871987 _ = d .Set ("task_status" , mysqlInfo .TaskStatus )
988+
989+ if mysqlInfo .MasterInfo != nil || mysqlInfo .ClusterInfo != nil {
990+ ctTmpList := make ([]map [string ]interface {}, 0 , 1 )
991+ ctMap := make (map [string ]interface {})
992+ if mysqlInfo .ClusterInfo != nil {
993+ var masterZone string
994+ rwTmpList := make ([]map [string ]interface {}, 0 , 1 )
995+ for _ , item := range mysqlInfo .ClusterInfo {
996+ dMap := make (map [string ]interface {})
997+ if item .Role != nil && * item .Role == "master" {
998+ if item .Zone != nil {
999+ dMap ["zone" ] = * item .Zone
1000+ masterZone = * item .Zone
1001+ }
1002+
1003+ if item .NodeId != nil {
1004+ dMap ["node_id" ] = * item .NodeId
1005+ }
1006+
1007+ rwTmpList = append (rwTmpList , dMap )
1008+ break
1009+ }
1010+ }
1011+
1012+ ctMap ["read_write_node" ] = rwTmpList
1013+
1014+ roTmpList := make ([]map [string ]interface {}, 0 , len (mysqlInfo .ClusterInfo ))
1015+ for _ , item := range mysqlInfo .ClusterInfo {
1016+ dMap := make (map [string ]interface {})
1017+ if item .Role != nil && * item .Role == "slave" {
1018+ if item .Zone != nil {
1019+ dMap ["zone" ] = * item .Zone
1020+ if masterZone == * item .Zone {
1021+ dMap ["is_random_zone" ] = false
1022+ } else {
1023+ dMap ["is_random_zone" ] = true
1024+ }
1025+ }
1026+
1027+ if item .NodeId != nil {
1028+ dMap ["node_id" ] = * item .NodeId
1029+ }
1030+
1031+ roTmpList = append (roTmpList , dMap )
1032+ }
1033+ }
1034+
1035+ ctMap ["read_only_nodes" ] = roTmpList
1036+ }
1037+
1038+ ctTmpList = append (ctTmpList , ctMap )
1039+ _ = d .Set ("cluster_topology" , ctTmpList )
1040+ }
1041+
8721042 return
8731043}
8741044
@@ -1333,6 +1503,152 @@ func mysqlAllInstanceRoleUpdate(ctx context.Context, d *schema.ResourceData, met
13331503 }
13341504 }
13351505
1506+ if d .HasChange ("cluster_topology" ) {
1507+ var (
1508+ waitSwitch int64
1509+ asyncRequestId string
1510+ )
1511+
1512+ if v , ok := d .GetOkExists ("wait_switch" ); ok {
1513+ waitSwitch = int64 (v .(int ))
1514+ }
1515+
1516+ request := cdb .NewUpgradeDBInstanceRequest ()
1517+ response := cdb .NewUpgradeDBInstanceResponse ()
1518+ if v , ok := d .GetOk ("cluster_topology" ); ok {
1519+ clusterTopologyList := v .([]interface {})
1520+ if len (clusterTopologyList ) > 0 {
1521+ clusterTopology := clusterTopologyList [0 ].(map [string ]interface {})
1522+ tmpObj := cdb.ClusterTopology {}
1523+ if readWriteNodeList , ok := clusterTopology ["read_write_node" ].([]interface {}); ok {
1524+ if len (readWriteNodeList ) > 0 {
1525+ item := readWriteNodeList [0 ].(map [string ]interface {})
1526+ readWriteNode := cdb.ReadWriteNode {}
1527+ if item ["zone" ] != nil && item ["zone" ].(string ) != "" {
1528+ readWriteNode .Zone = helper .String (item ["zone" ].(string ))
1529+ }
1530+
1531+ if item ["node_id" ] != nil && item ["node_id" ].(string ) != "" {
1532+ readWriteNode .NodeId = helper .String (item ["node_id" ].(string ))
1533+ }
1534+
1535+ tmpObj .ReadWriteNode = & readWriteNode
1536+ }
1537+ }
1538+
1539+ if readOnlyNodesSet , ok := clusterTopology ["read_only_nodes" ].(* schema.Set ); ok {
1540+ readOnlyNodes := readOnlyNodesSet .List ()
1541+ if len (readOnlyNodes ) > 0 {
1542+ requestRoList := make ([]* cdb.ReadonlyNode , 0 , len (readOnlyNodes ))
1543+ for _ , v := range readOnlyNodes {
1544+ item := v .(map [string ]interface {})
1545+ readonlyNode := cdb.ReadonlyNode {}
1546+ if item ["is_random_zone" ] != nil {
1547+ if item ["is_random_zone" ].(bool ) == true {
1548+ readonlyNode .IsRandomZone = helper .String ("YES" )
1549+ }
1550+ }
1551+
1552+ if item ["zone" ] != nil && item ["zone" ].(string ) != "" {
1553+ readonlyNode .Zone = helper .String (item ["zone" ].(string ))
1554+ }
1555+
1556+ if item ["node_id" ] != nil && item ["node_id" ].(string ) != "" {
1557+ readonlyNode .NodeId = helper .String (item ["node_id" ].(string ))
1558+ }
1559+
1560+ requestRoList = append (requestRoList , & readonlyNode )
1561+ }
1562+
1563+ tmpObj .ReadOnlyNodes = requestRoList
1564+ }
1565+ }
1566+
1567+ request .ClusterTopology = & tmpObj
1568+ }
1569+ }
1570+
1571+ // required parameter
1572+ memSize := int64 (d .Get ("mem_size" ).(int ))
1573+ volumeSize := int64 (d .Get ("volume_size" ).(int ))
1574+ request .Memory = & memSize
1575+ request .Volume = & volumeSize
1576+
1577+ request .InstanceId = helper .String (d .Id ())
1578+ err := resource .Retry (tccommon .WriteRetryTimeout , func () * resource.RetryError {
1579+ result , e := meta .(tccommon.ProviderMeta ).GetAPIV3Conn ().UseMysqlClient ().UpgradeDBInstance (request )
1580+ if e != nil {
1581+ return tccommon .RetryError (e )
1582+ } else {
1583+ log .Printf ("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n " , logId , request .GetAction (), request .ToJsonString (), result .ToJsonString ())
1584+ }
1585+
1586+ if result == nil || result .Response == nil || result .Response .AsyncRequestId == nil {
1587+ return resource .NonRetryableError (fmt .Errorf ("update mysql cluster topology failed, response is nil." ))
1588+ }
1589+
1590+ response = result
1591+ return nil
1592+ })
1593+
1594+ if err != nil {
1595+ log .Printf ("[CRITAL]%s Update mysql cluster topology failed, reason:%s\n " , logId , err .Error ())
1596+ return err
1597+ }
1598+
1599+ asyncRequestId = * response .Response .AsyncRequestId
1600+ if waitSwitch != InWindow {
1601+ err = resource .Retry (6 * time .Hour , func () * resource.RetryError {
1602+ taskStatus , message , err := mysqlService .DescribeAsyncRequestInfo (ctx , asyncRequestId )
1603+ if err != nil {
1604+ if _ , ok := err .(* errors.TencentCloudSDKError ); ! ok {
1605+ return resource .RetryableError (err )
1606+ } else {
1607+ return resource .NonRetryableError (err )
1608+ }
1609+ }
1610+
1611+ if taskStatus == MYSQL_TASK_STATUS_SUCCESS {
1612+ return nil
1613+ }
1614+
1615+ if taskStatus == MYSQL_TASK_STATUS_INITIAL || taskStatus == MYSQL_TASK_STATUS_RUNNING {
1616+ return resource .RetryableError (fmt .Errorf ("update mysql cluster topology status is %s" , taskStatus ))
1617+ }
1618+
1619+ err = fmt .Errorf ("update mysql cluster topology task status is %s, we won't wait for it finish, it show message:%s" , taskStatus , message )
1620+ return resource .NonRetryableError (err )
1621+ })
1622+
1623+ if err != nil {
1624+ log .Printf ("[CRITAL]%s update mysql cluster topology fail, reason:%s\n " , logId , err .Error ())
1625+ return err
1626+ }
1627+ } else {
1628+ err = resource .Retry (tccommon .ReadRetryTimeout * 5 , func () * resource.RetryError {
1629+ mysqlInfo , err := mysqlService .DescribeDBInstanceById (ctx , d .Id ())
1630+ if err != nil {
1631+ if _ , ok := err .(* errors.TencentCloudSDKError ); ! ok {
1632+ return resource .RetryableError (err )
1633+ } else {
1634+ return resource .NonRetryableError (err )
1635+ }
1636+ }
1637+
1638+ if * mysqlInfo .TaskStatus == 15 {
1639+ return nil
1640+ }
1641+
1642+ return resource .RetryableError (fmt .Errorf ("update mysql cluster topology task status is %v" , mysqlInfo .TaskStatus ))
1643+ })
1644+
1645+ if err != nil {
1646+ log .Printf ("[CRITAL]%s update mysql cluster topology fail, reason:%s\n " , logId , err .Error ())
1647+ return err
1648+ }
1649+ }
1650+ }
1651+
13361652 if d .HasChange ("tags" ) {
13371653
13381654 oldValue , newValue := d .GetChange ("tags" )
0 commit comments