diff --git a/.changelog/2711.txt b/.changelog/2711.txt new file mode 100644 index 0000000000..ba2c087f7b --- /dev/null +++ b/.changelog/2711.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/tencentcloud_cynosdb_cluster: add `slave_zone` param +``` diff --git a/tencentcloud/services/cynosdb/extension_cynosdb.go b/tencentcloud/services/cynosdb/extension_cynosdb.go index 5a78ea101f..f75c3f5786 100644 --- a/tencentcloud/services/cynosdb/extension_cynosdb.go +++ b/tencentcloud/services/cynosdb/extension_cynosdb.go @@ -160,7 +160,7 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema { Type: schema.TypeString, Required: true, ForceNew: true, - Description: "Version of CynosDB, which is related to `db_type`. For `MYSQL`, available value is `5.7`.", + Description: "Version of CynosDB, which is related to `db_type`. For `MYSQL`, available value is `5.7`, `8.0`.", }, "storage_limit": { Type: schema.TypeInt, @@ -342,7 +342,7 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema { "param_items": { Type: schema.TypeList, Optional: true, - Description: "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.", + Description: "Specify parameter list of database. It is valid when `param_template_id` is set in create cluster. Use `data.tencentcloud_mysql_default_params` to query available parameter details.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -364,10 +364,19 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema { }, }, "prarm_template_id": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - Description: "The ID of the parameter template.", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"param_template_id"}, + Deprecated: "It will be deprecated. Use `param_template_id` instead.", + Description: "The ID of the parameter template.", + }, + "param_template_id": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"prarm_template_id"}, + Description: "The ID of the parameter template.", }, "db_mode": { Type: schema.TypeString, @@ -394,6 +403,11 @@ func TencentCynosdbClusterBaseInfo() map[string]*schema.Schema { Optional: true, Description: "Specify auto-pause delay in second while `db_mode` is `SERVERLESS`. Value range: `[600, 691200]`. Default: `600`.", }, + "slave_zone": { + Type: schema.TypeString, + Optional: true, + Description: "Multi zone Addresses of the CynosDB Cluster.", + }, "serverless_status_flag": { Type: schema.TypeString, Optional: true, diff --git a/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.go b/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.go index 1399a79f88..1a83e7b365 100644 --- a/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.go +++ b/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.go @@ -40,9 +40,8 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter defer tccommon.LogElapsed("resource.tencentcloud_cynosdb_cluster.create")() var ( - logId = tccommon.GetLogId(tccommon.ContextNil) - ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() cynosdbService = CynosdbService{client: client} tagService = svctag.NewTagService(client) @@ -67,15 +66,19 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter if v, ok := d.GetOk("db_mode"); ok { request.DbMode = helper.String(v.(string)) } + if v, ok := d.GetOk("min_cpu"); ok { request.MinCpu = helper.Float64(v.(float64)) } + if v, ok := d.GetOk("max_cpu"); ok { request.MaxCpu = helper.Float64(v.(float64)) } + if v, ok := d.GetOk("auto_pause"); ok { request.AutoPause = helper.String(v.(string)) } + if v, ok := d.GetOk("auto_pause_delay"); ok { request.AutoPauseDelay = helper.IntInt64(v.(int)) } @@ -88,6 +91,10 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter request.StoragePayMode = helper.IntInt64(v.(int)) } + if v, ok := d.GetOk("slave_zone"); ok { + request.SlaveZone = helper.String(v.(string)) + } + // set params if v, ok := d.GetOk("param_items"); ok { paramItems := v.([]interface{}) @@ -105,15 +112,22 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter request.ClusterParams = append(request.ClusterParams, param) } } + if v, ok := d.GetOk("prarm_template_id"); ok { request.ParamTemplateId = helper.IntInt64(v.(int)) } + + if v, ok := d.GetOk("param_template_id"); ok { + request.ParamTemplateId = helper.IntInt64(v.(int)) + } + isServerless := d.Get("db_mode").(string) == CYNOSDB_SERVERLESS if v, ok := d.GetOk("instance_cpu_core"); ok { request.Cpu = helper.IntInt64(v.(int)) } else if !isServerless { return fmt.Errorf("`instance_cpu_core` is required while creating non-serverless cluster") } + if v, ok := d.GetOk("instance_memory_size"); ok { request.Memory = helper.IntInt64(v.(int)) } else if !isServerless { @@ -138,11 +152,12 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter } else { return fmt.Errorf("prepaid period can not be empty when charge type is %s", CYNOSDB_CHARGE_TYPE_PREPAID) } + request.AutoRenewFlag = helper.IntInt64(d.Get("auto_renew_flag").(int)) } } - request.PayMode = &chargeType + request.PayMode = &chargeType request.InstanceCount = helper.Int64(1) var response *cynosdb.CreateClustersResponse @@ -156,19 +171,24 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter return resource.RetryableError(fmt.Errorf("waiting billing status, retry...")) } } + log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) //internal version: replace bpass begin, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. //internal version: replace bpass end, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. return tccommon.RetryError(err) } + return nil }) + if err != nil { return err } + if response != nil && response.Response != nil && len(response.Response.DealNames) < 1 { return fmt.Errorf("cynosdb cluster id count isn't 1") } + //after 1.53.3 the response is async dealName := response.Response.DealNames[0] dealReq := cynosdb.NewDescribeResourcesByDealNameRequest() @@ -184,10 +204,13 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter return resource.RetryableError(fmt.Errorf("DealName[%s] Not Found, retry... reason: %s", *dealName, err.Error())) } } + return tccommon.RetryError(err) } + return nil }) + if err != nil { return err } @@ -206,6 +229,7 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter if err != nil { return err } + if !has { return fmt.Errorf("[CRITAL]%s creating cynosdb cluster failed, cluster doesn't exist", logId) } @@ -223,20 +247,24 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter if err != nil { return err } + var rwInstanceId string for _, v := range cluster.InstanceSet { _, instance, has, err := cynosdbService.DescribeInstanceById(ctx, *v.InstanceId) if err != nil { return err } + if !has { continue } + if *instance.InstanceType == CYNOSDB_INSTANCE_RW_TYPE { rwInstanceId = *instance.InstanceId break } } + // set maintenance info var weekdays []interface{} if v, ok := d.GetOk("instance_maintain_weekdays"); ok { @@ -244,10 +272,12 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter } else { weekdays = []interface{}{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"} } + reqWeekdays := make([]*string, 0, len(weekdays)) for _, v := range weekdays { reqWeekdays = append(reqWeekdays, helper.String(v.(string))) } + startTime := int64(d.Get("instance_maintain_start_time").(int)) duration := int64(d.Get("instance_maintain_duration").(int)) err = cynosdbService.ModifyMaintainPeriodConfig(ctx, rwInstanceId, startTime, duration, reqWeekdays) @@ -269,16 +299,19 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter roGroupIds = append(roGroupIds, *insGrp.InstanceGrpId) } } + if v, ok := d.GetOk("rw_group_sg"); ok { vv := v.([]interface{}) vvv := make([]*string, 0, len(vv)) for _, item := range vv { vvv = append(vvv, helper.String(item.(string))) } + if err = cynosdbService.ModifyInsGrpSecurityGroups(ctx, rwGroupId, d.Get("available_zone").(string), vvv); err != nil { return err } } + if v, ok := d.GetOk("ro_group_sg"); ok && len(roGroupIds) > 0 { for _, roGroupId := range roGroupIds { vv := v.([]interface{}) @@ -286,6 +319,7 @@ func resourceTencentCloudCynosdbClusterCreate(d *schema.ResourceData, meta inter for _, item := range vv { vvv = append(vvv, helper.String(item.(string))) } + if err = cynosdbService.ModifyInsGrpSecurityGroups(ctx, roGroupId, d.Get("available_zone").(string), vvv); err != nil { return err } @@ -308,17 +342,19 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa defer tccommon.LogElapsed("resource.tencentcloud_cynosdb_cluster.read")() defer tccommon.InconsistentCheck(d, meta)() - logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - - id := d.Id() + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() + cynosdbService = CynosdbService{client: client} + id = d.Id() + ) - client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() - cynosdbService := CynosdbService{client: client} item, cluster, has, err := cynosdbService.DescribeClusterById(ctx, id) if err != nil { return err } + if !has { d.SetId("") return nil @@ -341,6 +377,10 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa _ = d.Set("serverless_status", cluster.ServerlessStatus) _ = d.Set("storage_pay_mode", cluster.StoragePayMode) + if cluster.SlaveZones != nil && len(cluster.SlaveZones) > 0 { + _ = d.Set("slave_zone", cluster.SlaveZones[0]) + } + if _, ok := d.GetOk("serverless_status_flag"); ok && *item.DbMode == CYNOSDB_SERVERLESS { status := *item.ServerlessStatus _ = d.Set("serverless_status_flag", status) @@ -363,18 +403,22 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa if err != nil { return err } + if !has { continue } + if *instance.InstanceType == CYNOSDB_INSTANCE_RW_TYPE { maintain, err := cynosdbService.DescribeMaintainPeriod(ctx, *v.InstanceId) if err != nil { return err } + if *item.DbMode != CYNOSDB_SERVERLESS { _ = d.Set("instance_cpu_core", instance.Cpu) _ = d.Set("instance_memory_size", instance.Memory) } + _ = d.Set("instance_id", instance.InstanceId) _ = d.Set("instance_name", instance.InstanceName) _ = d.Set("instance_status", instance.Status) @@ -391,6 +435,7 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa if err != nil { return err } + var rwGroupId string rwGroupIns := make([]map[string]interface{}, 0) rwGroupAddr := make([]map[string]interface{}, 0) @@ -407,6 +452,7 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa "instance_name": *rwIns.InstanceName, }) } + rwGroupAddr = append(rwGroupAddr, map[string]interface{}{ "ip": *insGrp.Vip, "port": *insGrp.Vport, @@ -420,12 +466,14 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa "instance_name": *roIns.InstanceName, }) } + roGroupAddr = append(roGroupAddr, map[string]interface{}{ "ip": *insGrp.Vip, "port": *insGrp.Vport, }) } } + _ = d.Set("rw_group_instances", rwGroupIns) _ = d.Set("rw_group_addr", rwGroupAddr) _ = d.Set("ro_group_instances", roGroupIns) @@ -437,6 +485,7 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa if err != nil { return err } + if sgs != nil { sgIds := make([]*string, 0, len(sgs.Response.Groups)) for _, item := range sgs.Response.Groups { @@ -445,11 +494,13 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa _ = d.Set("rw_group_sg", sgIds) } } + if roGroupId != "" { sgs, err := cynosdbService.DescribeInsGrpSecurityGroups(ctx, roGroupId) if err != nil { return err } + if sgs != nil { sgIds := make([]*string, 0, len(sgs.Response.Groups)) for _, item := range sgs.Response.Groups { @@ -466,9 +517,11 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa if err != nil { return err } + for _, param := range params { currentParamMap[*param.ParamName] = param } + resultParamItems := make([]map[string]string, 0) if v, ok := d.GetOk("param_items"); ok { paramItems := v.([]interface{}) @@ -481,12 +534,15 @@ func resourceTencentCloudCynosdbClusterRead(d *schema.ResourceData, meta interfa if currentParamMap[name] != nil && currentParamMap[name].CurrentValue != nil { currentParamItem["current_value"] = *currentParamMap[name].CurrentValue } + if oldValue != "" { currentParamItem["old_value"] = oldValue } + resultParamItems = append(resultParamItems, currentParamItem) } } + _ = d.Set("param_items", resultParamItems) } @@ -499,13 +555,14 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter var ( logId = tccommon.GetLogId(tccommon.ContextNil) ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - clusterId = d.Id() - instanceId = d.Get("instance_id").(string) client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() cynosdbService = CynosdbService{client: client} tagService = svctag.NewTagService(client) region = client.Region + clusterId = d.Id() + instanceId = d.Get("instance_id").(string) ) + immutableArgs := []string{ "db_mode", "min_cpu", @@ -513,6 +570,8 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter "auto_pause", "auto_pause_delay", "storage_pay_mode", + "prarm_template_id", + "param_template_id", } for _, a := range immutableArgs { @@ -536,6 +595,7 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter if e != nil { return resource.NonRetryableError(e) } + if !has { return resource.NonRetryableError(fmt.Errorf("[CRITAL]%s updating cynosdb cluster instance failed, instance doesn't exist", logId)) } @@ -545,12 +605,13 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter if cpu != cpuReal || memory != memReal { return resource.RetryableError(fmt.Errorf("[CRITAL] updating cynosdb instance, current cpu and memory values: %d, %d, waiting for them becoming new value: %d, %d", cpuReal, memReal, cpu, memory)) } + return nil }) + if errUpdate != nil { return errUpdate } - } if d.HasChange("instance_maintain_weekdays") || d.HasChange("instance_maintain_start_time") || d.HasChange("instance_maintain_duration") { @@ -559,13 +620,13 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter for _, v := range weekdays { reqWeekdays = append(reqWeekdays, helper.String(v.(string))) } + startTime := int64(d.Get("instance_maintain_start_time").(int)) duration := int64(d.Get("instance_maintain_duration").(int)) err := cynosdbService.ModifyMaintainPeriodConfig(ctx, instanceId, startTime, duration, reqWeekdays) if err != nil { return err } - } // update param @@ -574,6 +635,7 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter if e != nil { return e } + if !has { return fmt.Errorf("[CRITAL]%s updating cynosdb cluster instance failed, instance doesn't exist", logId) } @@ -599,15 +661,15 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter ParamName: &name, CurrentValue: &currVal, } + if ok { param.OldValue = &oldVal } + request.ParamList = append(request.ParamList, param) } - var ( - asyncRequestId string - ) + var asyncRequestId string err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { aReqId, modifyErr := cynosdbService.ModifyClusterParam(ctx, request) if modifyErr != nil { @@ -615,48 +677,132 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter if err.Code == "FailedOperation.OperationFailedError" { return resource.RetryableError(err) } + return resource.NonRetryableError(err) } + asyncRequestId = aReqId return nil }) + if err != nil { return err } mysqlService := svccdb.NewMysqlService(client) - _ = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { taskStatus, message, err := mysqlService.DescribeAsyncRequestInfo(ctx, asyncRequestId) if err != nil { return resource.NonRetryableError(err) } + if taskStatus == svccdb.MYSQL_TASK_STATUS_SUCCESS { return nil } + if taskStatus == svccdb.MYSQL_TASK_STATUS_INITIAL || taskStatus == svccdb.MYSQL_TASK_STATUS_RUNNING { return resource.RetryableError(fmt.Errorf("%s modify params task status is %s", clusterId, taskStatus)) } + err = fmt.Errorf("%s create account task status is %s,we won't wait for it finish ,it show message:%s", clusterId, taskStatus, message) return resource.NonRetryableError(err) }) - } - if d.HasChange("prarm_template_id") { - return fmt.Errorf("prarm_template_id not support update!") + // update slave_zone + if d.HasChange("slave_zone") { + oldValue, newValue := d.GetChange("slave_zone") + oldSlaveZone := oldValue.(string) + newSlaveZone := newValue.(string) + var flowId int64 + // add slave_zone + if oldSlaveZone == "" && newSlaveZone != "" { + request := cynosdb.NewAddClusterSlaveZoneRequest() + request.ClusterId = helper.String(clusterId) + request.SlaveZone = helper.String(newSlaveZone) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + response, err := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseCynosdbClient().AddClusterSlaveZone(request) + if err != nil { + return tccommon.RetryError(err) + } + + flowId = *response.Response.FlowId + return nil + }) + + if err != nil { + return err + } + } else if oldSlaveZone != "" && newSlaveZone == "" { + // del slave_zone + request := cynosdb.NewRemoveClusterSlaveZoneRequest() + request.ClusterId = helper.String(clusterId) + request.SlaveZone = helper.String(oldSlaveZone) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + response, err := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseCynosdbClient().RemoveClusterSlaveZone(request) + if err != nil { + return tccommon.RetryError(err) + } + + flowId = *response.Response.FlowId + return nil + }) + + if err != nil { + return err + } + } else { + // update slave_zone + request := cynosdb.NewModifyClusterSlaveZoneRequest() + request.ClusterId = helper.String(clusterId) + request.OldSlaveZone = helper.String(oldSlaveZone) + request.NewSlaveZone = helper.String(newSlaveZone) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + response, err := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseCynosdbClient().ModifyClusterSlaveZone(request) + if err != nil { + return tccommon.RetryError(err) + } + + flowId = *response.Response.FlowId + return nil + }) + + if err != nil { + return err + } + } + + service := CynosdbService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + err := resource.Retry(6*tccommon.ReadRetryTimeout, func() *resource.RetryError { + ok, err := service.DescribeFlow(ctx, flowId) + if err != nil { + if _, ok := err.(*sdkErrors.TencentCloudSDKError); !ok { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + + if ok { + return nil + } else { + return resource.RetryableError(fmt.Errorf("update cynosdb slave_zone is processing")) + } + }) + + if err != nil { + return err + } } // update tags if d.HasChange("tags") { oldTags, newTags := d.GetChange("tags") replaceTags, deleteTags := svctag.DiffTags(oldTags.(map[string]interface{}), newTags.(map[string]interface{})) - resourceName := tccommon.BuildTagResourceName("cynosdb", "instance", region, clusterId) if err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags); err != nil { return err } - //internal version: replace waitTag begin, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. //internal version: replace waitTag end, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. } @@ -668,16 +814,19 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter for _, item := range v { vv = append(vv, helper.String(item.(string))) } + if err := cynosdbService.ModifyInsGrpSecurityGroups(ctx, d.Get("rw_group_id").(string), d.Get("available_zone").(string), vv); err != nil { return err } } + if d.HasChange("ro_group_sg") { v := d.Get("ro_group_sg").([]interface{}) vv := make([]*string, 0, len(v)) for _, item := range v { vv = append(vv, helper.String(item.(string))) } + if roGroupId := d.Get("ro_group_id").(string); roGroupId != "" { err := cynosdbService.ModifyInsGrpSecurityGroups(ctx, roGroupId, d.Get("available_zone").(string), vv) if err != nil { @@ -687,8 +836,6 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter } // update serverless status - - // serverless status if d.HasChange("serverless_status_flag") { resume := d.Get("serverless_status_flag").(string) == "resume" err := cynosdbService.SwitchServerlessCluster(ctx, clusterId, resume) @@ -743,26 +890,21 @@ func resourceTencentCloudCynosdbClusterUpdate(d *schema.ResourceData, meta inter func resourceTencentCloudCynosdbClusterDelete(d *schema.ResourceData, meta interface{}) error { defer tccommon.LogElapsed("resource.tencentcloud_cynosdb_cluster.delete")() - logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - - clusterID := d.Id() - cynosdbService := CynosdbService{ - client: meta.(tccommon.ProviderMeta).GetAPIV3Conn(), - } - - forceDelete := d.Get("force_delete").(bool) var ( - err error + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + cynosdbService = CynosdbService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + clusterID = d.Id() + err error ) - _, err = cynosdbService.IsolateCluster(ctx, clusterID) + forceDelete := d.Get("force_delete").(bool) + _, err = cynosdbService.IsolateCluster(ctx, clusterID) if err != nil { return err } conf := tccommon.BuildStateChangeConf([]string{}, []string{"isolated"}, 2*tccommon.ReadRetryTimeout, time.Second, cynosdbService.CynosdbInstanceIsolateStateRefreshFunc(d.Id(), []string{})) - if _, e := conf.WaitForState(); e != nil { return e } @@ -773,13 +915,13 @@ func resourceTencentCloudCynosdbClusterDelete(d *schema.ResourceData, meta inter } conf := tccommon.BuildStateChangeConf([]string{}, []string{"offlined"}, 2*tccommon.ReadRetryTimeout, time.Second, cynosdbService.CynosdbInstanceOfflineStateRefreshFunc(d.Id(), []string{})) - if _, e := conf.WaitForState(); e != nil { if ee, ok := e.(*sdkErrors.TencentCloudSDKError); ok { if ee.Message == "record not found" { return nil } } + return e } } diff --git a/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.md b/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.md index 6cbc72f863..db7db26568 100644 --- a/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.md +++ b/tencentcloud/services/cynosdb/resource_tc_cynosdb_cluster.md @@ -2,18 +2,56 @@ Provide a resource to create a CynosDB cluster. Example Usage +Create a single availability zone NORMAL CynosDB cluster + ```hcl -resource "tencentcloud_cynosdb_cluster" "foo" { - available_zone = "ap-guangzhou-4" - vpc_id = "vpc-h70b6b49" - subnet_id = "subnet-q6fhy1mi" +variable "availability_zone" { + default = "ap-guangzhou-3" +} + +# create vpc +resource "tencentcloud_vpc" "vpc" { + name = "vpc" + cidr_block = "10.0.0.0/16" +} + +# create subnet +resource "tencentcloud_subnet" "subnet" { + availability_zone = var.availability_zone + name = "subnet" + vpc_id = tencentcloud_vpc.vpc.id + cidr_block = "10.0.20.0/28" + is_multicast = false +} + +# create security group +resource "tencentcloud_security_group" "example" { + name = "tf-example" + description = "sg desc." + project_id = 0 + + tags = { + "example" = "test" + } +} + +# create cynosdb cluster +resource "tencentcloud_cynosdb_cluster" "example" { + available_zone = var.availability_zone + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + db_mode = "NORMAL" db_type = "MYSQL" db_version = "5.7" + port = 3306 storage_limit = 1000 - cluster_name = "tf-cynosdb" - password = "cynos@123" + cluster_name = "tf-example" + password = "cynosDB@123" instance_maintain_duration = 7200 instance_maintain_start_time = 10800 + instance_cpu_core = 2 + instance_memory_size = 4 + force_delete = false instance_maintain_weekdays = [ "Fri", "Mon", @@ -24,28 +62,120 @@ resource "tencentcloud_cynosdb_cluster" "foo" { "Tue", ] - instance_cpu_core = 1 - instance_memory_size = 2 - - param_item { - name = "character_set_server" + param_items { + name = "character_set_server" current_value = "utf8mb4" } - prarm_template_id = "12345" + param_items { + name = "lower_case_table_names" + current_value = "0" + } + + rw_group_sg = [ + tencentcloud_security_group.example.id, + ] + + ro_group_sg = [ + tencentcloud_security_group.example.id, + ] tags = { - test = "test" + createBy = "terraform" } +} +``` - force_delete = false +Create a multiple availability zone SERVERLESS CynosDB cluster + +```hcl +variable "availability_zone" { + default = "ap-guangzhou-4" +} + +variable "slave_zone" { + default = "ap-guangzhou-6" +} + +# create vpc +resource "tencentcloud_vpc" "vpc" { + name = "vpc" + cidr_block = "10.0.0.0/16" +} + +# create subnet +resource "tencentcloud_subnet" "subnet" { + availability_zone = var.availability_zone + name = "subnet" + vpc_id = tencentcloud_vpc.vpc.id + cidr_block = "10.0.20.0/28" + is_multicast = false +} + +# create security group +resource "tencentcloud_security_group" "example" { + name = "tf-example" + description = "sg desc." + project_id = 0 + + tags = { + "example" = "test" + } +} + +# create param template +resource "tencentcloud_cynosdb_param_template" "example" { + db_mode = "SERVERLESS" + engine_version = "8.0" + template_name = "tf-example" + template_description = "terraform-template" + + param_list { + current_value = "-1" + param_name = "optimizer_trace_offset" + } +} + +# create cynosdb cluster +resource "tencentcloud_cynosdb_cluster" "example" { + available_zone = var.availability_zone + slave_zone = var.slave_zone + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + db_mode = "SERVERLESS" + db_type = "MYSQL" + db_version = "8.0" + port = 3306 + storage_limit = 1000 + cluster_name = "tf-example" + password = "cynosDB@123" + instance_maintain_duration = 7200 + instance_maintain_start_time = 10800 + min_cpu = 2 + max_cpu = 4 + param_template_id = tencentcloud_cynosdb_param_template.example.template_id + force_delete = false + instance_maintain_weekdays = [ + "Fri", + "Mon", + "Sat", + "Sun", + "Thu", + "Wed", + "Tue", + ] rw_group_sg = [ - "sg-ibyjkl6r", + tencentcloud_security_group.example.id, ] + ro_group_sg = [ - "sg-ibyjkl6r", + tencentcloud_security_group.example.id, ] + + tags = { + createBy = "terraform" + } } ``` @@ -54,5 +184,5 @@ Import CynosDB cluster can be imported using the id, e.g. ``` -$ terraform import tencentcloud_cynosdb_cluster.foo cynosdbmysql-dzj5l8gz -``` \ No newline at end of file +$ terraform import tencentcloud_cynosdb_cluster.example cynosdbmysql-dzj5l8gz +``` diff --git a/tencentcloud/services/cynosdb/service_tencentcloud_cynosdb.go b/tencentcloud/services/cynosdb/service_tencentcloud_cynosdb.go index 09697859e6..a5fbf69d75 100644 --- a/tencentcloud/services/cynosdb/service_tencentcloud_cynosdb.go +++ b/tencentcloud/services/cynosdb/service_tencentcloud_cynosdb.go @@ -104,7 +104,7 @@ func (me *CynosdbService) DescribeClusterById(ctx context.Context, clusterId str // get cluster status var notExist bool var clusters []*cynosdb.CynosdbCluster - errRet = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + errRet = resource.Retry(tccommon.ReadRetryTimeout*5, func() *resource.RetryError { ratelimit.Check(request.GetAction()) clusters, errRet = me.DescribeClusters(ctx, map[string]string{"ClusterId": clusterId}) if errRet != nil { @@ -165,7 +165,7 @@ func (me *CynosdbService) UpgradeInstance(ctx context.Context, instanceId string request.Memory = &mem request.UpgradeType = helper.String(CYNOSDB_UPGRADE_IMMEDIATE) - errRet = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + errRet = resource.Retry(tccommon.WriteRetryTimeout*2, func() *resource.RetryError { ratelimit.Check(request.GetAction()) _, errRet = me.client.UseCynosdbClient().UpgradeInstance(request) if errRet != nil { @@ -330,7 +330,7 @@ func (me *CynosdbService) DescribeInstanceById(ctx context.Context, instanceId s var notExist bool var instances []*cynosdb.CynosdbInstance - errRet = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + errRet = resource.Retry(tccommon.ReadRetryTimeout*5, func() *resource.RetryError { ratelimit.Check(request.GetAction()) instances, errRet = me.DescribeInstances(ctx, map[string]string{"InstanceId": instanceId}) if errRet != nil { diff --git a/website/docs/r/cynosdb_cluster.html.markdown b/website/docs/r/cynosdb_cluster.html.markdown index f77ad576c6..9e2d9c241f 100644 --- a/website/docs/r/cynosdb_cluster.html.markdown +++ b/website/docs/r/cynosdb_cluster.html.markdown @@ -13,18 +13,56 @@ Provide a resource to create a CynosDB cluster. ## Example Usage +### Create a single availability zone NORMAL CynosDB cluster + ```hcl -resource "tencentcloud_cynosdb_cluster" "foo" { - available_zone = "ap-guangzhou-4" - vpc_id = "vpc-h70b6b49" - subnet_id = "subnet-q6fhy1mi" +variable "availability_zone" { + default = "ap-guangzhou-3" +} + +# create vpc +resource "tencentcloud_vpc" "vpc" { + name = "vpc" + cidr_block = "10.0.0.0/16" +} + +# create subnet +resource "tencentcloud_subnet" "subnet" { + availability_zone = var.availability_zone + name = "subnet" + vpc_id = tencentcloud_vpc.vpc.id + cidr_block = "10.0.20.0/28" + is_multicast = false +} + +# create security group +resource "tencentcloud_security_group" "example" { + name = "tf-example" + description = "sg desc." + project_id = 0 + + tags = { + "example" = "test" + } +} + +# create cynosdb cluster +resource "tencentcloud_cynosdb_cluster" "example" { + available_zone = var.availability_zone + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + db_mode = "NORMAL" db_type = "MYSQL" db_version = "5.7" + port = 3306 storage_limit = 1000 - cluster_name = "tf-cynosdb" - password = "cynos@123" + cluster_name = "tf-example" + password = "cynosDB@123" instance_maintain_duration = 7200 instance_maintain_start_time = 10800 + instance_cpu_core = 2 + instance_memory_size = 4 + force_delete = false instance_maintain_weekdays = [ "Fri", "Mon", @@ -35,28 +73,120 @@ resource "tencentcloud_cynosdb_cluster" "foo" { "Tue", ] - instance_cpu_core = 1 - instance_memory_size = 2 - - param_item { + param_items { name = "character_set_server" current_value = "utf8mb4" } - prarm_template_id = "12345" + param_items { + name = "lower_case_table_names" + current_value = "0" + } + + rw_group_sg = [ + tencentcloud_security_group.example.id, + ] + + ro_group_sg = [ + tencentcloud_security_group.example.id, + ] + + tags = { + createBy = "terraform" + } +} +``` + +### Create a multiple availability zone SERVERLESS CynosDB cluster + +```hcl +variable "availability_zone" { + default = "ap-guangzhou-4" +} + +variable "slave_zone" { + default = "ap-guangzhou-6" +} + +# create vpc +resource "tencentcloud_vpc" "vpc" { + name = "vpc" + cidr_block = "10.0.0.0/16" +} + +# create subnet +resource "tencentcloud_subnet" "subnet" { + availability_zone = var.availability_zone + name = "subnet" + vpc_id = tencentcloud_vpc.vpc.id + cidr_block = "10.0.20.0/28" + is_multicast = false +} + +# create security group +resource "tencentcloud_security_group" "example" { + name = "tf-example" + description = "sg desc." + project_id = 0 tags = { - test = "test" + "example" = "test" } +} - force_delete = false +# create param template +resource "tencentcloud_cynosdb_param_template" "example" { + db_mode = "SERVERLESS" + engine_version = "8.0" + template_name = "tf-example" + template_description = "terraform-template" + + param_list { + current_value = "-1" + param_name = "optimizer_trace_offset" + } +} + +# create cynosdb cluster +resource "tencentcloud_cynosdb_cluster" "example" { + available_zone = var.availability_zone + slave_zone = var.slave_zone + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + db_mode = "SERVERLESS" + db_type = "MYSQL" + db_version = "8.0" + port = 3306 + storage_limit = 1000 + cluster_name = "tf-example" + password = "cynosDB@123" + instance_maintain_duration = 7200 + instance_maintain_start_time = 10800 + min_cpu = 2 + max_cpu = 4 + param_template_id = tencentcloud_cynosdb_param_template.example.template_id + force_delete = false + instance_maintain_weekdays = [ + "Fri", + "Mon", + "Sat", + "Sun", + "Thu", + "Wed", + "Tue", + ] rw_group_sg = [ - "sg-ibyjkl6r", + tencentcloud_security_group.example.id, ] + ro_group_sg = [ - "sg-ibyjkl6r", + tencentcloud_security_group.example.id, ] + + tags = { + createBy = "terraform" + } } ``` @@ -67,7 +197,7 @@ The following arguments are supported: * `available_zone` - (Required, String, ForceNew) The available zone of the CynosDB Cluster. * `cluster_name` - (Required, String) Name of CynosDB cluster. * `db_type` - (Required, String, ForceNew) Type of CynosDB, and available values include `MYSQL`. -* `db_version` - (Required, String, ForceNew) Version of CynosDB, which is related to `db_type`. For `MYSQL`, available value is `5.7`. +* `db_version` - (Required, String, ForceNew) Version of CynosDB, which is related to `db_type`. For `MYSQL`, available value is `5.7`, `8.0`. * `password` - (Required, String, ForceNew) Password of `root` account. * `subnet_id` - (Required, String) ID of the subnet within this VPC. * `vpc_id` - (Required, String) ID of the VPC. @@ -85,14 +215,16 @@ The following arguments are supported: * `max_cpu` - (Optional, Float64) Maximum CPU core count, required while `db_mode` is `SERVERLESS`, request DescribeServerlessInstanceSpecs for more reference. * `min_cpu` - (Optional, Float64) Minimum CPU core count, required while `db_mode` is `SERVERLESS`, request DescribeServerlessInstanceSpecs for more reference. * `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. -* `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. +* `param_items` - (Optional, List) Specify parameter list of database. It is valid when `param_template_id` is set in create cluster. Use `data.tencentcloud_mysql_default_params` to query available parameter details. +* `param_template_id` - (Optional, Int) The ID of the parameter template. * `port` - (Optional, Int, ForceNew) Port of CynosDB cluster. -* `prarm_template_id` - (Optional, Int) The ID of the parameter template. +* `prarm_template_id` - (Optional, Int, **Deprecated**) It will be deprecated. Use `param_template_id` instead. The ID of the parameter template. * `prepaid_period` - (Optional, Int, ForceNew) The tenancy (time unit is month) of the prepaid instance. Valid values are `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `24`, `36`. NOTE: it only works when charge_type is set to `PREPAID`. * `project_id` - (Optional, Int, ForceNew) ID of the project. `0` by default. * `ro_group_sg` - (Optional, List: [`String`]) IDs of security group for `ro_group`. * `rw_group_sg` - (Optional, List: [`String`]) IDs of security group for `rw_group`. * `serverless_status_flag` - (Optional, String) Specify whether to pause or resume serverless cluster. values: `resume`, `pause`. +* `slave_zone` - (Optional, String) Multi zone Addresses of the CynosDB Cluster. * `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. * `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. * `tags` - (Optional, Map) The tags of the CynosDB cluster. @@ -138,6 +270,6 @@ In addition to all arguments above, the following attributes are exported: CynosDB cluster can be imported using the id, e.g. ``` -$ terraform import tencentcloud_cynosdb_cluster.foo cynosdbmysql-dzj5l8gz +$ terraform import tencentcloud_cynosdb_cluster.example cynosdbmysql-dzj5l8gz ```