alibabacloudstack/resource_apsarastack_adb_dbcluster.go (484 lines of code) (raw):

package alibabacloudstack import ( "fmt" "log" "strconv" "strings" "time" "github.com/aliyun/alibaba-cloud-sdk-go/services/adb" util "github.com/alibabacloud-go/tea-utils/service" "github.com/alibabacloud-go/tea/tea" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/connectivity" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/errmsgs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceAlibabacloudStackAdbDbCluster() *schema.Resource { resource := &schema.Resource{ Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(50 * time.Minute), Delete: schema.DefaultTimeout(50 * time.Minute), Update: schema.DefaultTimeout(72 * time.Minute), }, Schema: map[string]*schema.Schema{ "auto_renew_period": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntInSlice([]int{1, 2, 3, 6, 12, 24, 36}), Default: 1, DiffSuppressFunc: adbPostPaidAndRenewDiffSuppressFunc, }, "compute_resource": { Type: schema.TypeString, Optional: true, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { if v, ok := d.GetOk("mode"); ok && v.(string) == "reserver" { return true } return false }, }, /*"connection_string": { Type: schema.TypeString, Computed: true, },*/ "db_cluster_category": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{"Basic", "Cluster", "basic", "cluster"}, false), }, "db_cluster_class": { Type: schema.TypeString, Optional: true, Deprecated: "It duplicates with attribute db_node_class and is deprecated from 1.121.2.", }, "storage_resource": { Type: schema.TypeString, Optional: true, Computed: true, }, "storage_type": { Type: schema.TypeString, Optional: true, Computed: true, }, "db_cluster_version": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"3.0"}, false), Default: "3.0", }, "cluster_type": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{"analyticdb", "AnalyticdbOnPanguHybrid", "AnalyticdbOnPanguSSD"}, false), }, "cpu_type": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{"intel", "hygon"}, false), }, "db_node_class": { Type: schema.TypeString, Optional: true, Computed: true, }, "db_node_count": { Type: schema.TypeInt, Optional: true, Computed: true, }, "executor_count": { Type: schema.TypeInt, Optional: true, Computed: true, }, "db_node_storage": { Type: schema.TypeInt, Optional: true, Computed: true, }, "description": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: validation.StringLenBetween(2, 256), }, //"elastic_io_resource": { // Type: schema.TypeInt, // Optional: true, // Default: 0, // DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { // if v, ok := d.GetOk("mode"); ok && v.(string) == "reserver" { // return true // } // return false // }, //}, "maintain_time": { Type: schema.TypeString, Optional: true, Computed: true, }, "mode": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{"reserver", "flexible"}, false), }, "modify_type": { Type: schema.TypeString, Optional: true, }, "payment_type": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"PayAsYouGo", "Subscription"}, false), Deprecated: "Field 'payment_type' is deprecated and will be removed in a future release. Please use new field 'pay_type' instead.", ConflictsWith: []string{"pay_type"}, }, "pay_type": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"PostPaid", "PrePaid"}, false), ConflictsWith: []string{"payment_type"}, }, "period": { Type: schema.TypeInt, ValidateFunc: validation.IntInSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}), DiffSuppressFunc: adbPostPaidDiffSuppressFunc, Optional: true, }, "renewal_status": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{"AutoRenewal", "Normal", "NotRenewal"}, false), Default: "NotRenewal", DiffSuppressFunc: adbPostPaidDiffSuppressFunc, }, "resource_group_id": { Type: schema.TypeString, Optional: true, Computed: true, }, "security_ips": { Type: schema.TypeSet, Optional: true, Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, }, }, "status": { Type: schema.TypeString, Computed: true, }, //"tags": tagsSchema(), "vswitch_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "instance_inner_connection": { Type: schema.TypeString, Deprecated: "Field 'instance_inner_connection' is deprecated and will be removed in a future release. Please use new field 'connection_string' instead.", Computed: true, }, "instance_inner_port": { Type: schema.TypeString, Deprecated: "Field 'instance_inner_port' is deprecated and will be removed in a future release. Please use new field 'port' instead.", Computed: true, }, "instance_vpc_id": { Type: schema.TypeString, Computed: true, }, "connection_string": { Type: schema.TypeString, Computed: true, }, "port": { Type: schema.TypeString, Computed: true, }, "zone_id": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, }, } setResourceFunc(resource, resourceAlibabacloudStackAdbDbClusterCreate, resourceAlibabacloudStackAdbDbClusterRead, resourceAlibabacloudStackAdbDbClusterUpdate, resourceAlibabacloudStackAdbDbClusterDelete) return resource } func resourceAlibabacloudStackAdbDbClusterCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) adbService := AdbService{client} var response *adb.CreateDBClusterResponse request := adb.CreateCreateDBClusterRequest() client.InitRpcRequest(*request.RpcRequest) request.DBClusterCategory = d.Get("db_cluster_category").(string) if v, ok := d.GetOk("db_node_class"); ok { request.DBClusterClass = v.(string) } else if v, ok := d.GetOk("db_cluster_class"); ok { request.DBClusterClass = v.(string) } if v, ok := d.GetOk("storage_resource"); ok { request.StorageResource = v.(string) } if v, ok := d.GetOk("compute_resource"); ok { request.ComputeResource = v.(string) } if v, ok := d.GetOk("mode"); ok { request.Mode = v.(string) } if v, ok := d.GetOk("storage_type"); ok { request.StorageType = v.(string) } request.DBClusterVersion = d.Get("db_cluster_version").(string) if v, ok := d.GetOk("db_node_count"); ok { request.DBNodeGroupCount = strconv.Itoa(v.(int)) request.ExecutorCount = strconv.Itoa(v.(int)) } if v, ok := d.GetOk("db_node_storage"); ok { request.DBNodeStorage = strconv.Itoa(v.(int)) } if v, ok := d.GetOk("description"); ok { request.DBClusterDescription = v.(string) } if v, ok := connectivity.GetResourceDataOk(d, "pay_type", "payment_type"); ok { request.PayType = convertAdbDBClusterPaymentTypeRequest(v.(string)) if request.PayType != string(Postpaid) { request.PayType = string(Prepaid) period := d.Get("period").(int) request.UsedTime = strconv.Itoa(period) request.Period = string(Month) if period > 9 { request.UsedTime = strconv.Itoa(period / 12) request.Period = string(Year) } } } else { request.PayType = "Postpaid" } if v, ok := d.GetOk("resource_group_id"); ok { request.ResourceGroupId = v.(string) } if v, ok := d.GetOk("zone_id"); ok { request.ZoneId = v.(string) } request.DBClusterNetworkType = "Classic" request.QueryParams["ClusterType"] = d.Get("cluster_type").(string) request.QueryParams["CpuType"] = d.Get("cpu_type").(string) vswitchId := Trim(d.Get("vswitch_id").(string)) if vswitchId != "" { vpcService := VpcService{client} //vsw, err := vpcService.DescribeVSwitchWithTeadsl(vswitchId) var vsw, err = vpcService.DescribeVSwitch(vswitchId) if err != nil { return errmsgs.WrapError(err) } request.DBClusterNetworkType = "VPC" request.VPCId = vsw.VpcId request.VSwitchId = vswitchId if request.ZoneId == "" { request.ZoneId = vsw.ZoneId } } runtime := util.RuntimeOptions{IgnoreSSL: tea.Bool(client.Config.Insecure)} runtime.SetAutoretry(true) request.ClientToken = buildClientToken("CreateDBCluster") raw, err := client.WithAdbClient(func(adbClient *adb.Client) (interface{}, error) { log.Printf("[DEBUG] ======================================= domain: %s", client.Domain) return adbClient.CreateDBCluster(request) }) if err != nil { return errmsgs.WrapError(fmt.Errorf("[ERROR] CreateDBCluster got an error: %#v", err)) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) response, _ = raw.(*adb.CreateDBClusterResponse) d.SetId(fmt.Sprint(response.DBClusterId)) stateConf := BuildStateConf([]string{"Preparing", "Creating"}, []string{"Running"}, d.Timeout(schema.TimeoutCreate), 900*time.Second, adbService.AdbDbClusterStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return errmsgs.WrapErrorf(err, errmsgs.IdMsg, d.Id()) } return nil } func resourceAlibabacloudStackAdbDbClusterRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) adbService := AdbService{client} object, err := adbService.DescribeAdbDbCluster(d.Id()) info, err := adbService.DescribeAdbClusterNetInfo2(d.Id()) if err != nil { if errmsgs.NotFoundError(err) { log.Printf("[DEBUG] Resource AlibabacloudStack_analyticdb_for_mysql3.0_db_cluster adbService.DescribeAdbDbCluster Failed!!! %s", err) d.SetId("") return nil } return errmsgs.WrapError(err) } connectivity.SetResourceData(d, info.ConnectionString, "connection_string", "instance_inner_connection") connectivity.SetResourceData(d, info.Port, "port", "instance_inner_port") d.Set("instance_vpc_id", info.VPCId) d.Set("compute_resource", object["ComputeResource"]) //d.Set("connection_string", object["ConnectionString"]) d.Set("db_cluster_category", object["Category"]) d.Set("db_node_class", object["DBNodeClass"]) d.Set("db_node_count", object["DBNodeCount"]) d.Set("executor_count", object["ExecutorCount"]) d.Set("db_node_storage", object["DBNodeStorage"]) d.Set("storage_type", object["StorageType"]) d.Set("description", object["DBClusterDescription"]) //d.Set("elastic_io_resource", formatInt(object["ElasticIOResource"])) d.Set("maintain_time", object["MaintainTime"]) d.Set("mode", object["Mode"]) paytype := convertAdbDBClusterPaymentTypeResponse(object["PayType"].(string)) connectivity.SetResourceData(d, paytype, "pay_type", "payment_type") //d.Set("resource_group_id", object["ResourceGroupId"]) d.Set("status", object["DBClusterStatus"]) //d.Set("tags", tagsToMap(object["Tags"].(map[string]interface{})["Tag"])) d.Set("vswitch_id", object["VSwitchId"]) d.Set("zone_id", object["ZoneId"]) if object["PayType"].(string) == string(Prepaid) { describeAutoRenewAttributeObject, err := adbService.DescribeAutoRenewAttribute(d.Id()) if err != nil { return errmsgs.WrapError(err) } renewPeriod := 1 if describeAutoRenewAttributeObject != nil { renewPeriod = formatInt(describeAutoRenewAttributeObject["Duration"]) } if describeAutoRenewAttributeObject != nil && describeAutoRenewAttributeObject["PeriodUnit"] == string(Year) { renewPeriod = renewPeriod * 12 } d.Set("auto_renew_period", renewPeriod) //period, err := computePeriodByUnit(object["CreationTime"], object["ExpireTime"], d.Get("period").(int), "Month") //if err != nil { // return errmsgs.WrapError(err) //} //d.Set("period", period) d.Set("renewal_status", describeAutoRenewAttributeObject["RenewalStatus"]) } describeDBClusterAccessWhiteListObject, err := adbService.DescribeDBClusterAccessWhiteList(d.Id()) if err != nil { return errmsgs.WrapError(err) } d.Set("security_ips", strings.Split(describeDBClusterAccessWhiteListObject["SecurityIPList"].(string), ",")) describeDBClustersObject, err := adbService.DescribeDBClusters(d.Id()) if err != nil { return errmsgs.WrapError(err) } d.Set("db_cluster_version", describeDBClustersObject["DBVersion"]) return nil } func resourceAlibabacloudStackAdbDbClusterUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) adbService := AdbService{client} d.Partial(true) //专有云 没有 UntagResources 接口 /*if d.HasChange("tags") { if err := adbService.SetResourceTags(d, "ALIYUN::ADB::CLUSTER"); err != nil { return errmsgs.WrapError(err) } d.SetPartial("tags") }*/ if !d.IsNewResource() && d.HasChange("description") { request := map[string]interface{}{ "DBClusterId": d.Id(), } request["DBClusterDescription"] = d.Get("description") action := "ModifyDBClusterDescription" _, err := client.DoTeaRequest("POST", "adb", "2019-03-15", action, "", nil, nil, request) if err != nil { return err } //d.SetPartial("description") } //专有云 没有 ModifyDBClusterMaintainTime 接口 /*if d.HasChange("maintain_time") { request := map[string]interface{}{ "DBClusterId": d.Id(), } request["MaintainTime"] = d.Get("maintain_time") request["Product"] = "adb" request["OrganizationId"] = client.Department action := "ModifyDBClusterMaintainTime" conn, err := client.NewAdsClient() if err != nil { return errmsgs.WrapError(err) } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-03-15"), StringPointer("AK"), nil, request, &util.RuntimeOptions{IgnoreSSL: tea.Bool(client.Config.Insecure)}) if err != nil { if errmsgs.NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return errmsgs.WrapErrorf(err, errmsgs.DefaultErrorMsg, d.Id(), action, errmsgs.AlibabacloudStackSdkGoERROR) } d.SetPartial("maintain_time") }*/ //专有云 没有 ModifyDBClusterResourceGroup 接口 /*if !d.IsNewResource() && d.HasChange("resource_group_id") { request := map[string]interface{}{ "DBClusterId": d.Id(), } request["NewResourceGroupId"] = d.Get("resource_group_id") request["Product"] = "adb" request["OrganizationId"] = client.Department action := "ModifyDBClusterResourceGroup" conn, err := client.NewAdsClient() if err != nil { return errmsgs.WrapError(err) } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-03-15"), StringPointer("AK"), nil, request, &util.RuntimeOptions{IgnoreSSL: tea.Bool(client.Config.Insecure)}) if err != nil { if errmsgs.NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return errmsgs.WrapErrorf(err, errmsgs.DefaultErrorMsg, d.Id(), action, errmsgs.AlibabacloudStackSdkGoERROR) } d.SetPartial("resource_group_id") }*/ update := false //专有云 316 版本没有 ModifyAutoRenewAttribute 接口 /*request := map[string]interface{}{ "DBClusterId": d.Id(), } request["Product"] = "adb" request["OrganizationId"] = client.Department request["RegionId"] = client.RegionId if d.Get("pay_type").(string) == string(PrePaid) || d.Get("payment_type").(string) == "Subscription" && d.HasChange("auto_renew_period") { update = true if d.Get("renewal_status").(string) == string(RenewAutoRenewal) { period := d.Get("auto_renew_period").(int) request["Duration"] = strconv.Itoa(period) request["PeriodUnit"] = string(Month) if period > 9 { request["Duration"] = strconv.Itoa(period / 12) request["PeriodUnit"] = string(Year) } } } if d.Get("pay_type").(string) == string(PrePaid) || d.Get("payment_type").(string) == "Subscription" && d.HasChange("renewal_status") { update = true request["RenewalStatus"] = d.Get("renewal_status") } if update { action := "ModifyAutoRenewAttribute" response, err = client.DoTeaRequest("POST", "adb", "2019-03-15", action, "", nil, nil, request) if err != nil { return errmsgs.WrapErrorf(err, errmsgs.DefaultErrorMsg, d.Id(), action, errmsgs.AlibabacloudStackSdkGoERROR) } addDebug(action, response, request) d.SetPartial("auto_renew_period") d.SetPartial("renewal_status") }*/ update = false modifyDBClusterAccessWhiteListReq := map[string]interface{}{ "DBClusterId": d.Id(), } if d.HasChange("security_ips") { update = true } modifyDBClusterAccessWhiteListReq["SecurityIps"] = convertListToCommaSeparate(d.Get("security_ips").(*schema.Set).List()) if update { action := "ModifyDBClusterAccessWhiteList" _, err := client.DoTeaRequest("POST", "adb", "2019-03-15", action, "", nil, nil, modifyDBClusterAccessWhiteListReq) if err != nil { return err } //d.SetPartial("security_ips") } update = false // 目前 316 版本页面 仅支持 变配 节点数量 modifyDBClusterReq := map[string]interface{}{ "DBClusterId": d.Id(), } //if !d.IsNewResource() && d.HasChange("compute_resource") { // update = true // modifyDBClusterReq["ComputeResource"] = d.Get("compute_resource") //} //if !d.IsNewResource() && d.HasChange("db_cluster_category") { // update = true // modifyDBClusterReq["DBClusterCategory"] = d.Get("db_cluster_category") //} //if !d.IsNewResource() && d.HasChange("db_node_class") { // update = true // modifyDBClusterReq["DBNodeClass"] = d.Get("db_node_class") //} if !d.IsNewResource() && d.HasChange("db_node_count") { update = true modifyDBClusterReq["DBNodeGroupCount"] = d.Get("db_node_count") } if !d.IsNewResource() && d.HasChange("executor_count") { update = true modifyDBClusterReq["ExecutorCount"] = d.Get("executor_count") } if !d.IsNewResource() && d.HasChange("db_node_storage") { update = true modifyDBClusterReq["DBNodeStorage"] = d.Get("db_node_storage") } //if d.HasChange("elastic_io_resource") { // update = true // modifyDBClusterReq["ElasticIOResource"] = d.Get("elastic_io_resource") //} if update { if _, ok := d.GetOk("mode"); ok { modifyDBClusterReq["Mode"] = d.Get("mode") } if _, ok := d.GetOk("modify_type"); ok { modifyDBClusterReq["ModifyType"] = d.Get("modify_type") } action := "ModifyDBCluster" _, err := client.DoTeaRequest("POST", "adb", "2019-03-15", action, "", nil, nil, modifyDBClusterReq) if err != nil { return err } stateConf := BuildStateConf([]string{"ClassChanging"}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 900*time.Second, adbService.AdbDbClusterStateRefreshFunc(d.Id(), []string{})) if _, err := stateConf.WaitForState(); err != nil { return errmsgs.WrapErrorf(err, errmsgs.IdMsg, d.Id()) } //d.SetPartial("compute_resource") //d.SetPartial("db_cluster_category") //d.SetPartial("db_node_class") //d.SetPartial("db_node_count") //d.SetPartial("db_node_storage") //d.SetPartial("elastic_io_resource") } d.Partial(false) return nil } func resourceAlibabacloudStackAdbDbClusterDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) //adbService := AdbService{client} action := "DeleteDBCluster" request := map[string]interface{}{ "DBClusterId": d.Id(), } _, err := client.DoTeaRequest("POST", "adb", "2019-03-15", action, "", nil, nil, request) if err != nil { if errmsgs.IsExpectedErrors(err, []string{"InvalidDBCluster.NotFound"}) { return nil } return err } //stateConf := BuildStateConf([]string{"Waiting", "Running", "Failed", "Retry", "Pause", "Stop"}, []string{"Finished", "Closed", "Cancel"}, d.Timeout(schema.TimeoutDelete), 10*time.Minute, adbService.AdbTaskStateRefreshFunc(d.Id(), taskId)) //if _, err = stateConf.WaitForState(); err != nil { // return errmsgs.WrapErrorf(err, errmsgs.IdMsg, d.Id()) //} return nil } func convertAdbDbClusterDBClusterPayTypeRequest(source string) string { switch source { case "PostPaid": return "Postpaid" case "PrePaid": return "Prepaid" } return source } func convertAdbDbClusterDBClusterPayTypeResponse(source string) string { switch source { case "Postpaid": return "PostPaid" case "Prepaid": return "PrePaid" } return source } func convertAdbDBClusterPaymentTypeRequest(source string) string { switch source { case "PayAsYouGo": return "Postpaid" case "Subscription": return "Prepaid" } return source } func convertAdbDBClusterPaymentTypeResponse(source string) string { switch source { case "Postpaid": return "PayAsYouGo" case "Prepaid": return "Subscription" } return source } func convertAdbDBClusterCategoryResponse(source string) string { switch source { case "MIXED_STORAGE": return "MixedStorage" case "basic": return "Basic" case "cluster": return "Cluster" } return source }