Skip to content

Commit 386735c

Browse files
authored
fix(cdb): [127606228] tencentcloud_mysql_instance support cluster_topology (#3532)
* add * add
1 parent 166dae4 commit 386735c

File tree

12 files changed

+4042
-1325
lines changed

12 files changed

+4042
-1325
lines changed

.changelog/3532.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_mysql_instance: support `cluster_topology` fields
3+
```

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ require (
3535
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.1071
3636
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cat v1.0.825
3737
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cbs v1.1.0
38-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.0.944
38+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.1.27
3939
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1010
4040
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdwch v1.1.7
4141
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cfs v1.0.627

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cbs v1.1.0 h1:XhA8+gNAk
841841
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cbs v1.1.0/go.mod h1:fxQECHc6BhgubNmnBFMohy2GNdbPvL5nrToQS3zdC8s=
842842
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.0.944 h1:+PGoNHlZE/WY6KWWNOByL0sYVv1ZJtSx7yXMUJNYV1Y=
843843
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.0.944/go.mod h1:+VHcZ4Cnzpt6vtCvNROz8xWfNWUkoAZ9UPSonbA3NWM=
844+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.1.27 h1:WcOPanoXwPwLf0DW7HcPL0vWBBRvZzh44sOF14rksr0=
845+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdb v1.1.27/go.mod h1:lljFAiBuUusv/K6wzLs1HMVLGJ8lBncCIfOPQKBpo6I=
844846
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdc v1.0.1149 h1:lW1auC8TdFa4NkE6ORzslUrP3lcGigdd0X8/4T+pY40=
845847
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdc v1.0.1149/go.mod h1:LDcZtoh9sKi/2/Tze53H64C4G3CzzHN22AWsflf3Cn4=
846848
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1010 h1:sO0vW6E09xFQ5+I8mfvAyIlRZvWBWPf6ilZU5LI4lmE=

tencentcloud/services/cdb/resource_tc_mysql_instance.go

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)