Skip to content

Commit 72d67e3

Browse files
gitmknanonymous
andauthored
fix: modify cluster (#1909)
* fix: support modify name and modify storage and switch vpc * fix: fmt * fix: modify cluster * feat: support modify cluster_name, storage_limit, vpc_id, subnet_id, old_ip_reserve_hours * feat: add changelog * fix: modify test --------- Co-authored-by: anonymous <anonymous@mail.org>
1 parent 2fa5f9b commit 72d67e3

File tree

6 files changed

+179
-18
lines changed

6 files changed

+179
-18
lines changed

.changelog/1909.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_cynosdb_cluster: Support `cluster_name, storage_limit, vpc_id, subnet_id, old_ip_reserve_hours` modification
3+
```

tencentcloud/extension_cynosdb.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,18 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema {
115115
"vpc_id": {
116116
Type: schema.TypeString,
117117
Required: true,
118-
ForceNew: true,
119118
Description: "ID of the VPC.",
120119
},
121120
"subnet_id": {
122121
Type: schema.TypeString,
123122
Required: true,
124-
ForceNew: true,
125123
Description: "ID of the subnet within this VPC.",
126124
},
125+
"old_ip_reserve_hours": {
126+
Type: schema.TypeInt,
127+
Optional: true,
128+
Description: "Recycling time of the old address, must be filled in when modifying the vpcRecycling time of the old address, must be filled in when modifying the vpc.",
129+
},
127130
"port": {
128131
Type: schema.TypeInt,
129132
Optional: true,
@@ -146,13 +149,17 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema {
146149
"storage_limit": {
147150
Type: schema.TypeInt,
148151
Optional: true,
149-
ForceNew: true,
150-
Description: "Storage limit of CynosDB cluster instance, unit in GB. The maximum storage of a non-serverless instance in GB. NOTE: If db_type is `MYSQL` and charge_type is `PREPAID`, the value cannot exceed the maximum storage corresponding to the CPU and memory specifications, when charge_type is `POSTPAID_BY_HOUR`, this argument is unnecessary.",
152+
Description: "Storage limit of CynosDB cluster instance, unit in GB. The maximum storage of a non-serverless instance in GB. NOTE: If db_type is `MYSQL` and charge_type is `PREPAID`, the value cannot exceed the maximum storage corresponding to the CPU and memory specifications, and the transaction mode is `order and pay`. when charge_type is `POSTPAID_BY_HOUR`, this argument is unnecessary.",
153+
},
154+
"storage_pay_mode": {
155+
Type: schema.TypeInt,
156+
Optional: true,
157+
Computed: true,
158+
Description: "Cluster storage billing mode, pay-as-you-go: `0`-yearly/monthly: `1`-The default is pay-as-you-go. When the DbType is MYSQL, when the cluster computing billing mode is post-paid (including DbMode is SERVERLESS), the storage billing mode can only be billing by volume; rollback and cloning do not support yearly subscriptions monthly storage.",
151159
},
152160
"cluster_name": {
153161
Type: schema.TypeString,
154162
Required: true,
155-
ForceNew: true,
156163
Description: "Name of CynosDB cluster.",
157164
},
158165
"password": {

tencentcloud/resource_tc_cynosdb_cluster.go

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,9 @@ import (
6666
"log"
6767
"time"
6868

69-
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
70-
7169
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
7270
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
73-
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
71+
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
7472
cynosdb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cynosdb/v20190107"
7573
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
7674
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/ratelimit"
@@ -136,6 +134,10 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter
136134
request.StorageLimit = helper.IntInt64(v.(int))
137135
}
138136

137+
if v, ok := d.GetOk("storage_pay_mode"); ok {
138+
request.StoragePayMode = helper.IntInt64(v.(int))
139+
}
140+
139141
// set params
140142
if v, ok := d.GetOk("param_items"); ok {
141143
paramItems := v.([]interface{})
@@ -195,7 +197,7 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter
195197
ratelimit.Check(request.GetAction())
196198
response, err = meta.(*TencentCloudClient).apiV3Conn.UseCynosdbClient().CreateClusters(request)
197199
if err != nil {
198-
if e, ok := err.(*errors.TencentCloudSDKError); ok {
200+
if e, ok := err.(*sdkErrors.TencentCloudSDKError); ok {
199201
if e.GetCode() == "InvalidParameterValue.DealNameNotFound" {
200202
return resource.RetryableError(fmt.Errorf("waiting billing status, retry..."))
201203
}
@@ -208,7 +210,7 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter
208210
if err != nil {
209211
return err
210212
}
211-
if response != nil && response.Response != nil && len(response.Response.DealNames) != 1 {
213+
if response != nil && response.Response != nil && len(response.Response.DealNames) < 1 {
212214
return fmt.Errorf("cynosdb cluster id count isn't 1")
213215
}
214216
//after 1.53.3 the response is async
@@ -378,6 +380,7 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa
378380
_ = d.Set("storage_used", *cluster.UsedStorage/1000/1000)
379381
_ = d.Set("auto_renew_flag", *item.RenewFlag)
380382
_ = d.Set("serverless_status", cluster.ServerlessStatus)
383+
_ = d.Set("storage_pay_mode", cluster.StoragePayMode)
381384

382385
if _, ok := d.GetOk("serverless_status_flag"); ok && *item.DbMode == CYNOSDB_SERVERLESS {
383386
status := *item.ServerlessStatus
@@ -548,6 +551,7 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter
548551
"max_cpu",
549552
"auto_pause",
550553
"auto_pause_delay",
554+
"storage_pay_mode",
551555
}
552556

553557
for _, a := range immutableArgs {
@@ -605,6 +609,14 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter
605609

606610
// update param
607611
if d.HasChange("param_items") {
612+
_, _, has, e := cynosdbService.DescribeClusterById(ctx, clusterId)
613+
if e != nil {
614+
return e
615+
}
616+
if !has {
617+
return fmt.Errorf("[CRITAL]%s updating cynosdb cluster instance failed, instance doesn't exist", logId)
618+
}
619+
608620
o, n := d.GetChange("param_items")
609621
oldParams := o.([]interface{})
610622
newParams := n.([]interface{})
@@ -731,6 +743,35 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter
731743
}
732744
}
733745

746+
// update cluster_name
747+
if d.HasChange("cluster_name") {
748+
clusterName := d.Get("cluster_name").(string)
749+
err := cynosdbService.ModifyClusterName(ctx, clusterId, clusterName)
750+
if err != nil {
751+
return err
752+
}
753+
}
754+
755+
// update storage_limit
756+
if d.HasChange("storage_limit") {
757+
oldStorageLimit, newStorageLimit := d.GetChange("storage_limit")
758+
err := cynosdbService.ModifyClusterStorage(ctx, clusterId, int64(newStorageLimit.(int)), int64(oldStorageLimit.(int)))
759+
if err != nil {
760+
return err
761+
}
762+
}
763+
764+
// update vpc
765+
if d.HasChange("vpc_id") || d.HasChange("subnet_id") || d.HasChange("old_ip_reserve_hours") {
766+
vpcId := d.Get("vpc_id").(string)
767+
subnetId := d.Get("subnet_id").(string)
768+
oldIpReserveHours := int64(d.Get("old_ip_reserve_hours").(int))
769+
err := cynosdbService.SwitchClusterVpc(ctx, clusterId, vpcId, subnetId, oldIpReserveHours)
770+
if err != nil {
771+
return err
772+
}
773+
}
774+
734775
d.Partial(false)
735776

736777
return resourceTencentCloudCynosdbClusterRead(d, meta)
@@ -771,6 +812,11 @@ func resourceTencentCloudCynosdbClusterDelete(d *schema.ResourceData, meta inter
771812
conf := BuildStateChangeConf([]string{}, []string{"offlined"}, 2*readRetryTimeout, time.Second, cynosdbService.CynosdbInstanceOfflineStateRefreshFunc(d.Id(), []string{}))
772813

773814
if _, e := conf.WaitForState(); e != nil {
815+
if ee, ok := e.(*sdkErrors.TencentCloudSDKError); ok {
816+
if ee.Message == "record not found" {
817+
return nil
818+
}
819+
}
774820
return e
775821
}
776822
}

tencentcloud/resource_tc_cynosdb_cluster_test.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1010
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11+
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
1112
)
1213

1314
func init() {
@@ -49,6 +50,7 @@ func init() {
4950
})
5051
}
5152

53+
// go test -i; go test -test.run TestAccTencentCloudCynosdbClusterResourceBasic -v
5254
func TestAccTencentCloudCynosdbClusterResourceBasic(t *testing.T) {
5355
t.Parallel()
5456
resource.Test(t, resource.TestCase{
@@ -65,7 +67,7 @@ func TestAccTencentCloudCynosdbClusterResourceBasic(t *testing.T) {
6567
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "subnet_id", "subnet-qpxez62e"),
6668
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "db_type", "MYSQL"),
6769
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "db_version", "5.7"),
68-
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "storage_limit", "1000"),
70+
// resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "storage_limit", "1000"),
6971
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "cluster_name", "tf-cynosdb"),
7072
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "instance_maintain_duration", "3600"),
7173
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "instance_maintain_start_time", "10800"),
@@ -109,6 +111,8 @@ func TestAccTencentCloudCynosdbClusterResourceBasic(t *testing.T) {
109111
{
110112
Config: testAccCynosdbCluster_update,
111113
Check: resource.ComposeTestCheckFunc(
114+
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "vpc_id", "vpc-k1t8ickr"),
115+
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "subnet_id", "subnet-jdi5xn22"),
112116
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "instance_maintain_duration", "7200"),
113117
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "instance_maintain_start_time", "21600"),
114118
resource.TestCheckResourceAttr("tencentcloud_cynosdb_cluster.foo", "instance_maintain_weekdays.#", "6"),
@@ -192,6 +196,11 @@ func testAccCheckCynosdbClusterDestroy(s *terraform.State) error {
192196

193197
_, _, has, err := cynosdbService.DescribeClusterById(ctx, rs.Primary.ID)
194198
if err != nil {
199+
if ee, ok := err.(*sdkErrors.TencentCloudSDKError); ok {
200+
if ee.Message == "record not found" {
201+
return nil
202+
}
203+
}
195204
return err
196205
}
197206
if !has {
@@ -298,12 +307,13 @@ resource "tencentcloud_cynosdb_cluster" "foo" {
298307
const testAccCynosdbCluster_update = testAccCynosdbBasic + `
299308
resource "tencentcloud_cynosdb_cluster" "foo" {
300309
available_zone = var.availability_zone
301-
vpc_id = var.my_vpc
302-
subnet_id = var.my_subnet
310+
vpc_id = "vpc-k1t8ickr"
311+
subnet_id = "subnet-jdi5xn22"
312+
old_ip_reserve_hours = 1
303313
db_type = "MYSQL"
304314
db_version = "5.7"
305315
storage_limit = 1000
306-
cluster_name = "tf-cynosdb"
316+
cluster_name = "tf-cynosdb-update"
307317
password = "cynos@123"
308318
instance_maintain_duration = 7200
309319
instance_maintain_start_time = 21600

tencentcloud/service_tencentcloud_cynosdb.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,99 @@ func (me *CynosdbService) SetRenewFlag(ctx context.Context, instanceId string, a
25012501
return
25022502
}
25032503

2504+
func (me *CynosdbService) ModifyClusterName(ctx context.Context, clusterId string, clusterName string) (errRet error) {
2505+
logId := getLogId(ctx)
2506+
request := cynosdb.NewModifyClusterNameRequest()
2507+
request.ClusterId = &clusterId
2508+
request.ClusterName = &clusterName
2509+
2510+
errRet = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
2511+
ratelimit.Check(request.GetAction())
2512+
_, errRet = me.client.UseCynosdbClient().ModifyClusterName(request)
2513+
if errRet != nil {
2514+
log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), errRet.Error())
2515+
return retryError(errRet)
2516+
}
2517+
return nil
2518+
})
2519+
if errRet != nil {
2520+
return
2521+
}
2522+
2523+
return
2524+
}
2525+
2526+
func (me *CynosdbService) ModifyClusterStorage(ctx context.Context, clusterId string, newStorageLimit int64, oldStorageLimit int64) (errRet error) {
2527+
logId := getLogId(ctx)
2528+
request := cynosdb.NewModifyClusterStorageRequest()
2529+
request.ClusterId = &clusterId
2530+
request.NewStorageLimit = &newStorageLimit
2531+
request.OldStorageLimit = &oldStorageLimit
2532+
request.DealMode = helper.IntInt64(0)
2533+
2534+
errRet = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
2535+
ratelimit.Check(request.GetAction())
2536+
_, errRet = me.client.UseCynosdbClient().ModifyClusterStorage(request)
2537+
if errRet != nil {
2538+
log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), errRet.Error())
2539+
return retryError(errRet)
2540+
}
2541+
return nil
2542+
})
2543+
if errRet != nil {
2544+
return
2545+
}
2546+
2547+
return
2548+
}
2549+
2550+
func (me *CynosdbService) SwitchClusterVpc(ctx context.Context, clusterId string, vpcId string, subnetId string, oldIpReserveHours int64) (errRet error) {
2551+
logId := getLogId(ctx)
2552+
request := cynosdb.NewSwitchClusterVpcRequest()
2553+
request.ClusterId = &clusterId
2554+
request.UniqVpcId = &vpcId
2555+
request.UniqSubnetId = &subnetId
2556+
request.OldIpReserveHours = &oldIpReserveHours
2557+
2558+
var flowId int64
2559+
errRet = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
2560+
ratelimit.Check(request.GetAction())
2561+
response, errRet := me.client.UseCynosdbClient().SwitchClusterVpc(request)
2562+
if errRet != nil {
2563+
log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), errRet.Error())
2564+
return retryError(errRet)
2565+
}
2566+
flowId = *response.Response.FlowId
2567+
return nil
2568+
})
2569+
if errRet != nil {
2570+
return
2571+
}
2572+
2573+
err := resource.Retry(6*readRetryTimeout, func() *resource.RetryError {
2574+
ok, err := me.DescribeFlow(ctx, flowId)
2575+
if err != nil {
2576+
if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok {
2577+
return resource.RetryableError(err)
2578+
} else {
2579+
return resource.NonRetryableError(err)
2580+
}
2581+
}
2582+
if ok {
2583+
return nil
2584+
} else {
2585+
return resource.RetryableError(fmt.Errorf("update cynosdb SwitchClusterVpc is processing"))
2586+
}
2587+
})
2588+
if err != nil {
2589+
log.Printf("[CRITAL]%s update cynosdb SwitchClusterVpc fail, reason:%s\n", logId, err.Error())
2590+
errRet = err
2591+
return
2592+
}
2593+
2594+
return
2595+
}
2596+
25042597
func (me *CynosdbService) DescribeCynosdbResourcePackageById(ctx context.Context, packageId string) (resourcePackage *cynosdb.PackageDetail, errRet error) {
25052598
logId := getLogId(ctx)
25062599

website/docs/r/cynosdb_cluster.html.markdown

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ resource "tencentcloud_cynosdb_cluster" "foo" {
6565
The following arguments are supported:
6666

6767
* `available_zone` - (Required, String, ForceNew) The available zone of the CynosDB Cluster.
68-
* `cluster_name` - (Required, String, ForceNew) Name of CynosDB cluster.
68+
* `cluster_name` - (Required, String) Name of CynosDB cluster.
6969
* `db_type` - (Required, String, ForceNew) Type of CynosDB, and available values include `MYSQL`.
7070
* `db_version` - (Required, String, ForceNew) Version of CynosDB, which is related to `db_type`. For `MYSQL`, available value is `5.7`.
7171
* `password` - (Required, String, ForceNew) Password of `root` account.
72-
* `subnet_id` - (Required, String, ForceNew) ID of the subnet within this VPC.
73-
* `vpc_id` - (Required, String, ForceNew) ID of the VPC.
72+
* `subnet_id` - (Required, String) ID of the subnet within this VPC.
73+
* `vpc_id` - (Required, String) ID of the VPC.
7474
* `auto_pause_delay` - (Optional, Int) Specify auto-pause delay in second while `db_mode` is `SERVERLESS`. Value range: `[600, 691200]`. Default: `600`.
7575
* `auto_pause` - (Optional, String) Specify whether the cluster can auto-pause while `db_mode` is `SERVERLESS`. Values: `yes` (default), `no`.
7676
* `auto_renew_flag` - (Optional, Int) Auto renew flag. Valid values are `0`(MANUAL_RENEW), `1`(AUTO_RENEW). Default value is `0`. Only works for PREPAID cluster.
@@ -84,6 +84,7 @@ The following arguments are supported:
8484
* `instance_memory_size` - (Optional, Int) Memory capacity of read-write type instance, unit in GB. Required while creating normal cluster. Note: modification of this field will take effect immediately, if want to upgrade on maintenance window, please upgrade from console.
8585
* `max_cpu` - (Optional, Float64) Maximum CPU core count, required while `db_mode` is `SERVERLESS`, request DescribeServerlessInstanceSpecs for more reference.
8686
* `min_cpu` - (Optional, Float64) Minimum CPU core count, required while `db_mode` is `SERVERLESS`, request DescribeServerlessInstanceSpecs for more reference.
87+
* `old_ip_reserve_hours` - (Optional, Int) Recycling time of the old address, must be filled in when modifying the vpcRecycling time of the old address, must be filled in when modifying the vpc.
8788
* `param_items` - (Optional, List) Specify parameter list of database. It is valid when prarm_template_id is set in create cluster. Use `data.tencentcloud_mysql_default_params` to query available parameter details.
8889
* `port` - (Optional, Int, ForceNew) Port of CynosDB cluster.
8990
* `prarm_template_id` - (Optional, Int) The ID of the parameter template.
@@ -92,7 +93,8 @@ The following arguments are supported:
9293
* `ro_group_sg` - (Optional, List: [`String`]) IDs of security group for `ro_group`.
9394
* `rw_group_sg` - (Optional, List: [`String`]) IDs of security group for `rw_group`.
9495
* `serverless_status_flag` - (Optional, String) Specify whether to pause or resume serverless cluster. values: `resume`, `pause`.
95-
* `storage_limit` - (Optional, Int, ForceNew) Storage limit of CynosDB cluster instance, unit in GB. The maximum storage of a non-serverless instance in GB. NOTE: If db_type is `MYSQL` and charge_type is `PREPAID`, the value cannot exceed the maximum storage corresponding to the CPU and memory specifications, when charge_type is `POSTPAID_BY_HOUR`, this argument is unnecessary.
96+
* `storage_limit` - (Optional, Int) Storage limit of CynosDB cluster instance, unit in GB. The maximum storage of a non-serverless instance in GB. NOTE: If db_type is `MYSQL` and charge_type is `PREPAID`, the value cannot exceed the maximum storage corresponding to the CPU and memory specifications, and the transaction mode is `order and pay`. when charge_type is `POSTPAID_BY_HOUR`, this argument is unnecessary.
97+
* `storage_pay_mode` - (Optional, Int) Cluster storage billing mode, pay-as-you-go: `0`-yearly/monthly: `1`-The default is pay-as-you-go. When the DbType is MYSQL, when the cluster computing billing mode is post-paid (including DbMode is SERVERLESS), the storage billing mode can only be billing by volume; rollback and cloning do not support yearly subscriptions monthly storage.
9698
* `tags` - (Optional, Map) The tags of the CynosDB cluster.
9799

98100
The `param_items` object supports the following:

0 commit comments

Comments
 (0)