alicloud/service_alicloud_rds.go (2,484 lines of code) (raw):

package alicloud import ( "encoding/json" "fmt" "log" "regexp" "strconv" "strings" "time" "github.com/PaesslerAG/jsonpath" util "github.com/alibabacloud-go/tea-utils/service" "github.com/aliyun/alibaba-cloud-sdk-go/services/ram" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/denverdino/aliyungo/common" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) type RdsService struct { client *connectivity.AliyunClient } // _______________ _______________ _______________ // | | ______param______\ | | _____request_____\ | | // | Business | | Service | | SDK/API | // | | __________________ | | __________________ | | // |______________| \ (obj, err) |______________| \ (status, cont) |______________| // | | // |A. {instance, nil} |a. {200, content} // |B. {nil, error} |b. {200, nil} // |c. {4xx, nil} // // The API return 200 for resource not found. // When getInstance is empty, then throw InstanceNotfound error. // That the business layer only need to check error. var DBInstanceStatusCatcher = Catcher{"OperationDenied.DBInstanceStatus", 60, 5} func (s *RdsService) DescribeDBInstance(id string) (object map[string]interface{}, err error) { client := s.client action := "DescribeDBInstanceAttribute" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) || IsExpectedErrors(err, []string{"InvalidParameter"}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound", "InvalidDBInstanceName.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items.DBInstanceAttribute", response) if err != nil { return nil, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items.DBInstanceAttribute", response) } if len(v.([]interface{})) < 1 { return nil, WrapErrorf(NotFoundErr("DBAccount", id), NotFoundMsg, ProviderERROR) } return v.([]interface{})[0].(map[string]interface{}), nil } func (s *RdsService) DescribeTasks(id string) (object map[string]interface{}, err error) { action := "DescribeTasks" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, ProviderERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) DescribeDBReadonlyInstance(id string) (object map[string]interface{}, err error) { action := "DescribeDBInstanceAttribute" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) dBInstanceAttributes := response["Items"].(map[string]interface{})["DBInstanceAttribute"].([]interface{}) if len(dBInstanceAttributes) < 1 { return nil, WrapErrorf(NotFoundErr("DBInstance", id), NotFoundMsg, ProviderERROR) } return dBInstanceAttributes[0].(map[string]interface{}), nil } func (s *RdsService) DescribeDBAccountPrivilege(id string) (object map[string]interface{}, err error) { var ds map[string]interface{} parts, err := ParseResourceId(id, 3) if err != nil { return ds, WrapError(err) } action := "DescribeAccounts" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": parts[0], "AccountName": parts[1], "SourceIp": s.client.SourceIp, } client := s.client invoker := NewInvoker() invoker.AddCatcher(DBInstanceStatusCatcher) var response map[string]interface{} if err := invoker.Run(func() error { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { return WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return nil }); err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return ds, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return ds, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } dBInstanceAccounts := response["Accounts"].(map[string]interface{})["DBInstanceAccount"].([]interface{}) if len(dBInstanceAccounts) < 1 { return ds, WrapErrorf(NotFoundErr("DBAccountPrivilege", id), NotFoundMsg, ProviderERROR) } return dBInstanceAccounts[0].(map[string]interface{}), nil } func (s *RdsService) DescribeDBDatabase(id string) (object map[string]interface{}, err error) { var ds map[string]interface{} parts, err := ParseResourceId(id, 2) if err != nil { return ds, WrapError(err) } dbName := parts[1] var response map[string]interface{} action := "DescribeDatabases" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": parts[0], "DBName": dbName, "SourceIp": s.client.SourceIp, } client := s.client err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InternalError", "OperationDenied.DBInstanceStatus"}) { return resource.RetryableError(WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)) } if NotFoundError(err) || IsExpectedErrors(err, []string{"InvalidDBName.NotFound", "InvalidDBInstanceId.NotFoundError"}) { return resource.NonRetryableError(WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)) } return resource.NonRetryableError(WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)) } addDebug(action, response, request) v, err := jsonpath.Get("$.Databases.Database", response) if err != nil { return resource.NonRetryableError(WrapErrorf(err, FailedGetAttributeMsg, id, "$.Databases.Database", response)) } if len(v.([]interface{})) < 1 { return resource.NonRetryableError(WrapErrorf(NotFoundErr("DBDatabase", dbName), NotFoundMsg, ProviderERROR)) } ds = v.([]interface{})[0].(map[string]interface{}) return nil }) return ds, err } func (s *RdsService) DescribeParameters(id string) (object map[string]interface{}, err error) { client := s.client action := "DescribeParameters" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } runtime := util.RuntimeOptions{} runtime.SetAutoretry(true) response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, err } func (s *RdsService) SetTimeZone(d *schema.ResourceData) error { targetParameterName := "" engine := d.Get("engine") if engine == string(MySQL) { targetParameterName = "default_time_zone" } else if engine == string(PostgreSQL) { targetParameterName = "timezone" } if targetParameterName != "" { paramsRes, err := s.DescribeParameters(d.Id()) if err != nil { return WrapError(err) } parameters := paramsRes["RunningParameters"].(map[string]interface{})["DBInstanceParameter"].([]interface{}) for _, item := range parameters { item := item.(map[string]interface{}) parameterName := item["ParameterName"] if parameterName == targetParameterName { d.Set("db_time_zone", item["ParameterValue"]) break } } } return nil } func (s *RdsService) RefreshParameters(d *schema.ResourceData, attribute string) error { var param []map[string]interface{} documented, ok := d.GetOk(attribute) if !ok { return nil } object, err := s.DescribeParameters(d.Id()) if err != nil { return WrapError(err) } var parameters = make(map[string]interface{}) dBInstanceParameters := object["RunningParameters"].(map[string]interface{})["DBInstanceParameter"].([]interface{}) for _, i := range dBInstanceParameters { i := i.(map[string]interface{}) if i["ParameterName"] != "" { parameter := map[string]interface{}{ "name": i["ParameterName"], "value": i["ParameterValue"], } parameters[i["ParameterName"].(string)] = parameter } } dBInstanceParameters = object["ConfigParameters"].(map[string]interface{})["DBInstanceParameter"].([]interface{}) for _, i := range dBInstanceParameters { i := i.(map[string]interface{}) if i["ParameterName"] != "" { parameter := map[string]interface{}{ "name": i["ParameterName"], "value": i["ParameterValue"], } parameters[i["ParameterName"].(string)] = parameter } } for _, parameter := range documented.(*schema.Set).List() { name := parameter.(map[string]interface{})["name"] for _, value := range parameters { if value.(map[string]interface{})["name"] == name { param = append(param, value.(map[string]interface{})) break } } } if len(param) > 0 { if err := d.Set(attribute, param); err != nil { return WrapError(err) } } return nil } func (s *RdsService) RefreshPgHbaConf(d *schema.ResourceData, attribute string) error { response, err := s.DescribePGHbaConfig(d.Id()) if err != nil { return WrapError(err) } runningHbaItems := make([]interface{}, 0) if v, exist := response["RunningHbaItems"].(map[string]interface{})["HbaItem"]; exist { runningHbaItems = v.([]interface{}) } var items []map[string]interface{} documented, ok := d.GetOk(attribute) if !ok { return nil } for _, item := range documented.(*schema.Set).List() { item := item.(map[string]interface{}) for _, item2 := range runningHbaItems { item2 := item2.(map[string]interface{}) if item["priority_id"] == formatInt(item2["PriorityId"]) { mapping := map[string]interface{}{ "type": item2["Type"], "database": item2["Database"], "priority_id": formatInt(item2["PriorityId"]), "address": item2["Address"], "user": item2["User"], "method": item2["Method"], "option": item2["Option"], "mask": item2["Mask"], } if item2["mask"] != nil && item2["mask"] != "" { mapping["mask"] = item2["mask"] } if item2["option"] != nil && item2["option"] != "" { mapping["option"] = item2["option"] } items = append(items, mapping) } } } if len(items) > 0 { if err := d.Set(attribute, items); err != nil { return WrapError(err) } } return nil } func (s *RdsService) ModifyPgHbaConfig(d *schema.ResourceData, attribute string) error { client := s.client var err error action := "ModifyPGHbaConfig" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "SourceIp": s.client.SourceIp, } request["OpsType"] = "update" pgHbaConfig := d.Get("pg_hba_conf") count := 1 for _, i := range pgHbaConfig.(*schema.Set).List() { i := i.(map[string]interface{}) request[fmt.Sprint("HbaItem.", count, ".Type")] = i["type"] if i["mask"] != nil && i["mask"] != "" { request[fmt.Sprint("HbaItem.", count, ".Mask")] = i["mask"] } request[fmt.Sprint("HbaItem.", count, ".Database")] = i["database"] request[fmt.Sprint("HbaItem.", count, ".PriorityId")] = i["priority_id"] request[fmt.Sprint("HbaItem.", count, ".Address")] = i["address"] request[fmt.Sprint("HbaItem.", count, ".User")] = i["user"] request[fmt.Sprint("HbaItem.", count, ".Method")] = i["method"] if i["option"] != nil && i["mask"] != "" { request[fmt.Sprint("HbaItem.", count, ".Option")] = i["option"] } count = count + 1 } var response map[string]interface{} err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if IsExpectedErrors(err, []string{"InternalError"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapError(err) } if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } desResponse, err := s.DescribePGHbaConfig(d.Id()) if err != nil { return WrapError(err) } if desResponse["LastModifyStatus"] == "failed" { return WrapError(Error("%v", desResponse["ModifyStatusReason"].(string))) } d.SetPartial(attribute) return nil } func (s *RdsService) ModifyDBInstanceDeletionProtection(d *schema.ResourceData, attribute string) error { client := s.client var err error action := "ModifyDBInstanceDeletionProtection" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "SourceIp": s.client.SourceIp, } request["DeletionProtection"] = d.Get("deletion_protection") var response map[string]interface{} err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if IsExpectedErrors(err, []string{"InternalError"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapError(err) } if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } d.SetPartial(attribute) return nil } func (s *RdsService) ModifyHADiagnoseConfig(d *schema.ResourceData, attribute string) error { client := s.client action := "ModifyHADiagnoseConfig" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "SourceIp": s.client.SourceIp, } request["TcpConnectionType"] = d.Get("tcp_connection_type") var response map[string]interface{} var err error err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if IsExpectedErrors(err, []string{"InternalError"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapError(err) } if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } d.SetPartial(attribute) return nil } func (s *RdsService) ModifyParameters(d *schema.ResourceData, attribute string) error { client := s.client action := "ModifyParameter" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "Forcerestart": d.Get("force_restart"), "SourceIp": s.client.SourceIp, } config := make(map[string]string) allConfig := make(map[string]string) o, n := d.GetChange(attribute) os, ns := o.(*schema.Set), n.(*schema.Set) add := ns.Difference(os).List() if len(add) > 0 { for _, i := range add { key := i.(map[string]interface{})["name"].(string) value := i.(map[string]interface{})["value"].(string) config[key] = value } cfg, _ := json.Marshal(config) request["Parameters"] = string(cfg) // wait instance status is Normal before modifying if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } // Need to check whether some parameter needs restart if !d.Get("force_restart").(bool) { action := "DescribeParameterTemplates" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "Engine": d.Get("engine"), "EngineVersion": d.Get("engine_version"), "ClientToken": buildClientToken(action), "SourceIp": s.client.SourceIp, } forceRestartMap := make(map[string]string) response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) stateConf := BuildStateConf([]string{}, []string{"Running"}, d.Timeout(schema.TimeoutUpdate), 3*time.Minute, s.RdsDBInstanceStateRefreshFunc(d.Id(), []string{"Deleting"})) if _, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, IdMsg, d.Id()) } templateRecords := response["Parameters"].(map[string]interface{})["TemplateRecord"].([]interface{}) for _, para := range templateRecords { para := para.(map[string]interface{}) if para["ForceRestart"] == "true" { forceRestartMap[para["ParameterName"].(string)] = para["ForceRestart"].(string) } } if len(forceRestartMap) > 0 { for key := range config { if _, ok := forceRestartMap[key]; ok { return WrapError(fmt.Errorf("Modifying RDS instance's parameter '%s' requires setting 'force_restart = true'.", key)) } } } } response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) // wait instance parameter expect after modifying for _, i := range ns.List() { key := i.(map[string]interface{})["name"].(string) value := i.(map[string]interface{})["value"].(string) allConfig[key] = value } if err := s.WaitForDBParameter(d.Id(), DefaultLongTimeout, allConfig); err != nil { return WrapError(err) } // wait instance status is Normal after modifying if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } } d.SetPartial(attribute) return nil } func (s *RdsService) DescribeDBInstanceRwNetInfoByMssql(id string) ([]interface{}, error) { action := "DescribeDBInstanceNetInfo" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, "DBInstanceNetRWSplitType": "ReadWriteSplitting", } client := s.client var response map[string]interface{} var err error err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InternalError"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } } return response["DBInstanceNetInfos"].(map[string]interface{})["DBInstanceNetInfo"].([]interface{}), nil } func (s *RdsService) DescribeDBInstanceNetInfo(id string) ([]interface{}, error) { action := "DescribeDBInstanceNetInfo" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} var err error err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InternalError"}) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } } return response["DBInstanceNetInfos"].(map[string]interface{})["DBInstanceNetInfo"].([]interface{}), nil } func (s *RdsService) DescribeDBConnection(id string) (map[string]interface{}, error) { parts, err := ParseResourceId(id, 2) if err != nil { return nil, WrapError(err) } object, err := s.DescribeDBInstanceNetInfo(parts[0]) if err != nil { if IsExpectedErrors(err, []string{"InvalidCurrentConnectionString.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapError(err) } if object != nil { for _, o := range object { o := o.(map[string]interface{}) if strings.HasPrefix(o["ConnectionString"].(string), parts[1]) { return o, nil } } } return nil, WrapErrorf(NotFoundErr("DBConnection", id), NotFoundMsg, ProviderERROR) } func (s *RdsService) DescribeDBReadWriteSplittingConnection(id string) (map[string]interface{}, error) { object, err := s.DescribeDBInstanceRwNetInfoByMssql(id) if err != nil && !NotFoundError(err) { return nil, err } if object != nil { for _, conn := range object { conn := conn.(map[string]interface{}) if conn["ConnectionStringType"] != "ReadWriteSplitting" { continue } if _, ok := conn["MaxDelayTime"]; ok { if conn["MaxDelayTime"] == nil { continue } if _, err := strconv.Atoi(conn["MaxDelayTime"].(string)); err != nil { return nil, err } } return conn, nil } } return nil, WrapErrorf(NotFoundErr("ReadWriteSplittingConnection", id), NotFoundMsg, ProviderERROR) } func (s *RdsService) GrantAccountPrivilege(id, dbName string) error { parts, err := ParseResourceId(id, 3) if err != nil { return WrapError(err) } action := "GrantAccountPrivilege" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": parts[0], "AccountName": parts[1], "DBName": dbName, "AccountPrivilege": parts[2], "SourceIp": s.client.SourceIp, } var response map[string]interface{} client := s.client err = resource.Retry(3*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if IsExpectedErrors(err, OperationDeniedDBStatus) || IsExpectedErrors(err, []string{"InvalidDB.NotFound"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } if err := s.WaitForAccountPrivilege(id, dbName, Available, DefaultTimeoutMedium); err != nil { return WrapError(err) } return nil } func (s *RdsService) RevokeAccountPrivilege(id, dbName string) error { parts, err := ParseResourceId(id, 3) if err != nil { return WrapError(err) } action := "RevokeAccountPrivilege" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": parts[0], "AccountName": parts[1], "DBName": dbName, "SourceIp": s.client.SourceIp, } client := s.client err = resource.Retry(3*time.Minute, func() *resource.RetryError { response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if IsExpectedErrors(err, OperationDeniedDBStatus) || NeedRetry(err) { return resource.RetryableError(err) } else if IsExpectedErrors(err, []string{"InvalidDB.NotFound"}) { log.Printf("[WARN] Resource alicloud_db_account_privilege RevokeAccountPrivilege Failed!!! %s", err) return nil } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } if err := s.WaitForAccountPrivilegeRevoked(id, dbName, DefaultTimeoutMedium); err != nil { return WrapError(err) } return nil } func (s *RdsService) ReleaseDBPublicConnection(instanceId, connection string) error { action := "ReleaseInstancePublicConnection" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": instanceId, "CurrentConnectionString": connection, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, instanceId, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return nil } func (s *RdsService) ModifyDBBackupPolicy(d *schema.ResourceData, updateForData, updateForLog bool) error { enableBackupLog := "1" backupPeriod := "" if v, ok := d.GetOk("preferred_backup_period"); ok && v.(*schema.Set).Len() > 0 { periodList := expandStringList(v.(*schema.Set).List()) backupPeriod = fmt.Sprintf("%s", strings.Join(periodList[:], COMMA_SEPARATED)) } else { periodList := expandStringList(d.Get("backup_period").(*schema.Set).List()) backupPeriod = fmt.Sprintf("%s", strings.Join(periodList[:], COMMA_SEPARATED)) } backupTime := "02:00Z-03:00Z" if v, ok := d.GetOk("preferred_backup_time"); ok && v.(string) != "02:00Z-03:00Z" { backupTime = v.(string) } else if v, ok := d.GetOk("backup_time"); ok && v.(string) != "" { backupTime = v.(string) } retentionPeriod := "7" if v, ok := d.GetOk("backup_retention_period"); ok && v.(int) != 7 { retentionPeriod = strconv.Itoa(v.(int)) } else if v, ok := d.GetOk("retention_period"); ok && v.(int) != 0 { retentionPeriod = strconv.Itoa(v.(int)) } logBackupRetentionPeriod := "" if v, ok := d.GetOk("log_backup_retention_period"); ok && v.(int) != 0 { logBackupRetentionPeriod = strconv.Itoa(v.(int)) } else if v, ok := d.GetOk("log_retention_period"); ok && v.(int) != 0 { logBackupRetentionPeriod = strconv.Itoa(v.(int)) } localLogRetentionHours := "" if v, ok := d.GetOk("local_log_retention_hours"); ok { localLogRetentionHours = strconv.Itoa(v.(int)) } localLogRetentionSpace := "" if v, ok := d.GetOk("local_log_retention_space"); ok { localLogRetentionSpace = strconv.Itoa(v.(int)) } highSpaceUsageProtection := d.Get("high_space_usage_protection").(string) if !d.Get("enable_backup_log").(bool) { enableBackupLog = "0" } if d.HasChange("log_backup_retention_period") { if d.Get("log_backup_retention_period").(int) > d.Get("backup_retention_period").(int) { logBackupRetentionPeriod = retentionPeriod } } logBackupFrequency := "" if v, ok := d.GetOk("log_backup_frequency"); ok { logBackupFrequency = v.(string) } compressType := "" if v, ok := d.GetOk("compress_type"); ok { compressType = v.(string) } archiveBackupRetentionPeriod := "0" if v, ok := d.GetOk("archive_backup_retention_period"); ok { archiveBackupRetentionPeriod = strconv.Itoa(v.(int)) } archiveBackupKeepCount := "1" if v, ok := d.GetOk("archive_backup_keep_count"); ok { archiveBackupKeepCount = strconv.Itoa(v.(int)) } archiveBackupKeepPolicy := "0" if v, ok := d.GetOk("archive_backup_keep_policy"); ok { archiveBackupKeepPolicy = v.(string) } releasedKeepPolicy := "" if v, ok := d.GetOk("released_keep_policy"); ok { releasedKeepPolicy = v.(string) } category := "" if v, ok := d.GetOk("category"); ok { category = v.(string) } backupInterval := "-1" if v, ok := d.GetOk("backup_interval"); ok { backupInterval = v.(string) } enableIncrementDataBackup := false if v, ok := d.GetOkExists("enable_increment_data_backup"); ok { enableIncrementDataBackup = v.(bool) } backupMethod := "Physical" if v, ok := d.GetOk("backup_method"); ok { backupMethod = v.(string) } logBackupLocalRetentionNumber := 60 if v, ok := d.GetOk("log_backup_local_retention_number"); ok { logBackupLocalRetentionNumber = v.(int) } runtime := util.RuntimeOptions{} runtime.SetAutoretry(true) instance, err := s.DescribeDBInstance(d.Id()) if err != nil { return WrapError(err) } if updateForData { client := s.client action := "ModifyBackupPolicy" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "PreferredBackupPeriod": backupPeriod, "PreferredBackupTime": backupTime, "BackupRetentionPeriod": retentionPeriod, "CompressType": compressType, "BackupPolicyMode": "DataBackupPolicy", "SourceIp": s.client.SourceIp, "ReleasedKeepPolicy": releasedKeepPolicy, "Category": category, } if instance["Engine"] == "SQLServer" && instance["Category"] == "AlwaysOn" { if v, ok := d.GetOk("backup_priority"); ok { request["BackupPriority"] = v.(int) } } if instance["Engine"] == "SQLServer" && instance["DBInstanceStorageType"] != "local_ssd" { request["EnableIncrementDataBackup"] = enableIncrementDataBackup request["BackupMethod"] = backupMethod } if instance["Engine"] == "SQLServer" && logBackupFrequency == "LogInterval" { request["LogBackupFrequency"] = logBackupFrequency } if instance["Engine"] == "MySQL" && instance["DBInstanceStorageType"] == "local_ssd" { request["ArchiveBackupRetentionPeriod"] = archiveBackupRetentionPeriod request["ArchiveBackupKeepCount"] = archiveBackupKeepCount request["ArchiveBackupKeepPolicy"] = archiveBackupKeepPolicy } if (instance["Engine"] == "MySQL" || instance["Engine"] == "PostgreSQL") && instance["DBInstanceStorageType"] != "local_ssd" { request["BackupInterval"] = backupInterval } response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) if err := s.WaitForDBInstance(d.Id(), Running, DefaultTimeoutMedium); err != nil { return WrapError(err) } } // At present, the sql server database does not support setting logBackupRetentionPeriod if updateForLog && instance["Engine"] != "SQLServer" { client := s.client action := "ModifyBackupPolicy" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": d.Id(), "EnableBackupLog": enableBackupLog, "LocalLogRetentionHours": localLogRetentionHours, "LocalLogRetentionSpace": localLogRetentionSpace, "HighSpaceUsageProtection": highSpaceUsageProtection, "BackupPolicyMode": "LogBackupPolicy", "LogBackupRetentionPeriod": logBackupRetentionPeriod, "LogBackupLocalRetentionNumber": logBackupLocalRetentionNumber, "SourceIp": s.client.SourceIp, } response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) if err := s.WaitForDBInstance(d.Id(), Running, DefaultTimeoutMedium); err != nil { return WrapError(err) } } return nil } func (s *RdsService) ModifyDBSecurityIps(instanceId, ips string) error { client := s.client action := "ModifySecurityIps" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": instanceId, "SecurityIps": ips, "SourceIp": s.client.SourceIp, } response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { return WrapErrorf(err, DefaultErrorMsg, instanceId, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) if err := s.WaitForDBInstance(instanceId, Running, DefaultTimeoutMedium); err != nil { return WrapError(err) } return nil } func (s *RdsService) DescribeDBSecurityIps(instanceId string) ([]interface{}, error) { action := "DescribeDBInstanceIPArrayList" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": instanceId, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} var err error wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, instanceId, action, AlibabaCloudSdkGoERROR) } return response["Items"].(map[string]interface{})["DBInstanceIPArray"].([]interface{}), nil } func (s *RdsService) DescribeParameterTemplates(instanceId, engine, engineVersion string) ([]interface{}, error) { action := "DescribeParameterTemplates" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": instanceId, "Engine": engine, "EngineVersion": engineVersion, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, instanceId, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response["Parameters"].(map[string]interface{})["TemplateRecord"].([]interface{}), nil } func (s *RdsService) GetSecurityIps(instanceId string, dbInstanceIpArrayName string) ([]string, error) { object, err := s.DescribeDBSecurityIps(instanceId) if err != nil { return nil, WrapError(err) } var ips, separator string ipsMap := make(map[string]string) for _, ip := range object { ip := ip.(map[string]interface{}) if ip["DBInstanceIPArrayName"].(string) == dbInstanceIpArrayName { ips += separator + ip["SecurityIPList"].(string) separator = COMMA_SEPARATED } } for _, ip := range strings.Split(ips, COMMA_SEPARATED) { ipsMap[ip] = ip } var finalIps []string if len(ipsMap) > 0 { for key := range ipsMap { finalIps = append(finalIps, key) } } return finalIps, nil } func (s *RdsService) DescribeSecurityGroupConfiguration(id string) ([]string, error) { action := "DescribeSecurityGroupConfiguration" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} var err error wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } groupIds := make([]string, 0) ecsSecurityGroupRelations := response["Items"].(map[string]interface{})["EcsSecurityGroupRelation"].([]interface{}) for _, v := range ecsSecurityGroupRelations { v := v.(map[string]interface{}) groupIds = append(groupIds, v["SecurityGroupId"].(string)) } return groupIds, nil } func (s *RdsService) DescribeDBInstanceSSL(id string) (object map[string]interface{}, err error) { action := "DescribeDBInstanceSSL" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return response, nil } func (s *RdsService) DescribeDBInstanceEncryptionKey(id string) (object map[string]interface{}, err error) { action := "DescribeDBInstanceEncryptionKey" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) DescribeHASwitchConfig(id string) (object map[string]interface{}, err error) { action := "DescribeHASwitchConfig" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return response, nil } func (s *RdsService) DescribeRdsTDEInfo(id string) (object map[string]interface{}, err error) { action := "DescribeDBInstanceTDE" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } statErr := s.WaitForDBInstance(id, Running, DefaultLongTimeout) if statErr != nil { return nil, WrapError(statErr) } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return response, nil } func (s *RdsService) ModifySecurityGroupConfiguration(id string, groupid string) error { client := s.client action := "ModifySecurityGroupConfiguration" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } //openapi required that input "Empty" if groupid is "" if len(groupid) == 0 { groupid = "Empty" } request["SecurityGroupId"] = groupid var response map[string]interface{} var err error wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if NeedRetry(err) || IsExpectedErrors(err, []string{"ServiceUnavailable"}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return nil } // return multiIZ list of current region func (s *RdsService) DescribeMultiIZByRegion() (izs []string, err error) { action := "DescribeRegions" request := map[string]interface{}{ "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, "MultiIZByRegion", action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) regions := response["Regions"].(map[string]interface{})["RDSRegion"].([]interface{}) zoneIds := []string{} for _, r := range regions { r := r.(map[string]interface{}) if r["RegionId"] == string(s.client.Region) && strings.Contains(r["ZoneId"].(string), MULTI_IZ_SYMBOL) { zoneIds = append(zoneIds, r["ZoneId"].(string)) } } return zoneIds, nil } func (s *RdsService) DescribeBackupPolicy(id string) (object map[string]interface{}, err error) { action := "DescribeBackupPolicy" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) DescribeDbInstanceMonitor(id string) (monitoringPeriod int, err error) { action := "DescribeDBInstanceMonitor" request := map[string]interface{}{ "DBInstanceId": id, "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) monPeriod, err := strconv.Atoi(response["Period"].(string)) if err != nil { return 0, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return monPeriod, nil } func (s *RdsService) DescribeSQLCollectorPolicy(id string) (object map[string]interface{}, err error) { action := "DescribeSQLCollectorPolicy" request := map[string]interface{}{ "DBInstanceId": id, "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return response, nil } func (s *RdsService) DescribeSQLCollectorRetention(id string) (object map[string]interface{}, err error) { action := "DescribeSQLCollectorRetention" request := map[string]interface{}{ "DBInstanceId": id, "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } return response, nil } // WaitForInstance waits for instance to given status func (s *RdsService) WaitForDBInstance(id string, status Status, timeout int) error { deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBInstance(id) if err != nil { if NotFoundError(err) { if status == Deleted { return nil } } else { return WrapError(err) } } if object != nil && strings.ToLower(fmt.Sprint(object["DBInstanceStatus"])) == strings.ToLower(string(status)) { break } time.Sleep(DefaultIntervalShort * time.Second) if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object["DBInstanceStatus"], status, ProviderERROR) } } return nil } func (s *RdsService) RdsDBInstanceStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeDBInstance(id) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } for _, failState := range failStates { if object["DBInstanceStatus"] == failState { return object, fmt.Sprint(object["DBInstanceStatus"]), WrapError(Error(FailedToReachTargetStatus, object["DBInstanceStatus"])) } } return object, fmt.Sprint(object["DBInstanceStatus"]), nil } } func (s *RdsService) RdsDBInstanceNodeIdRefreshFunc(id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { describeDBInstanceHAConfigObject, err := s.DescribeDBInstanceHAConfig(id) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } hostInstanceInfos := describeDBInstanceHAConfigObject["HostInstanceInfos"].(map[string]interface{})["NodeInfo"].([]interface{}) var nodeId string for _, val := range hostInstanceInfos { item := val.(map[string]interface{}) nodeType := item["NodeType"].(string) if nodeType == "Master" { nodeId = item["NodeId"].(string) break // 停止遍历 } } return describeDBInstanceHAConfigObject, fmt.Sprint(nodeId), nil } } func (s *RdsService) RdsTaskStateRefreshFunc(id string, taskAction string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeTasks(id) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } taskProgressInfos := object["Items"].(map[string]interface{})["TaskProgressInfo"].([]interface{}) for _, t := range taskProgressInfos { t := t.(map[string]interface{}) if t["TaskAction"] == taskAction { return object, t["Status"].(string), nil } } return object, "Pending", nil } } // WaitForDBParameter waits for instance parameter to given value. // Status of DB instance is Running after ModifyParameters API was // call, so we can not just wait for instance status become // Running, we should wait until parameters have expected values. func (s *RdsService) WaitForDBParameter(instanceId string, timeout int, expects map[string]string) error { deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeParameters(instanceId) if err != nil { return WrapError(err) } var actuals = make(map[string]string) dBInstanceParameters := object["RunningParameters"].(map[string]interface{})["DBInstanceParameter"].([]interface{}) for _, i := range dBInstanceParameters { i := i.(map[string]interface{}) if i["ParameterName"] == nil || i["ParameterValue"] == nil { continue } actuals[i["ParameterName"].(string)] = i["ParameterValue"].(string) } dBInstanceParameters = object["ConfigParameters"].(map[string]interface{})["DBInstanceParameter"].([]interface{}) for _, i := range dBInstanceParameters { i := i.(map[string]interface{}) if i["ParameterName"] == nil || i["ParameterValue"] == nil { continue } actuals[i["ParameterName"].(string)] = i["ParameterValue"].(string) } match := true got_value := "" expected_value := "" for name, expect := range expects { if actual, ok := actuals[name]; ok { if expect != actual { match = false got_value = actual expected_value = expect break } } else { match = false } } if match { break } time.Sleep(DefaultIntervalShort * time.Second) if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, instanceId, GetFunc(1), timeout, got_value, expected_value, ProviderERROR) } } return nil } func (s *RdsService) WaitForDBConnection(id string, status Status, timeout int) error { deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBConnection(id) if err != nil { if NotFoundError(err) { if status == Deleted { return nil } } else { return WrapError(err) } } if object != nil && object["ConnectionString"] != "" { return nil } if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object["ConnectionString"], id, ProviderERROR) } } } func (s *RdsService) WaitForDBReadWriteSplitting(id string, status Status, timeout int) error { deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBReadWriteSplittingConnection(id) if err != nil { if NotFoundError(err) { if status == Deleted { return nil } } else { return WrapError(err) } } if err == nil { break } time.Sleep(DefaultIntervalShort * time.Second) if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object["ConnectionString"], id, ProviderERROR) } } return nil } func (s *RdsService) WaitForAccountPrivilege(id, dbName string, status Status, timeout int) error { parts, err := ParseResourceId(id, 3) if err != nil { return WrapError(err) } deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBDatabase(parts[0] + ":" + dbName) if err != nil { if NotFoundError(err) { if status == Deleted { return nil } } else { return WrapError(err) } } ready := false if object != nil { accountPrivilegeInfos := object["Accounts"].(map[string]interface{})["AccountPrivilegeInfo"].([]interface{}) for _, account := range accountPrivilegeInfos { // At present, postgresql response has a bug, DBOwner will be changed to ALL // At present, sqlserver response has a bug, DBOwner will be changed to DbOwner account := account.(map[string]interface{}) if account["Account"] == parts[1] && (account["AccountPrivilege"] == parts[2] || (parts[2] == "DBOwner" && (account["AccountPrivilege"] == "ALL" || account["AccountPrivilege"] == "DbOwner"))) { ready = true break } } } if status == Deleted && !ready { break } if ready { break } if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, "", id, ProviderERROR) } } return nil } func (s *RdsService) WaitForAccountPrivilegeRevoked(id, dbName string, timeout int) error { parts, err := ParseResourceId(id, 3) if err != nil { return WrapError(err) } deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBDatabase(parts[0] + ":" + dbName) if err != nil { if NotFoundError(err) { return nil } return WrapError(err) } exist := false if object != nil { accountPrivilegeInfo := object["Accounts"].(map[string]interface{})["AccountPrivilegeInfo"].([]interface{}) for _, account := range accountPrivilegeInfo { account := account.(map[string]interface{}) if account["Account"] == parts[1] && (account["AccountPrivilege"] == parts[2] || (parts[2] == "DBOwner" && account["AccountPrivilege"] == "ALL")) { exist = true break } } } if !exist { break } if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, "", dbName, ProviderERROR) } } return nil } func (s *RdsService) WaitForDBDatabase(id string, status Status, timeout int) error { parts, err := ParseResourceId(id, 2) if err != nil { return WrapError(err) } deadline := time.Now().Add(time.Duration(timeout) * time.Second) for { object, err := s.DescribeDBDatabase(id) if err != nil { if NotFoundError(err) { if status == Deleted { return nil } } return WrapError(err) } if object != nil && object["DBName"] == parts[1] { break } time.Sleep(DefaultIntervalShort * time.Second) if time.Now().After(deadline) { return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object["DBName"], parts[1], ProviderERROR) } } return nil } // turn period to TimeType func (s *RdsService) TransformPeriod2Time(period int, chargeType string) (ut int, tt common.TimeType) { if chargeType == string(Postpaid) { return 1, common.Day } if period >= 1 && period <= 9 { return period, common.Month } if period == 12 { return 1, common.Year } if period == 24 { return 2, common.Year } return 0, common.Day } // turn TimeType to Period func (s *RdsService) TransformTime2Period(ut int, tt common.TimeType) (period int) { if tt == common.Year { return 12 * ut } return ut } func (s *RdsService) flattenDBSecurityIPs(list []interface{}) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) for _, i := range list { i := i.(map[string]interface{}) l := map[string]interface{}{ "security_ips": i["SecurityIPList"], } result = append(result, l) } return result } func (s *RdsService) setInstanceTags(d *schema.ResourceData) error { if d.HasChange("tags") { added, removed := parsingTags(d) client := s.client var err error removedTagKeys := make([]string, 0) for _, v := range removed { if !ignoredTags(v, "") { removedTagKeys = append(removedTagKeys, v) } } if len(removedTagKeys) > 0 { action := "UnTagResources" request := map[string]interface{}{ "RegionId": s.client.RegionId, "ResourceType": "INSTANCE", "ResourceId.1": d.Id(), "SourceIp": s.client.SourceIp, } for i, key := range removedTagKeys { request[fmt.Sprintf("TagKey.%d", i+1)] = key } wait := incrementalWait(1*time.Second, 2*time.Second) err = resource.Retry(10*time.Minute, func() *resource.RetryError { response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } } if len(added) > 0 { action := "TagResources" request := map[string]interface{}{ "RegionId": s.client.RegionId, "ResourceType": "INSTANCE", "ResourceId.1": d.Id(), } count := 1 for key, value := range added { request[fmt.Sprintf("Tag.%d.Key", count)] = key request[fmt.Sprintf("Tag.%d.Value", count)] = value count++ } wait := incrementalWait(1*time.Second, 2*time.Second) err = resource.Retry(10*time.Minute, func() *resource.RetryError { response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, false) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } } if err := s.WaitForDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil { return WrapError(err) } d.SetPartial("tags") } return nil } func (s *RdsService) describeTags(d *schema.ResourceData) (tags []Tag, err error) { action := "DescribeTags" request := map[string]interface{}{ "DBInstanceId": d.Id(), "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, } client := s.client var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { return nil, WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) } return s.respToTags(response["Items"].(map[string]interface{})["TagInfos"].([]interface{})), nil } func (s *RdsService) respToTags(tagSet []interface{}) (tags []Tag) { result := make([]Tag, 0, len(tagSet)) for _, t := range tagSet { t := t.(map[string]interface{}) tag := Tag{ Key: t["TagKey"].(string), Value: t["TagValue"].(string), } result = append(result, tag) } return result } func (s *RdsService) tagsToMap(tags []Tag) map[string]string { result := make(map[string]string) for _, t := range tags { if !s.ignoreTag(t) { result[t.Key] = t.Value } } return result } func (s *RdsService) ignoreTag(t Tag) bool { filter := []string{"^aliyun", "^acs:", "^http://", "^https://"} for _, v := range filter { log.Printf("[DEBUG] Matching prefix %v with %v\n", v, t.Key) ok, _ := regexp.MatchString(v, t.Key) if ok { log.Printf("[DEBUG] Found Alibaba Cloud specific t %s (val: %s), ignoring.\n", t.Key, t.Value) return true } } return false } func (s *RdsService) tagsToString(tags []Tag) string { v, _ := json.Marshal(s.tagsToMap(tags)) return string(v) } func (s *RdsService) DescribeDBProxy(id string) (object map[string]interface{}, err error) { action := "DescribeDBProxy" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) object = make(map[string]interface{}) v, err := jsonpath.Get("$.DBProxyConnectStringItems", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.DBProxyConnectStringItems", response) } if dbProxyInstanceType, ok := response["DBProxyInstanceType"]; ok { object["DBProxyInstanceType"] = dbProxyInstanceType } object["DBProxyInstanceStatus"] = response["DBProxyInstanceStatus"] if dBProxyInstanceNum, ok := response["DBProxyInstanceNum"]; ok { object["DBProxyInstanceNum"] = dBProxyInstanceNum } if dBProxyPersistentConnectionStatus, ok := response["DBProxyPersistentConnectionStatus"]; ok { object["DBProxyPersistentConnectionStatus"] = dBProxyPersistentConnectionStatus } if dBProxyInstanceCurrentMinorVersion, ok := response["DBProxyInstanceCurrentMinorVersion"]; ok { object["DBProxyInstanceCurrentMinorVersion"] = dBProxyInstanceCurrentMinorVersion } if dBProxyInstanceLatestMinorVersion, ok := response["DBProxyInstanceLatestMinorVersion"]; ok { object["DBProxyInstanceLatestMinorVersion"] = dBProxyInstanceLatestMinorVersion } if dBProxyServiceStatus, ok := response["DBProxyServiceStatus"]; ok { object["DBProxyServiceStatus"] = dBProxyServiceStatus } if dBProxyConnectStringItems, ok := v.(map[string]interface{})["DBProxyConnectStringItems"].([]interface{}); ok { if len(dBProxyConnectStringItems) < 1 { return nil, WrapErrorf(NotFoundErr("DBProxyConnectStringItems", id), NotFoundMsg, ProviderERROR) } dBProxyConnectStringItem := dBProxyConnectStringItems[0].(map[string]interface{}) object["DBProxyVpcId"] = dBProxyConnectStringItem["DBProxyVpcId"] object["DBProxyVswitchId"] = dBProxyConnectStringItem["DBProxyVswitchId"] } return object, nil } func (s *RdsService) DescribeDBProxyEndpoint(id string, endpointName string) (object map[string]interface{}, err error) { action := "DescribeDBProxyEndpoint" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "DBProxyEndpointId": endpointName, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound", "Endpoint.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) DescribeRdsProxyEndpoint(id string) (object map[string]interface{}, err error) { action := "DescribeDBProxyEndpoint" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound", "Endpoint.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) DescribeRdsParameterGroup(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeParameterGroup" request := map[string]interface{}{ "RegionId": s.client.RegionId, "ParameterGroupId": id, } response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"ParamGroupsNotExistError"}) { err = WrapErrorf(NotFoundErr("RdsParameterGroup", id), NotFoundMsg, ProviderERROR) return object, err } err = WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) return object, err } addDebug(action, response, request) v, err := jsonpath.Get("$.ParamGroup.ParameterGroup", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.ParamGroup.ParameterGroup", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } else { if v.([]interface{})[0].(map[string]interface{})["ParameterGroupId"].(string) != id { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) DescribeRdsAccount(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeAccounts" parts, err := ParseResourceId(id, 2) if err != nil { err = WrapError(err) return } request := map[string]interface{}{ "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, "AccountName": parts[1], "DBInstanceId": parts[0], } response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { err = WrapErrorf(NotFoundErr("RdsAccount", id), NotFoundMsg, ProviderERROR) return object, err } err = WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) return object, err } addDebug(action, response, request) v, err := jsonpath.Get("$.Accounts.DBInstanceAccount", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Accounts.DBInstanceAccount", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) RdsAccountStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeRdsAccount(id) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } for _, failState := range failStates { if object["AccountStatus"].(string) == failState { return object, object["AccountStatus"].(string), WrapError(Error(FailedToReachTargetStatus, object["AccountStatus"].(string))) } } return object, object["AccountStatus"].(string), nil } } func (s *RdsService) DescribeRdsBackup(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeBackups" parts, err := ParseResourceId(id, 2) if err != nil { err = WrapError(err) return } request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "BackupId": parts[1], "DBInstanceId": parts[0], } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items.Backup", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items.Backup", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) DescribeBackupTasks(id string, backupJobId string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeBackupTasks" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": id, "BackupJobId": backupJobId, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items.BackupJob", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items.BackupJob", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } else { if fmt.Sprint(v.([]interface{})[0].(map[string]interface{})["BackupJobId"]) != backupJobId { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) RdsBackupStateRefreshFunc(id string, backupJobId string, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeBackupTasks(id, backupJobId) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } for _, failState := range failStates { if object["BackupStatus"] == failState { return object, object["BackupStatus"].(string), WrapError(Error(FailedToReachTargetStatus, object["BackupStatus"])) } } return object, object["BackupStatus"].(string), nil } } func (s *RdsService) DescribeDBInstanceHAConfig(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeDBInstanceHAConfig" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": id, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$", response) } object = v.(map[string]interface{}) return object, nil } func (s *RdsService) DescribeRdsCloneDbInstance(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeDBInstanceAttribute" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": id, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items.DBInstanceAttribute", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items.DBInstanceAttribute", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } else { if fmt.Sprint(v.([]interface{})[0].(map[string]interface{})["DBInstanceId"]) != id { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) DescribePGHbaConfig(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribePGHbaConfig" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": id, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$", response) } object = v.(map[string]interface{}) return object, nil } func (s *RdsService) DescribeHADiagnoseConfig(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeHADiagnoseConfig" request := map[string]interface{}{ "RegionId": s.client.RegionId, "SourceIp": s.client.SourceIp, "DBInstanceId": id, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$", response) } object = v.(map[string]interface{}) return object, nil } func (s *RdsService) DescribeUpgradeMajorVersionPrecheckTask(id string, taskId int) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client action := "DescribeUpgradeMajorVersionPrecheckTask" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": id, "TaskId": taskId, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items", response) } if len(v.([]interface{})) < 1 { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } else { if formatInt(v.([]interface{})[0].(map[string]interface{})["TaskId"]) != taskId { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } } object = v.([]interface{})[0].(map[string]interface{}) return object, nil } func (s *RdsService) RdsUpgradeMajorVersionRefreshFunc(id string, taskId int, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeUpgradeMajorVersionPrecheckTask(id, taskId) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } for _, failState := range failStates { if object["Result"] == failState { return object, object["Result"].(string), WrapError(Error(FailedToReachTargetStatus, object["Result"])) } } return object, object["Result"].(string), nil } } func (s *RdsService) DescribeRdsServiceLinkedRole(id string) (*ram.GetRoleResponse, error) { response := &ram.GetRoleResponse{} request := ram.CreateGetRoleRequest() request.RegionId = s.client.RegionId request.RoleName = id err := resource.Retry(5*time.Minute, func() *resource.RetryError { raw, err := s.client.WithRamClient(func(ramClient *ram.Client) (interface{}, error) { return ramClient.GetRole(request) }) if err != nil { if IsExpectedErrors(err, []string{ThrottlingUser}) { time.Sleep(2 * time.Second) return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) response, _ = raw.(*ram.GetRoleResponse) return nil }) if err != nil { if IsExpectedErrors(err, []string{"EntityNotExist.Role"}) { return response, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return response, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR) } return response, nil } func (s *RdsService) RdsDBProxyStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc { return func() (interface{}, string, error) { object, err := s.DescribeDBProxy(id) if err != nil { if NotFoundError(err) { // Set this to nil as if we didn't find anything. return nil, "", nil } return nil, "", WrapError(err) } for _, failState := range failStates { if object["DBProxyInstanceStatus"] == failState { return object, fmt.Sprint(object["DBProxyInstanceStatus"]), WrapError(Error(FailedToReachTargetStatus, object["DBProxyInstanceStatus"])) } } return object, fmt.Sprint(object["DBProxyInstanceStatus"]), nil } } func (s *RdsService) GetDbProxyInstanceSsl(id string) (object map[string]interface{}, err error) { action := "GetDbProxyInstanceSsl" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) v, err := jsonpath.Get("$.DbProxyCertListItems.DbProxyCertListItems", response) if err != nil { return object, WrapErrorf(NotFoundErr("RDS", id), NotFoundWithResponse, response) } if len(v.([]interface{})) < 1 { return object, nil } return v.([]interface{})[0].(map[string]interface{}), nil } func (s *RdsService) DescribeInstanceCrossBackupPolicy(id string) (object map[string]interface{}, err error) { action := "DescribeInstanceCrossBackupPolicy" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": id, "SourceIp": s.client.SourceIp, } client := s.client response, err := client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } if v, ok := response["BackupEnabled"]; ok && v.(string) == "Disabled" { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } addDebug(action, response, request) return response, nil } func (s *RdsService) FindKmsRoleArnDdr(k string) (string, error) { action := "DescribeKey" var response map[string]interface{} var err error client := s.client request := make(map[string]interface{}) request["KeyId"] = k wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Kms", "2016-01-20", 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, DataDefaultErrorMsg, k, action, AlibabaCloudSdkGoERROR) } resp, err := jsonpath.Get("$.KeyMetadata.Creator", response) if err != nil { return "", WrapErrorf(err, FailedGetAttributeMsg, action, "$.VersionIds.VersionId", response) } return strings.Join([]string{"acs:ram::", fmt.Sprint(resp), ":role/aliyunrdsinstanceencryptiondefaultrole"}, ""), nil } func (s *RdsService) DescribeRdsNode(id string) (object map[string]interface{}, err error) { client := s.client parts, err := ParseResourceId(id, 2) if err != nil { return nil, WrapError(err) } action := "DescribeDBInstanceAttribute" request := map[string]interface{}{ "RegionId": s.client.RegionId, "DBInstanceId": parts[0], "SourceIp": s.client.SourceIp, } var response map[string]interface{} wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", action, nil, request, true) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(action, response, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Items.DBInstanceAttribute", response) if err != nil { return nil, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Items.DBInstanceAttribute", response) } if len(v.([]interface{})) < 1 { return nil, WrapErrorf(NotFoundErr("DBAccount", id), NotFoundMsg, ProviderERROR) } dbNodeList := v.([]interface{})[0].(map[string]interface{}) if dbNodesList, ok := dbNodeList["DBClusterNodes"]; ok && dbNodesList != nil { if nodeList, ok := dbNodesList.(map[string]interface{})["DBClusterNode"].([]interface{}); ok { if len(nodeList) < 3 { return nil, WrapErrorf(NotFoundErr("DBAccount", id), NotFoundMsg, ProviderERROR) } for _, node := range nodeList { nodeId := node.(map[string]interface{})["NodeId"] if nodeId.(string) == parts[1] { object = node.(map[string]interface{}) object["DBInstanceId"] = dbNodeList["DBInstanceId"] break } } } } return object, nil } func (s *RdsService) DescribeDBInstanceEndpoints(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client parts, err := ParseResourceId(id, 2) if err != nil { return nil, WrapError(err) } _, err = s.DescribeDBInstance(parts[0]) if err != nil { return nil, WrapError(err) } action := "DescribeDBInstanceEndpoints" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": parts[0], "DBInstanceEndpointId": parts[1], "RegionId": s.client.RegionId, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(3*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 { if IsExpectedErrors(err, []string{"InvalidDBInstance.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Data.DBInstanceEndpoints", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Data.DBInstanceEndpoints", response) } if endpoints, ok := v.(map[string]interface{})["DBInstanceEndpoint"].([]interface{}); ok { if len(endpoints) < 1 { return nil, WrapErrorf(NotFoundErr("DBInstanceEndpoint", id), NotFoundMsg, ProviderERROR) } endpoint := endpoints[0].(map[string]interface{}) object = make(map[string]interface{}) object["EndpointDescription"] = endpoint["EndpointDescription"] object["EndpointType"] = endpoint["EndpointType"] object["DBInstanceId"] = parts[0] object["DBInstanceEndpointId"] = parts[1] nodeList := endpoint["NodeItems"] nodeItems := nodeList.(map[string]interface{})["NodeItem"].([]interface{}) dbNodesMaps := make([]map[string]interface{}, 0) if nodeItems != nil && len(nodeItems) > 0 { for _, nodeItem := range nodeItems { dbNodesListItemMap := map[string]interface{}{} dbNodesListItemMap["node_id"] = nodeItem.(map[string]interface{})["NodeId"] dbNodesListItemMap["weight"] = nodeItem.(map[string]interface{})["Weight"] dbNodesMaps = append(dbNodesMaps, dbNodesListItemMap) } object["NodeItems"] = dbNodesMaps } addressList := endpoint["AddressItems"] addressItems := addressList.(map[string]interface{})["AddressItem"].([]interface{}) if addressItems != nil && len(addressItems) > 0 { for _, addressItem := range addressItems { ipType := addressItem.(map[string]interface{})["IpType"] if ipType.(string) == "Private" { object["VpcId"] = addressItem.(map[string]interface{})["VpcId"] object["IpType"] = addressItem.(map[string]interface{})["IpType"] object["IpAddress"] = addressItem.(map[string]interface{})["IpAddress"] object["VSwitchId"] = addressItem.(map[string]interface{})["VSwitchId"] object["Port"] = addressItem.(map[string]interface{})["Port"] object["ConnectionString"] = addressItem.(map[string]interface{})["ConnectionString"] object["ConnectionStringPrefix"] = strings.Split(fmt.Sprint(object["ConnectionString"]), ".")[0] break } } } } return object, nil } func (s *RdsService) DescribeDBInstanceEndpointPublicAddress(id string) (object map[string]interface{}, err error) { var response map[string]interface{} client := s.client parts, err := ParseResourceId(id, 2) if err != nil { return nil, WrapError(err) } action := "DescribeDBInstanceEndpoints" request := map[string]interface{}{ "SourceIp": s.client.SourceIp, "DBInstanceId": parts[0], "DBInstanceEndpointId": parts[1], "RegionId": s.client.RegionId, } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(3*time.Minute, func() *resource.RetryError { response, err = client.RpcPost("Rds", "2014-08-15", 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 { if IsExpectedErrors(err, []string{"InvalidDBInstance.NotFound"}) { return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR) } return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) } v, err := jsonpath.Get("$.Data.DBInstanceEndpoints", response) if err != nil { return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.Data.DBInstanceEndpoints", response) } if endpoints, ok := v.(map[string]interface{})["DBInstanceEndpoint"].([]interface{}); ok { if len(endpoints) < 1 { return nil, WrapErrorf(NotFoundErr("DBInstanceEndpoint", id), NotFoundMsg, ProviderERROR) } endpoint := endpoints[0].(map[string]interface{}) object = make(map[string]interface{}) object["DBInstanceId"] = parts[0] object["DBInstanceEndpointId"] = parts[1] addressList := endpoint["AddressItems"] addressItems := addressList.(map[string]interface{})["AddressItem"].([]interface{}) if addressItems != nil && len(addressItems) > 0 { for _, addressItem := range addressItems { ipType := addressItem.(map[string]interface{})["IpType"] if ipType.(string) == "Public" { object["IpType"] = addressItem.(map[string]interface{})["IpType"] object["IpAddress"] = addressItem.(map[string]interface{})["IpAddress"] object["Port"] = addressItem.(map[string]interface{})["Port"] object["ConnectionString"] = addressItem.(map[string]interface{})["ConnectionString"] object["ConnectionStringPrefix"] = strings.Split(fmt.Sprint(object["ConnectionString"]), ".")[0] break } } } if _, ok := object["IpType"]; !ok { return nil, WrapErrorf(NotFoundErr("DBInstanceEndpointPublicAddress", id), NotFoundMsg, ProviderERROR) } } return object, nil }