alicloud/resource_alicloud_mongodb_instance.go (1,104 lines of code) (raw):

package alicloud import ( "fmt" "log" "sort" "strconv" "strings" "time" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/samber/lo" ) func resourceAliCloudMongoDBInstance() *schema.Resource { return &schema.Resource{ Create: resourceAliCloudMongoDBInstanceCreate, Read: resourceAliCloudMongoDBInstanceRead, Update: resourceAliCloudMongoDBInstanceUpdate, Delete: resourceAliCloudMongoDBInstanceDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), Update: schema.DefaultTimeout(30 * time.Minute), Delete: schema.DefaultTimeout(30 * time.Minute), }, Schema: map[string]*schema.Schema{ "engine_version": { Type: schema.TypeString, Required: true, }, "db_instance_class": { Type: schema.TypeString, Required: true, }, "db_instance_storage": { Type: schema.TypeInt, Required: true, }, "storage_engine": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, ValidateFunc: StringInSlice([]string{"WiredTiger", "RocksDB"}, false), }, "storage_type": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"cloud_essd1", "cloud_essd2", "cloud_essd3", "cloud_auto", "local_ssd"}, false), }, "provisioned_iops": { Type: schema.TypeInt, Optional: true, }, "vpc_id": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, }, "vswitch_id": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, }, "zone_id": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, }, "secondary_zone_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "hidden_zone_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "security_group_id": { Type: schema.TypeString, Optional: true, }, "network_type": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, ValidateFunc: StringInSlice([]string{"Classic", "VPC"}, false), }, "name": { Type: schema.TypeString, Optional: true, ValidateFunc: StringLenBetween(2, 256), }, "instance_charge_type": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{string(PrePaid), string(PostPaid)}, false), }, "period": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntInSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}), DiffSuppressFunc: PostPaidDiffSuppressFunc, }, "security_ip_list": { Type: schema.TypeSet, Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "account_password": { Type: schema.TypeString, Optional: true, Sensitive: true, }, "kms_encrypted_password": { Type: schema.TypeString, Optional: true, DiffSuppressFunc: kmsDiffSuppressFunc, }, "kms_encryption_context": { Type: schema.TypeMap, Optional: true, Elem: schema.TypeString, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return d.Get("kms_encrypted_password").(string) == "" }, }, "encrypted": { Type: schema.TypeBool, Optional: true, ForceNew: true, }, "cloud_disk_encryption_key": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "replication_factor": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntInSlice([]int{1, 3, 5, 7}), }, "readonly_replicas": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(0, 5), }, "resource_group_id": { Type: schema.TypeString, Optional: true, Computed: true, }, "auto_renew": { Type: schema.TypeBool, Optional: true, }, "backup_time": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice(BACKUP_TIME, false), }, "backup_period": { Type: schema.TypeSet, Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "backup_retention_period": { Type: schema.TypeInt, Optional: true, Computed: true, }, "backup_retention_policy_on_cluster_deletion": { Type: schema.TypeInt, Optional: true, }, "enable_backup_log": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntInSlice([]int{0, 1}), }, "log_backup_retention_period": { Type: schema.TypeInt, Optional: true, Computed: true, }, "snapshot_backup_type": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"Standard", "Flash"}, false), }, "backup_interval": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"-1", "15", "30", "60", "120", "180", "240", "360", "480", "720"}, false), }, "ssl_action": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"Open", "Close", "Update"}, false), }, "maintain_start_time": { Type: schema.TypeString, Optional: true, Computed: true, }, "maintain_end_time": { Type: schema.TypeString, Optional: true, Computed: true, }, "effective_time": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"Immediately", "MaintainTime"}, false), }, "order_type": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"UPGRADE", "DOWNGRADE"}, false), }, "tde_status": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"enabled", "disabled"}, false), ConflictsWith: []string{"encrypted", "cloud_disk_encryption_key"}, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return d.Get("engine_version").(string) < "4.0" }, }, "encryptor_name": { Type: schema.TypeString, Optional: true, Computed: true, ConflictsWith: []string{"encrypted", "cloud_disk_encryption_key"}, }, "encryption_key": { Type: schema.TypeString, Optional: true, Computed: true, ConflictsWith: []string{"encrypted", "cloud_disk_encryption_key"}, }, "role_arn": { Type: schema.TypeString, Optional: true, Computed: true, }, "tags": tagsSchema(), "parameters": { Type: schema.TypeSet, Optional: true, Computed: true, Set: parameterToHash, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, Required: true, }, "value": { Type: schema.TypeString, Required: true, }, }, }, }, "retention_period": { Type: schema.TypeInt, Computed: true, }, "replica_set_name": { Type: schema.TypeString, Computed: true, }, "ssl_status": { Type: schema.TypeString, Computed: true, }, "replica_sets": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "vpc_id": { Type: schema.TypeString, Computed: true, }, "vswitch_id": { Type: schema.TypeString, Computed: true, }, "network_type": { Type: schema.TypeString, Computed: true, }, "vpc_cloud_instance_id": { Type: schema.TypeString, Computed: true, }, "replica_set_role": { Type: schema.TypeString, Computed: true, }, "connection_domain": { Type: schema.TypeString, Computed: true, }, "connection_port": { Type: schema.TypeString, Computed: true, }, "role_id": { Type: schema.TypeString, Computed: true, }, }, }, }, }, } } func resourceAliCloudMongoDBInstanceCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) ddsService := MongoDBService{client} var response map[string]interface{} action := "CreateDBInstance" request := make(map[string]interface{}) var err error request["RegionId"] = string(client.Region) request["ClientToken"] = buildClientToken(action) request["Engine"] = "MongoDB" request["EngineVersion"] = Trim(d.Get("engine_version").(string)) request["DBInstanceClass"] = Trim(d.Get("db_instance_class").(string)) request["DBInstanceStorage"] = d.Get("db_instance_storage") if v, ok := d.GetOk("storage_engine"); ok { request["StorageEngine"] = v } if v, ok := d.GetOk("storage_type"); ok { request["StorageType"] = v } if v, ok := d.GetOkExists("provisioned_iops"); ok { request["ProvisionedIops"] = v } if v, ok := d.GetOk("vpc_id"); ok { request["VpcId"] = v } if v, ok := d.GetOk("vswitch_id"); ok { request["VSwitchId"] = v } if v, ok := d.GetOk("zone_id"); ok { request["ZoneId"] = v } if (request["ZoneId"] == nil || request["VpcId"] == nil) && request["VSwitchId"] != nil { // check vswitchId in zone vpcService := VpcService{client} vsw, err := vpcService.DescribeVSwitchWithTeadsl(request["VSwitchId"].(string)) if err != nil { return WrapError(err) } if request["ZoneId"] == nil { request["ZoneId"] = vsw["ZoneId"] } else if strings.Contains(request["ZoneId"].(string), MULTI_IZ_SYMBOL) { zoneStr := strings.Split(strings.SplitAfter(request["ZoneId"].(string), "(")[1], ")")[0] if !strings.Contains(zoneStr, string([]byte(vsw["ZoneId"].(string))[len(vsw["ZoneId"].(string))-1])) { return WrapError(Error("The specified vswitch %s isn't in multi the zone %s", request["VSwitchId"].(string), request["ZoneId"].(string))) } } else if request["ZoneId"].(string) != vsw["ZoneId"] { return WrapError(Error("The specified vswitch %s isn't in the zone %s", request["VSwitchId"].(string), request["ZoneId"].(string))) } if request["VpcId"] == nil { request["VpcId"] = vsw["VpcId"] } } if v, ok := d.GetOk("secondary_zone_id"); ok { request["SecondaryZoneId"] = v } if v, ok := d.GetOk("hidden_zone_id"); ok { request["HiddenZoneId"] = v } if v, ok := d.GetOk("network_type"); ok { request["NetworkType"] = v } if request["NetworkType"] == nil && request["VSwitchId"] != nil { request["NetworkType"] = "VPC" } if v, ok := d.GetOk("name"); ok { request["DBInstanceDescription"] = v } if v, ok := d.GetOk("instance_charge_type"); ok { request["ChargeType"] = v if period, ok := d.GetOk("period"); ok && PayType(v.(string)) == PrePaid { request["Period"] = period } } request["SecurityIPList"] = LOCAL_HOST_IP if v, ok := d.GetOk("security_ip_list"); ok { request["SecurityIPList"] = strings.Join(expandStringList(v.(*schema.Set).List()), COMMA_SEPARATED) } if v, ok := d.GetOk("account_password"); ok { request["AccountPassword"] = v } else if v, ok := d.GetOk("kms_encrypted_password"); ok { kmsService := KmsService{client} decryptResp, err := kmsService.Decrypt(v.(string), d.Get("kms_encryption_context").(map[string]interface{})) if err != nil { return WrapError(err) } request["AccountPassword"] = decryptResp } if v, ok := d.GetOk("encrypted"); ok { request["Encrypted"] = v } if v, ok := d.GetOk("cloud_disk_encryption_key"); ok { request["EncryptionKey"] = v } if v, ok := d.GetOkExists("replication_factor"); ok { request["ReplicationFactor"] = strconv.Itoa(v.(int)) } if v, ok := d.GetOkExists("readonly_replicas"); ok { request["ReadonlyReplicas"] = v } if v, ok := d.GetOk("resource_group_id"); ok { request["ResourceGroupId"] = v } if v, ok := d.GetOkExists("auto_renew"); ok { request["AutoRenew"] = strconv.FormatBool(v.(bool)) } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutCreate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, request) if err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_mongodb_instance", action, AlibabaCloudSdkGoERROR) } d.SetId(fmt.Sprint(response["DBInstanceId"])) stateConf := BuildStateConf([]string{"Creating"}, []string{"Running"}, d.Timeout(schema.TimeoutCreate), 1*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } return resourceAliCloudMongoDBInstanceUpdate(d, meta) } func resourceAliCloudMongoDBInstanceRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) ddsService := MongoDBService{client} object, err := ddsService.DescribeMongoDBInstance(d.Id()) if err != nil { if !d.IsNewResource() && NotFoundError(err) { d.SetId("") return nil } return WrapError(err) } d.Set("engine_version", object["EngineVersion"]) d.Set("db_instance_class", object["DBInstanceClass"]) d.Set("db_instance_storage", object["DBInstanceStorage"]) d.Set("storage_engine", object["StorageEngine"]) d.Set("storage_type", convertMongoDBInstanceStorageTypeResponse(fmt.Sprint(object["StorageType"]))) d.Set("provisioned_iops", formatInt(object["ProvisionedIops"])) d.Set("vpc_id", object["VPCId"]) d.Set("vswitch_id", object["VSwitchId"]) d.Set("zone_id", object["ZoneId"]) d.Set("secondary_zone_id", object["SecondaryZoneId"]) d.Set("hidden_zone_id", object["HiddenZoneId"]) d.Set("network_type", object["NetworkType"]) d.Set("name", object["DBInstanceDescription"]) d.Set("instance_charge_type", object["ChargeType"]) d.Set("replication_factor", formatInt(object["ReplicationFactor"])) d.Set("readonly_replicas", formatInt(object["ReadonlyReplicas"])) d.Set("resource_group_id", object["ResourceGroupId"]) d.Set("maintain_start_time", object["MaintainStartTime"]) d.Set("maintain_end_time", object["MaintainEndTime"]) d.Set("replica_set_name", object["ReplicaSetName"]) if fmt.Sprint(object["ChargeType"]) == "PrePaid" { period, err := computePeriodByUnit(object["CreationTime"], object["ExpireTime"], d.Get("period").(int), "Month") if err != nil { return WrapError(err) } d.Set("period", period) } groupIp, err := ddsService.DescribeMongoDBSecurityGroupId(d.Id()) if err != nil { return WrapError(err) } if len(groupIp) > 0 { if groupIpItem, ok := groupIp[0].(map[string]interface{}); ok { d.Set("security_group_id", groupIpItem["SecurityGroupId"]) } } securityIpList, err := ddsService.DescribeMongoDBSecurityIps(d.Id()) if err != nil { return WrapError(err) } d.Set("security_ip_list", securityIpList) backupPolicy, err := ddsService.DescribeMongoDBBackupPolicy(d.Id()) if err != nil { return WrapError(err) } d.Set("backup_time", backupPolicy["PreferredBackupTime"]) if backupPeriod, ok := backupPolicy["PreferredBackupPeriod"]; ok && fmt.Sprint(backupPeriod) != "" { d.Set("backup_period", strings.Split(backupPeriod.(string), ",")) } d.Set("backup_retention_period", formatInt(backupPolicy["BackupRetentionPeriod"])) d.Set("backup_retention_policy_on_cluster_deletion", formatInt(backupPolicy["BackupRetentionPolicyOnClusterDeletion"])) d.Set("enable_backup_log", formatInt(backupPolicy["EnableBackupLog"])) d.Set("log_backup_retention_period", formatInt(backupPolicy["LogBackupRetentionPeriod"])) d.Set("snapshot_backup_type", backupPolicy["SnapshotBackupType"]) d.Set("backup_interval", backupPolicy["BackupInterval"]) d.Set("retention_period", formatInt(backupPolicy["BackupRetentionPeriod"])) // https://next.api.aliyun.com/api/Dds/2015-12-01/DescribeDBInstanceAttribute if object["KindCode"] == "0" || object["StorageType"] == "local_ssd" { tdeInfo, err := ddsService.DescribeMongoDBTDEInfo(d.Id()) if err != nil { return WrapError(err) } d.Set("tde_status", tdeInfo["TDEStatus"]) d.Set("encryptor_name", tdeInfo["EncryptorName"]) d.Set("encryption_key", tdeInfo["EncryptionKey"]) d.Set("role_arn", tdeInfo["RoleARN"]) } else { d.Set("encrypted", object["Encrypted"]) d.Set("cloud_disk_encryption_key", object["EncryptionKey"]) } sslAction, err := ddsService.DescribeDBInstanceSSL(d.Id()) if err != nil { if !IsExpectedErrors(err, []string{"StorageTypeOrInstanceTypeNotSupported", "SingleNodeNotSupport"}) { return WrapError(err) } } else { d.Set("ssl_status", sslAction["SSLStatus"]) } if v, ok := object["Tags"].(map[string]interface{}); ok { d.Set("tags", tagsToMap(v["Tag"])) } if err = ddsService.RefreshParameters(d, "parameters"); err != nil { return WrapError(err) } replicaSetsObjects, err := ddsService.DescribeReplicaSetRole(d.Id()) if err != nil { return WrapError(err) } replicaSets := transferToMongoReplicaSets(replicaSetsObjects, false) // connection domain -> replica allPrivateNetworkAddresses := lo.FilterSliceToMap(replicaSets, func(replica map[string]interface{}) (string, map[string]interface{}, bool) { if networkType, ok := replica["network_type"]; ok && networkType.(string) == "VPC" { if connectionDomain, ok := replica["connection_domain"]; ok { return connectionDomain.(string), replica, true } } return "", replica, false }) if replicaSetsMap, ok := object["ReplicaSets"].(map[string]interface{}); ok && replicaSetsMap != nil { if replicaSetsList, ok := replicaSetsMap["ReplicaSet"]; ok && replicaSetsList != nil { replicaSetsMaps := make([]map[string]interface{}, 0) for _, replicaSets := range replicaSetsList.([]interface{}) { replicaSetsArg := replicaSets.(map[string]interface{}) replicaSetsItemMap := make(map[string]interface{}) if vpcId, ok := replicaSetsArg["VPCId"]; ok { replicaSetsItemMap["vpc_id"] = vpcId } if vswitchId, ok := replicaSetsArg["VSwitchId"]; ok { replicaSetsItemMap["vswitch_id"] = vswitchId } if networkType, ok := replicaSetsArg["NetworkType"]; ok { replicaSetsItemMap["network_type"] = networkType } if vpcCloudInstanceId, ok := replicaSetsArg["VPCCloudInstanceId"]; ok { replicaSetsItemMap["vpc_cloud_instance_id"] = vpcCloudInstanceId } if replicaSetRole, ok := replicaSetsArg["ReplicaSetRole"]; ok { replicaSetsItemMap["replica_set_role"] = replicaSetRole } if connectionDomain, ok := replicaSetsArg["ConnectionDomain"]; ok { replicaSetsItemMap["connection_domain"] = connectionDomain if replica, ok := allPrivateNetworkAddresses[connectionDomain.(string)]; ok { if roleID, ok := replica["role_id"]; ok { replicaSetsItemMap["role_id"] = roleID } } } if connectionPort, ok := replicaSetsArg["ConnectionPort"]; ok { replicaSetsItemMap["connection_port"] = connectionPort } replicaSetsMaps = append(replicaSetsMaps, replicaSetsItemMap) } // make the output attributes more stable. sort.Slice(replicaSetsMaps, func(i, j int) bool { r1, ok := replicaSetsMaps[i]["role_id"] if !ok { return false } r2, ok := replicaSetsMaps[j]["role_id"] if !ok { return true } return strings.Compare(r1.(string), r2.(string)) >= 0 }) d.Set("replica_sets", replicaSetsMaps) } } return nil } func resourceAliCloudMongoDBInstanceUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) ddsService := MongoDBService{client} var response map[string]interface{} var err error d.Partial(true) update := false upgradeDBInstanceEngineVersionReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if !d.IsNewResource() && d.HasChange("engine_version") { update = true } upgradeDBInstanceEngineVersionReq["EngineVersion"] = d.Get("engine_version").(string) if update { action := "UpgradeDBInstanceEngineVersion" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, upgradeDBInstanceEngineVersionReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, upgradeDBInstanceEngineVersionReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 1*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("engine_version") } update = false modifyDBInstanceSpecReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if !d.IsNewResource() && d.HasChange("db_instance_class") { update = true } modifyDBInstanceSpecReq["DBInstanceClass"] = d.Get("db_instance_class").(string) if !d.IsNewResource() && d.HasChange("db_instance_storage") { update = true } modifyDBInstanceSpecReq["DBInstanceStorage"] = strconv.Itoa(d.Get("db_instance_storage").(int)) if !d.IsNewResource() && d.HasChange("replication_factor") { update = true } if v, ok := d.GetOkExists("replication_factor"); ok { modifyDBInstanceSpecReq["ReplicationFactor"] = strconv.Itoa(v.(int)) } if !d.IsNewResource() && d.HasChange("readonly_replicas") { update = true } if v, ok := d.GetOkExists("readonly_replicas"); ok { modifyDBInstanceSpecReq["ReadonlyReplicas"] = strconv.Itoa(v.(int)) } if v, ok := d.GetOk("effective_time"); ok { modifyDBInstanceSpecReq["EffectiveTime"] = v } if v, ok := d.GetOk("order_type"); ok { modifyDBInstanceSpecReq["OrderType"] = v.(string) } if update { action := "ModifyDBInstanceSpec" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceSpecReq, true) if err != nil { if IsExpectedErrors(err, []string{"Task.Conflict", "OperationDenied.DBInstanceStatus"}) || NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceSpecReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{"order_wait_for_produce"}, []string{"all_completed"}, d.Timeout(schema.TimeoutUpdate), 1*time.Minute, ddsService.RdsMongodbDBInstanceOrderStateRefreshFunc(d.Id(), []string{""})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } stateConf = BuildStateConf([]string{"DBInstanceClassChanging", "DBInstanceNetTypeChanging", "NodeCreating"}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 1*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("db_instance_class") d.SetPartial("db_instance_storage") d.SetPartial("replication_factor") d.SetPartial("readonly_replicas") } update = false modifyDBInstanceDiskTypeReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if !d.IsNewResource() && d.HasChange("storage_type") { update = true } if v, ok := d.GetOk("storage_type"); ok { modifyDBInstanceDiskTypeReq["DbInstanceStorageType"] = v } if !d.IsNewResource() && d.HasChange("provisioned_iops") { update = true if v, ok := d.GetOkExists("provisioned_iops"); ok { modifyDBInstanceDiskTypeReq["ProvisionedIops"] = v } } if update { action := "ModifyDBInstanceDiskType" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceDiskTypeReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceDiskTypeReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 1*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("storage_type") d.SetPartial("provisioned_iops") } update = false modifySecurityGroupConfigurationReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if d.HasChange("security_group_id") { update = true } if v, ok := d.GetOk("security_group_id"); ok { modifySecurityGroupConfigurationReq["SecurityGroupId"] = v.(string) } if update { action := "ModifySecurityGroupConfiguration" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifySecurityGroupConfigurationReq, true) if err != nil { if IsExpectedErrors(err, []string{"InstanceStatusInvalid", "OperationDenied.DBInstanceStatus"}) || NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifySecurityGroupConfigurationReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } d.SetPartial("security_group_id") } update = false modifyDBInstanceDescriptionReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if !d.IsNewResource() && d.HasChange("name") { update = true } if v, ok := d.GetOk("name"); ok { modifyDBInstanceDescriptionReq["DBInstanceDescription"] = v } if update { action := "ModifyDBInstanceDescription" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceDescriptionReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceDescriptionReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } d.SetPartial("name") } update = false modifyResourceGroupReq := map[string]interface{}{ "RegionId": client.RegionId, "DBInstanceId": d.Id(), } if !d.IsNewResource() && d.HasChange("resource_group_id") { update = true } if v, ok := d.GetOk("resource_group_id"); ok { modifyResourceGroupReq["ResourceGroupId"] = v } if update { stateConf := BuildStateConf([]string{}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } action := "ModifyResourceGroup" wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyResourceGroupReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyResourceGroupReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } d.SetPartial("resource_group_id") } if !d.IsNewResource() && (d.HasChange("instance_charge_type") && d.Get("instance_charge_type").(string) == "PrePaid") { action := "TransformToPrePaid" transformToPrePaidReq := map[string]interface{}{ "InstanceId": d.Id(), } transformToPrePaidReq["AutoPay"] = requests.NewBoolean(true) transformToPrePaidReq["Period"] = requests.NewInteger(d.Get("period").(int)) if v, ok := d.GetOkExists("auto_renew"); ok { transformToPrePaidReq["AutoRenew"] = strconv.FormatBool(v.(bool)) } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, transformToPrePaidReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, transformToPrePaidReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } // wait instance status is running after modifying stateConf := BuildStateConf([]string{"DBInstanceClassChanging", "DBInstanceNetTypeChanging"}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 0, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("instance_charge_type") d.SetPartial("period") } if !d.IsNewResource() && d.HasChange("security_ip_list") { ipList := expandStringList(d.Get("security_ip_list").(*schema.Set).List()) ipstr := strings.Join(ipList[:], COMMA_SEPARATED) // default disable connect from outside if ipstr == "" { ipstr = LOCAL_HOST_IP } if err := ddsService.ModifyMongoDBSecurityIps(d, ipstr); err != nil { return WrapError(err) } d.SetPartial("security_ip_list") } if !d.IsNewResource() && (d.HasChange("account_password") || d.HasChange("kms_encrypted_password")) { var accountPassword string if accountPassword = d.Get("account_password").(string); accountPassword != "" { d.SetPartial("account_password") } else if kmsPassword := d.Get("kms_encrypted_password").(string); kmsPassword != "" { kmsService := KmsService{meta.(*connectivity.AliyunClient)} decryptResp, err := kmsService.Decrypt(kmsPassword, d.Get("kms_encryption_context").(map[string]interface{})) if err != nil { return WrapError(err) } accountPassword = decryptResp d.SetPartial("kms_encrypted_password") d.SetPartial("kms_encryption_context") } err := ddsService.ResetAccountPassword(d, accountPassword, "instance") if err != nil { return WrapError(err) } } if d.HasChange("backup_time") || d.HasChange("backup_period") || d.HasChange("backup_retention_period") || d.HasChange("backup_retention_policy_on_cluster_deletion") || d.HasChange("enable_backup_log") || d.HasChange("log_backup_retention_period") || d.HasChange("snapshot_backup_type") || d.HasChange("backup_interval") { if err := ddsService.ModifyMongoDBBackupPolicy(d); err != nil { return WrapError(err) } d.SetPartial("backup_time") d.SetPartial("backup_period") d.SetPartial("backup_retention_period") d.SetPartial("backup_retention_policy_on_cluster_deletion") d.SetPartial("enable_backup_log") d.SetPartial("log_backup_retention_period") d.SetPartial("snapshot_backup_type") d.SetPartial("backup_interval") } if d.HasChange("ssl_action") { action := "ModifyDBInstanceSSL" modifyDBInstanceSSLReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if v, ok := d.GetOk("ssl_action"); ok { modifyDBInstanceSSLReq["SSLAction"] = v } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceSSLReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceSSLReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{"SSLModifying"}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 0, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("ssl_action") } if d.HasChange("maintain_start_time") || d.HasChange("maintain_end_time") { action := "ModifyDBInstanceMaintainTime" modifyDBInstanceMaintainTimeReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if v, ok := d.GetOk("maintain_start_time"); ok { modifyDBInstanceMaintainTimeReq["MaintainStartTime"] = v } if v, ok := d.GetOk("maintain_end_time"); ok { modifyDBInstanceMaintainTimeReq["MaintainEndTime"] = v } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceMaintainTimeReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceMaintainTimeReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } d.SetPartial("maintain_start_time") d.SetPartial("maintain_end_time") } if d.HasChange("tde_status") || d.HasChange("encryptor_name") || d.HasChange("encryption_key") { action := "ModifyDBInstanceTDE" modifyDBInstanceTDEReq := map[string]interface{}{ "DBInstanceId": d.Id(), } if d.HasChange("tde_status") { if v, ok := d.GetOk("tde_status"); ok { modifyDBInstanceTDEReq["TDEStatus"] = v } } if d.HasChange("encryptor_name") { if v, ok := d.GetOk("encryptor_name"); ok { modifyDBInstanceTDEReq["EncryptorName"] = v } } if d.HasChange("encryption_key") { if v, ok := d.GetOk("encryption_key"); ok { modifyDBInstanceTDEReq["EncryptionKey"] = v } } if d.HasChange("role_arn") { if v, ok := d.GetOk("role_arn"); ok { modifyDBInstanceTDEReq["RoleARN"] = v } } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutUpdate)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, modifyDBInstanceTDEReq, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, modifyDBInstanceTDEReq) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 5*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("tde_status") d.SetPartial("encryptor_name") d.SetPartial("encryption_key") } if err := ddsService.setInstanceTags(d); err != nil { return WrapError(err) } if d.HasChange("parameters") { if err := ddsService.ModifyParameters(d, "parameters"); err != nil { return WrapError(err) } } d.Partial(false) return resourceAliCloudMongoDBInstanceRead(d, meta) } func resourceAliCloudMongoDBInstanceDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) ddsService := MongoDBService{client} action := "DeleteDBInstance" var response map[string]interface{} var err error object, err := ddsService.DescribeMongoDBInstance(d.Id()) if err != nil { return WrapError(err) } if fmt.Sprint(object["ChargeType"]) == "PrePaid" { log.Printf("[WARN] Cannot destroy resourceAliCloudMongoDBInstance prepay type. Terraform will remove this resource from the state file, however resources may remain.") return nil } request := map[string]interface{}{ "DBInstanceId": d.Id(), } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(client.GetRetryTimeout(d.Timeout(schema.TimeoutDelete)), func() *resource.RetryError { response, err = client.RpcPost("Dds", "2015-12-01", action, nil, request, true) if err != nil { if NeedRetry(err) || IsExpectedErrors(err, []string{"OperationDenied.DBInstanceStatus"}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) addDebug(action, response, request) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) || NotFoundError(err) { return nil } return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } stateConf := BuildStateConf([]string{"Creating", "Deleting"}, []string{}, d.Timeout(schema.TimeoutDelete), 1*time.Minute, ddsService.RdsMongodbDBInstanceStateRefreshFunc(d.Id(), []string{})) if _, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, IdMsg, d.Id()) } return nil } func convertMongoDBInstanceStorageTypeResponse(source string) string { switch source { case "cloud_essd": return "cloud_essd1" } return source }