alicloud/service_alicloud_polardb.go (1,790 lines of code) (raw):
package alicloud
import (
"encoding/json"
"fmt"
"log"
"regexp"
"sort"
"strconv"
"strings"
"time"
"github.com/PaesslerAG/jsonpath"
"github.com/aliyun/alibaba-cloud-sdk-go/services/polardb"
"github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
type PolarDBService struct {
client *connectivity.AliyunClient
}
func (s *PolarDBService) DescribePolarDBCluster(id string) (instance *polardb.DBCluster, err error) {
request := polardb.CreateDescribeDBClustersRequest()
request.RegionId = s.client.RegionId
dbClusterIds := []string{}
dbClusterIds = append(dbClusterIds, id)
request.DBClusterIds = id
var response *polardb.DescribeDBClustersResponse
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusters(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeDBClustersResponse)
return nil
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if len(response.Items.DBCluster) < 1 {
return nil, WrapErrorf(NotFoundErr("Cluster", id), NotFoundMsg, ProviderERROR)
}
return &response.Items.DBCluster[0], nil
}
func (s *PolarDBService) DescribePolarDBClusterAttribute(id string) (instance *polardb.DescribeDBClusterAttributeResponse, err error) {
request := polardb.CreateDescribeDBClusterAttributeRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
var response *polardb.DescribeDBClusterAttributeResponse
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterAttribute(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeDBClusterAttributeResponse)
return nil
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return instance, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return instance, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
return response, nil
}
func (s *PolarDBService) DescribeDBClusterAttribute(id string) (object map[string]interface{}, err error) {
action := "DescribeDBClusterAttribute"
request := map[string]interface{}{
"RegionId": s.client.RegionId,
"DBClusterId": id,
}
var response map[string]interface{}
client := s.client
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 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 *PolarDBService) DescribePolarDBAutoRenewAttribute(id string) (instance *polardb.AutoRenewAttribute, err error) {
request := polardb.CreateDescribeAutoRenewAttributeRequest()
request.RegionId = s.client.RegionId
request.DBClusterIds = id
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeAutoRenewAttribute(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return instance, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return instance, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ := raw.(*polardb.DescribeAutoRenewAttributeResponse)
if len(response.Items.AutoRenewAttribute) < 1 {
return nil, WrapErrorf(NotFoundErr("Cluster", id), NotFoundMsg, ProviderERROR)
}
return &response.Items.AutoRenewAttribute[0], nil
}
func (s *PolarDBService) DescribeParameters(id string) (ds *polardb.DescribeDBClusterParametersResponse, err error) {
request := polardb.CreateDescribeDBClusterParametersRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterParameters(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ := raw.(*polardb.DescribeDBClusterParametersResponse)
return response, err
}
func (s *PolarDBService) GrantPolarDBAccountPrivilege(id, dbName string) error {
parts, err := ParseResourceId(id, 3)
if err != nil {
return WrapError(err)
}
request := polardb.CreateGrantAccountPrivilegeRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = parts[0]
request.AccountName = parts[1]
request.DBName = dbName
request.AccountPrivilege = parts[2]
err = resource.Retry(3*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.GrantAccountPrivilege(request)
})
if err != nil {
if IsExpectedErrors(err, OperationDeniedDBStatus) {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if err := s.WaitForPolarDBAccountPrivilege(id, dbName, Available, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) RevokePolarDBAccountPrivilege(id, dbName string) error {
parts, err := ParseResourceId(id, 3)
if err != nil {
return WrapError(err)
}
request := polardb.CreateRevokeAccountPrivilegeRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = parts[0]
request.AccountName = parts[1]
request.DBName = dbName
err = resource.Retry(3*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.RevokeAccountPrivilege(request)
})
if err != nil {
if IsExpectedErrors(err, OperationDeniedDBStatus) {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if err := s.WaitForPolarDBAccountPrivilegeRevoked(id, dbName, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBAccountPrivilegeRevoked(id, dbName string, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBAccountPrivilege(id)
if err != nil {
return WrapError(err)
}
exist := false
if object != nil {
for _, dp := range object.DatabasePrivileges {
if dp.DBName == dbName {
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 *PolarDBService) WaitForPolarDBAccountPrivilege(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.DescribePolarDBAccountPrivilege(id)
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
} else {
return WrapError(err)
}
}
ready := false
if object != nil {
for _, dp := range object.DatabasePrivileges {
if dp.DBName == dbName && dp.AccountPrivilege == parts[2] {
ready = true
break
}
}
}
if status == Deleted && !ready {
break
}
if status != Deleted && ready {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, "", dbName, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) DescribePolarDBAccountPrivilege(id string) (account *polardb.DBAccount, err error) {
parts, err := ParseResourceId(id, 3)
if err != nil {
err = WrapError(err)
return
}
request := polardb.CreateDescribeAccountsRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = parts[0]
request.AccountName = parts[1]
invoker := NewInvoker()
invoker.AddCatcher(DBInstanceStatusCatcher)
var response *polardb.DescribeAccountsResponse
if err := invoker.Run(func() error {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeAccounts(request)
})
if err != nil {
return WrapError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeAccountsResponse)
return nil
}); err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if len(response.Accounts) < 1 {
return nil, WrapErrorf(NotFoundErr("DBAccountPrivilege", id), NotFoundMsg, ProviderERROR)
}
return &response.Accounts[0], nil
}
func (s *PolarDBService) WaitForPolarDBConnection(id string, status Status, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBConnectionV2(id, "Public")
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
} else {
return WrapError(err)
}
}
if status != Deleted && object != nil && object.ConnectionString != "" {
return nil
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object.ConnectionString, id, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
}
func (s *PolarDBService) WaitPolardbEndpointConfigEffect(id string, item map[string]string, timeout int) error {
parts, err := ParseResourceId(id, 2)
if err != nil {
return WrapError(err)
}
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
effected := true
object, err := s.DescribePolarDBInstanceNetInfo(parts[0])
if err != nil {
if NotFoundError(err) {
return WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return WrapError(err)
}
var endpoint polardb.DBEndpoint
if object != nil {
for _, o := range object {
if o.DBEndpointId == parts[1] {
endpoint = o
break
}
}
}
if value, ok := item["Nodes"]; ok {
if endpoint.Nodes != value {
effected = false
}
}
if value, ok := item["ReadWriteMode"]; ok {
if endpoint.ReadWriteMode != value {
effected = false
}
}
if value, ok := item["DBEndpointDescription"]; ok {
if endpoint.DBEndpointDescription != value {
effected = false
}
}
if value, ok := item["AutoAddNewNodes"]; ok {
if endpoint.AutoAddNewNodes != value {
effected = false
}
}
if value, ok := item["EndpointConfig"]; ok {
expectConfig := make(map[string]string)
actualConfig := make(map[string]string)
err = json.Unmarshal([]byte(value), &expectConfig)
err = json.Unmarshal([]byte(endpoint.EndpointConfig), &actualConfig)
for k, v := range expectConfig {
if subVal, ok := actualConfig[k]; !ok || subVal != v {
effected = false
break
}
}
}
if effected {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, endpoint, item, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBEndpoints(d *schema.ResourceData, status Status, endpointIds *schema.Set, timeout int) (string, error) {
var dbEndpointId string
if d.Id() != "" {
parts, err := ParseResourceId(d.Id(), 2)
if err != nil {
return "", WrapError(err)
}
dbEndpointId = parts[1]
}
dbClusterId := d.Get("db_cluster_id").(string)
endpointType := d.Get("endpoint_type").(string)
newEndpoint := make(map[string]string)
newEndpoint["endpoint_type"] = endpointType
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
endpoints, err := s.DescribePolarDBInstanceNetInfo(dbClusterId)
if err != nil {
return "", WrapError(err)
}
var deleted bool
deleted = true
for _, value := range endpoints {
if status == Deleted {
if dbEndpointId == value.DBEndpointId {
deleted = false
}
continue
}
if !endpointIds.Contains(value.DBEndpointId) && value.EndpointType == endpointType {
return value.DBEndpointId, nil
}
}
if status == Deleted && deleted {
return "", nil
}
if time.Now().After(deadline) {
return "", WrapErrorf(err, WaitTimeoutMsg, dbClusterId, GetFunc(1), timeout, endpoints, newEndpoint, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
}
func (s *PolarDBService) DescribePolarDBConnectionV2(id string, netType string) (*polardb.Address, error) {
parts, err := ParseResourceId(id, 2)
if err != nil {
return nil, WrapError(err)
}
deadline := time.Now().Add(time.Duration(DefaultIntervalLong) * time.Second)
for {
object, err := s.DescribePolarDBInstanceNetInfo(parts[0])
if err != nil {
if NotFoundError(err) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapError(err)
}
if object != nil {
for _, o := range object {
if o.DBEndpointId == parts[1] {
for _, p := range o.AddressItems {
if p.NetType == netType {
return &p, nil
}
}
}
}
}
time.Sleep(DefaultIntervalMini * time.Second)
if time.Now().After(deadline) {
break
}
}
return nil, WrapErrorf(NotFoundErr("DBConnection", id), NotFoundMsg, ProviderERROR)
}
func (s *PolarDBService) DescribePolarDBConnection(id string) (*polardb.Address, error) {
parts, err := ParseResourceId(id, 2)
if err != nil {
return nil, WrapError(err)
}
deadline := time.Now().Add(time.Duration(DefaultIntervalLong) * time.Second)
for {
object, err := s.DescribePolarDBInstanceNetInfo(parts[0])
if err != nil {
if NotFoundError(err) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapError(err)
}
if object != nil {
for _, o := range object {
if o.DBEndpointId == parts[1] {
for _, p := range o.AddressItems {
if p.NetType == "Public" {
return &p, nil
}
}
}
}
}
time.Sleep(DefaultIntervalMini * time.Second)
if time.Now().After(deadline) {
break
}
}
return nil, WrapErrorf(NotFoundErr("DBConnection", id), NotFoundMsg, ProviderERROR)
}
func (s *PolarDBService) DescribePolarDBInstanceNetInfo(id string) ([]polardb.DBEndpoint, error) {
request := polardb.CreateDescribeDBClusterEndpointsRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterEndpoints(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ := raw.(*polardb.DescribeDBClusterEndpointsResponse)
if len(response.Items) < 1 {
return nil, WrapErrorf(NotFoundErr("DBInstanceNetInfo", id), NotFoundMsg, ProviderERROR)
}
return response.Items, nil
}
func (s *PolarDBService) DescribePolarDBClusterEndpoint(id string) (*polardb.DBEndpoint, error) {
parts, err := ParseResourceId(id, 2)
if err != nil {
return nil, WrapError(err)
}
dbClusterId := parts[0]
dbEndpointId := parts[1]
request := polardb.CreateDescribeDBClusterEndpointsRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = dbClusterId
request.DBEndpointId = dbEndpointId
var raw interface{}
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err = s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterEndpoints(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
time.Sleep(10 * time.Second)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
response, _ := raw.(*polardb.DescribeDBClusterEndpointsResponse)
if len(response.Items) < 1 {
return nil, WrapErrorf(NotFoundErr("DBEndpoint", dbEndpointId), NotFoundMsg, ProviderERROR)
}
return &response.Items[0], nil
}
func (s *PolarDBService) DescribePolarDBClusterSSL(d *schema.ResourceData) (ssl *polardb.DescribeDBClusterSSLResponse, err error) {
parts, err := ParseResourceId(d.Id(), 2)
if err != nil {
return nil, WrapError(err)
}
dbClusterId := parts[0]
request := polardb.CreateDescribeDBClusterSSLRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = dbClusterId
var raw interface{}
err = resource.Retry(10*time.Minute, func() *resource.RetryError {
raw, err = s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterSSL(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
time.Sleep(10 * time.Second)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
response, _ := raw.(*polardb.DescribeDBClusterSSLResponse)
return response, nil
}
func (s *PolarDBService) DescribePolarDBDatabase(id string) (ds *polardb.Database, err error) {
parts, err := ParseResourceId(id, 2)
if err != nil {
return nil, WrapError(err)
}
dbName := parts[1]
request := polardb.CreateDescribeDatabasesRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = parts[0]
request.DBName = dbName
var raw interface{}
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err = s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDatabases(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
time.Sleep(10 * time.Second)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ := raw.(*polardb.DescribeDatabasesResponse)
if len(response.Databases.Database) < 1 {
return nil, WrapErrorf(NotFoundErr("DBDatabase", dbName), NotFoundMsg, ProviderERROR)
}
ds = &response.Databases.Database[0]
return ds, nil
}
func (s *PolarDBService) WaitForPolarDBDatabase(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.DescribePolarDBDatabase(id)
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
if status == Running {
continue
}
}
return WrapError(err)
}
if status != Deleted && object != nil && object.DBName == parts[1] {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object.DBName, parts[1], ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBAccount(id string, status Status, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBAccount(id)
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
} else {
return WrapError(err)
}
}
if object.AccountStatus == string(status) {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object.AccountStatus, status, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) DescribePolarDBAccount(id string) (ds *polardb.DBAccount, err error) {
parts, err := ParseResourceId(id, 2)
if err != nil {
err = WrapError(err)
return
}
request := polardb.CreateDescribeAccountsRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = parts[0]
request.AccountName = parts[1]
invoker := NewInvoker()
invoker.AddCatcher(DBInstanceStatusCatcher)
var response *polardb.DescribeAccountsResponse
if err := invoker.Run(func() error {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeAccounts(request)
})
if err != nil {
return err
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeAccountsResponse)
return nil
}); err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return nil, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return nil, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if len(response.Accounts) < 1 {
return nil, WrapErrorf(NotFoundErr("DBAccount", id), NotFoundMsg, ProviderERROR)
}
return &response.Accounts[0], nil
}
// WaitForInstance waits for instance to given status
func (s *PolarDBService) WaitForPolarDBInstance(id string, status Status, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBCluster(id)
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
} else {
return WrapError(err)
}
}
if strings.ToLower(object.DBClusterStatus) == strings.ToLower(string(status)) {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object.DBClusterStatus, status, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBConnectionPrefix(id, prefix, newPort string, netType string, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBConnectionV2(id, netType)
if err != nil {
return WrapError(err)
}
parts := strings.Split(object.ConnectionString, ".")
port := object.Port
if (newPort == "" || newPort == port) && (prefix == "" || prefix == parts[0]) {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, parts[0], prefix, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) fillingPolarDBEndpointSslCertificateUrl(sslEnabled string, d *schema.ResourceData) {
if sslEnabled == "Enable" {
d.Set("ssl_certificate_url", "https://apsaradb-public.oss-ap-southeast-1.aliyuncs.com/ApsaraDB-CA-Chain.zip?file=ApsaraDB-CA-Chain.zip®ionId="+s.client.RegionId)
} else {
d.Set("ssl_certificate_url", "")
}
}
func (s *PolarDBService) RefreshEndpointConfig(d *schema.ResourceData) error {
var config map[string]interface{}
config = make(map[string]interface{}, 0)
documented, ok := d.GetOk("endpoint_config")
if !ok {
d.Set("endpoint_config", config)
return nil
}
object, err := s.DescribePolarDBClusterEndpoint(d.Id())
if err != nil {
return WrapError(err)
}
var endpointConfig = make(map[string]interface{})
err = json.Unmarshal([]byte(object.EndpointConfig), &endpointConfig)
if err != nil {
return WrapError(err)
}
for k, v := range documented.(map[string]interface{}) {
if _, ok := endpointConfig[k]; ok {
config[k] = v
}
}
if err := d.Set("endpoint_config", config); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) RefreshParameters(d *schema.ResourceData) error {
var param []map[string]interface{}
documented, ok := d.GetOk("parameters")
object, err := s.DescribeParameters(d.Id())
if err != nil {
return WrapError(err)
}
var parameters = make(map[string]interface{})
for _, i := range object.RunningParameters.Parameter {
// 创建集群传入参数模板参数
changeParams := []string{"loose_polar_log_bin", "lower_case_table_names", "default_time_zone", "loose_xengine", "loose_xengine_use_memory_pct"}
if IsContain(changeParams, i.ParameterName) {
if i.ParameterName == "lower_case_table_names" {
if _parameterValue, err := strconv.Atoi(i.ParameterValue); err == nil {
d.Set(i.ParameterName, _parameterValue)
}
} else if d.Get("db_type").(string) == "MySQL" && d.Get("db_version") == "5.6" && i.ParameterName == "loose_polar_log_bin" {
// mysql 5.6 loose_polar_log_bin values: ON_WITH_GTID、OFF
if i.ParameterValue == "ON_WITH_GTID" {
d.Set(i.ParameterName, "ON")
}
} else if i.ParameterName == "loose_xengine" {
if i.ParameterValue == "1" {
d.Set("loose_xengine", "ON")
} else {
d.Set("loose_xengine", "OFF")
}
} else if i.ParameterName == "loose_xengine_use_memory_pct" {
if parameterValue, err := strconv.Atoi(i.ParameterValue); err == nil {
d.Set(i.ParameterName, parameterValue)
}
} else {
d.Set(i.ParameterName, i.ParameterValue)
}
}
if i.ParameterName != "" {
parameter := map[string]interface{}{
"name": i.ParameterName,
"value": i.ParameterValue,
}
parameters[i.ParameterName] = 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 !ok {
d.Set("parameters", param)
return nil
}
if err := d.Set("parameters", param); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) ModifyParameters(d *schema.ResourceData) error {
request := polardb.CreateModifyDBClusterParametersRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = d.Id()
config := make(map[string]string)
allConfig := make(map[string]string)
o, n := d.GetChange("parameters")
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.WaitForCluster(d.Id(), Running, DefaultLongTimeout); err != nil {
return WrapError(err)
}
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.ModifyDBClusterParameters(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, 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.WaitForPolarDBParameter(d.Id(), DefaultLongTimeout, allConfig); err != nil {
return WrapError(err)
}
}
d.SetPartial("parameters")
return nil
}
func (s *PolarDBService) CreateClusterParamsModifyParameters(d *schema.ResourceData) error {
request := polardb.CreateModifyDBClusterParametersRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = d.Id()
config := make(map[string]interface{})
allConfig := make(map[string]string)
changeParams := []string{"loose_polar_log_bin", "default_time_zone", "loose_xengine", "loose_xengine_use_memory_pct"}
for _, i := range changeParams {
if v, ok := d.GetOk(i); ok {
if d.HasChange(i) {
if i == "loose_xengine" {
if v == "ON" {
v = "1"
} else if v == "OFF" {
v = "0"
}
}
config[i] = v
allConfig[i] = fmt.Sprint(v)
}
}
}
cfg, _ := json.Marshal(config)
request.Parameters = string(cfg)
// wait instance status is Normal before modifying
if err := s.WaitForCluster(d.Id(), Running, DefaultLongTimeout); err != nil {
return WrapError(err)
}
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.ModifyDBClusterParameters(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
// wait instance parameter expect after modifying
if err := s.WaitForPolarDBParameter(d.Id(), 1200, allConfig); err != nil {
return WrapError(err)
}
for _, i := range changeParams {
d.SetPartial(i)
}
return nil
}
func (s *PolarDBService) setClusterTags(d *schema.ResourceData) error {
if d.HasChange("tags") {
oraw, nraw := d.GetChange("tags")
o := oraw.(map[string]interface{})
n := nraw.(map[string]interface{})
create, remove := s.diffTags(s.tagsFromMap(o), s.tagsFromMap(n))
if len(remove) > 0 {
var tagKey []string
for _, v := range remove {
if !ignoredTags(v.Key, v.Value) {
tagKey = append(tagKey, v.Key)
}
}
request := polardb.CreateUntagResourcesRequest()
request.ResourceId = &[]string{d.Id()}
request.ResourceType = "cluster"
request.TagKey = &tagKey
request.RegionId = s.client.RegionId
raw, err := s.client.WithPolarDBClient(func(client *polardb.Client) (interface{}, error) {
return client.UntagResources(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
}
if len(create) > 0 {
request := polardb.CreateTagResourcesRequest()
request.ResourceId = &[]string{d.Id()}
request.Tag = &create
request.ResourceType = "cluster"
request.RegionId = s.client.RegionId
raw, err := s.client.WithPolarDBClient(func(client *polardb.Client) (interface{}, error) {
return client.TagResources(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
}
d.SetPartial("tags")
}
return nil
}
func (s *PolarDBService) diffTags(oldTags, newTags []polardb.TagResourcesTag) ([]polardb.TagResourcesTag, []polardb.TagResourcesTag) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
create[t.Key] = t.Value
}
// Build the list of what to remove
var remove []polardb.TagResourcesTag
for _, t := range oldTags {
old, ok := create[t.Key]
if !ok || old != t.Value {
// Delete it!
remove = append(remove, t)
}
}
return s.tagsFromMap(create), remove
}
func (s *PolarDBService) tagsToMap(tags []polardb.TagResource) map[string]string {
result := make(map[string]string)
for _, t := range tags {
if !s.ignoreTag(t) {
result[t.TagKey] = t.TagValue
}
}
return result
}
func (s *PolarDBService) tagsFromMap(m map[string]interface{}) []polardb.TagResourcesTag {
result := make([]polardb.TagResourcesTag, 0, len(m))
for k, v := range m {
result = append(result, polardb.TagResourcesTag{
Key: k,
Value: v.(string),
})
}
return result
}
func (s *PolarDBService) ignoreTag(t polardb.TagResource) bool {
filter := []string{"^aliyun", "^acs:", "^http://", "^https://"}
for _, v := range filter {
log.Printf("[DEBUG] Matching prefix %v with %v\n", v, t.TagKey)
ok, _ := regexp.MatchString(v, t.TagKey)
if ok {
log.Printf("[DEBUG] Found Alibaba Cloud specific t %s (val: %s), ignoring.\n", t.TagKey, t.TagValue)
return true
}
}
return false
}
func (s *PolarDBService) DescribeTags(resourceId string, resourceType TagResourceType) (tags []polardb.TagResource, err error) {
request := polardb.CreateListTagResourcesRequest()
request.RegionId = s.client.RegionId
request.ResourceType = string(resourceType)
request.ResourceId = &[]string{resourceId}
raw, err := s.client.WithPolarDBClient(func(client *polardb.Client) (interface{}, error) {
return client.ListTagResources(request)
})
if err != nil {
err = WrapErrorf(err, DefaultErrorMsg, resourceId, request.GetActionName(), AlibabaCloudSdkGoERROR)
return
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ := raw.(*polardb.ListTagResourcesResponse)
return response.TagResources.TagResource, nil
}
// WaitForCluster waits for cluster to given status
func (s *PolarDBService) WaitForCluster(id string, status Status, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
object, err := s.DescribePolarDBClusterAttribute(id)
if err != nil {
if NotFoundError(err) {
if status == Deleted {
return nil
}
} else {
return WrapError(err)
}
}
if strings.ToLower(object.DBClusterStatus) == strings.ToLower(string(status)) {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object.DBClusterStatus, status, ProviderERROR)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
return nil
}
func (s *PolarDBService) DescribeDBSecurityIps(clusterId string, dbClusterIPArrayName string) (ips []string, err error) {
request := polardb.CreateDescribeDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = clusterId
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterAccessWhitelist(request)
})
if err != nil {
return ips, WrapErrorf(err, DefaultErrorMsg, clusterId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
resp, _ := raw.(*polardb.DescribeDBClusterAccessWhitelistResponse)
var ipstr, separator string
ipsMap := make(map[string]string)
for _, ip := range resp.Items.DBClusterIPArray {
if ip.DBClusterIPArrayName == dbClusterIPArrayName {
ipstr += separator + ip.SecurityIps
separator = COMMA_SEPARATED
}
}
for _, ip := range strings.Split(ipstr, 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 *PolarDBService) ModifyDBSecurityIps(clusterId, ips string) error {
request := polardb.CreateModifyDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = clusterId
request.SecurityIps = ips
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.ModifyDBClusterAccessWhitelist(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, clusterId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
if err := s.WaitForCluster(clusterId, Running, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) DescribeBackupPolicy(id string) (object map[string]interface{}, err error) {
var response map[string]interface{}
client := s.client
action := "DescribeBackupPolicy"
request := map[string]interface{}{
"DBClusterId": id,
"RegionId": s.client.RegionId,
}
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return object, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
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 *PolarDBService) DescribeLogBackupPolicy(id string) (object map[string]interface{}, err error) {
var response map[string]interface{}
client := s.client
action := "DescribeLogBackupPolicy"
request := map[string]interface{}{
"DBClusterId": id,
"RegionId": s.client.RegionId,
}
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return object, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
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 *PolarDBService) ModifyDBBackupPolicy(clusterId, backupTime, backupPeriod, backupRetentionPolicyOnClusterDeletion string) error {
request := polardb.CreateModifyBackupPolicyRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = clusterId
request.PreferredBackupPeriod = backupPeriod
request.PreferredBackupTime = backupTime
request.BackupRetentionPolicyOnClusterDeletion = backupRetentionPolicyOnClusterDeletion
raw, err := s.client.WithPolarDBClient(func(polardbClient *polardb.Client) (interface{}, error) {
return polardbClient.ModifyBackupPolicy(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, clusterId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
if err := s.WaitForCluster(clusterId, Running, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
return nil
}
func (s *PolarDBService) DescribeDBAuditLogCollectorStatus(id string) (collectorStatus string, err error) {
request := polardb.CreateDescribeDBClusterAuditLogCollectorRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
var response *polardb.DescribeDBClusterAuditLogCollectorResponse
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polardbClient *polardb.Client) (interface{}, error) {
return polardbClient.DescribeDBClusterAuditLogCollector(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
response, _ = raw.(*polardb.DescribeDBClusterAuditLogCollectorResponse)
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
if IsExpectedErrors(err, []string{"InvalidDBClusterId.NotFound"}) {
return "", WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return collectorStatus, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
return response.CollectorStatus, nil
}
func (s *PolarDBService) PolarDBClusterStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := s.DescribePolarDBClusterAttribute(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.DBClusterStatus == failState {
return object, object.DBClusterStatus, WrapError(Error(FailedToReachTargetStatus, object.DBClusterStatus))
}
}
return object, object.DBClusterStatus, 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 *PolarDBService) WaitForPolarDBParameter(clusterId string, timeout int, expects map[string]string) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
// get engine and engineVersion
attrbuteInfo, err := s.DescribePolarDBClusterAttribute(clusterId)
if err != nil {
return WrapError(err)
}
dbType := fmt.Sprint(attrbuteInfo.DBType)
db_version := fmt.Sprint(attrbuteInfo.DBVersion)
for {
object, err := s.DescribeParameters(clusterId)
if err != nil {
return WrapError(err)
}
var actuals = make(map[string]string)
for _, i := range object.RunningParameters.Parameter {
// mysql 5.6 loose_polar_log_bin values: ON_WITH_GTID、OFF
if dbType == "MySQL" && db_version == "5.6" && i.ParameterName == "loose_polar_log_bin" {
if i.ParameterValue == "ON_WITH_GTID" {
i.ParameterValue = "ON"
}
}
actuals[i.ParameterName] = i.ParameterValue
}
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, clusterId, GetFunc(1), timeout, got_value, expected_value, ProviderERROR)
}
}
return nil
}
func (s *PolarDBService) DescribeDBClusterTDE(id string) (map[string]interface{}, error) {
action := "DescribeDBClusterTDE"
request := map[string]interface{}{
"DBClusterId": id,
}
client := s.client
response, err := client.RpcPost("polardb", "2017-08-01", action, nil, request, true)
if err != nil {
return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)
}
addDebug(action, response, request)
return response, nil
}
func (s *PolarDBService) CheckKMSAuthorized(id string, tdeRegion string) (map[string]interface{}, error) {
action := "CheckKMSAuthorized"
request := map[string]interface{}{
"RegionId": s.client.RegionId,
"DBClusterId": id,
}
if tdeRegion != "" {
request["tdeRegion"] = tdeRegion
}
var response map[string]interface{}
var err error
client := s.client
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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)
return response, nil
}
func (s *PolarDBService) WaitForPolarDBTDEStatus(id string, status string, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Minute)
for {
object, err := s.DescribeDBClusterTDE(id)
if err != nil {
return WrapError(err)
}
if object["TDEStatus"] == status {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, object, status, ProviderERROR)
}
time.Sleep(DefaultIntervalMedium * time.Second)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBNodeClass(id string, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
clusters, err := s.DescribePolarDBCluster(id)
if err != nil {
return WrapError(err)
}
clusterAttribute, err := s.DescribePolarDBClusterAttribute(id)
if err != nil {
return WrapError(err)
}
if len(clusters.DBNodes.DBNode) == len(clusterAttribute.DBNodes) {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, ProviderERROR)
}
time.Sleep(DefaultIntervalMedium * time.Second)
}
return nil
}
func (s *PolarDBService) WaitForPolarDBPayType(id string, status string, timeout int) error {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
for {
clusters, err := s.DescribePolarDBCluster(id)
if err != nil {
return WrapError(err)
}
if clusters.PayType == status {
break
}
if time.Now().After(deadline) {
return WrapErrorf(err, WaitTimeoutMsg, id, GetFunc(1), timeout, clusters, status, ProviderERROR)
}
time.Sleep(DefaultIntervalMedium * time.Second)
}
return nil
}
func (s *PolarDBService) PolarDBClusterTDEStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := s.DescribeDBClusterTDE(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["TDEStatus"].(string) == failState {
return object, object["TDEStatus"].(string), WrapError(Error(FailedToReachTargetStatus, object["TDEStatus"].(string)))
}
}
return object, object["TDEStatus"].(string), nil
}
}
func (s *PolarDBService) DescribeDBSecurityGroups(clusterId string) ([]string, error) {
request := polardb.CreateDescribeDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = clusterId
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterAccessWhitelist(request)
})
if err != nil {
return nil, WrapErrorf(err, DefaultErrorMsg, clusterId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
resp, _ := raw.(*polardb.DescribeDBClusterAccessWhitelistResponse)
groups := make([]string, 0)
dbClusterSecurityGroups := resp.DBClusterSecurityGroups.DBClusterSecurityGroup
for _, group := range dbClusterSecurityGroups {
groups = append(groups, group.SecurityGroupId)
}
return groups, nil
}
func (s *PolarDBService) ModifyDBClusterAccessWhitelist(d *schema.ResourceData) error {
if _, ok := d.GetOk("db_cluster_ip_array"); ok {
removed, added := d.GetChange("db_cluster_ip_array")
for _, e := range removed.(*schema.Set).List() {
pack := e.(map[string]interface{})
if fmt.Sprint(pack["db_cluster_ip_array_name"]) == "default" {
continue
}
//ips expand string list
ipList := expandStringList(pack["security_ips"].(*schema.Set).List())
ipstr := strings.Join(ipList[:], COMMA_SEPARATED)
request := polardb.CreateModifyDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = d.Id()
request.SecurityIps = ipstr
request.DBClusterIPArrayName = pack["db_cluster_ip_array_name"].(string)
request.ModifyMode = "Delete"
wait := incrementalWait(3*time.Second, 3*time.Second)
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.ModifyDBClusterAccessWhitelist(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if err := s.WaitForCluster(d.Id(), Running, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
}
for _, e := range added.(*schema.Set).List() {
pack := e.(map[string]interface{})
//ips expand string list
ipList := expandStringList(pack["security_ips"].(*schema.Set).List())
ipstr := strings.Join(ipList[:], COMMA_SEPARATED)
// default disable connect from outside
if ipstr == "" {
ipstr = LOCAL_HOST_IP
}
request := polardb.CreateModifyDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = d.Id()
request.SecurityIps = ipstr
request.DBClusterIPArrayName = pack["db_cluster_ip_array_name"].(string)
request.ModifyMode = pack["modify_mode"].(string)
wait := incrementalWait(3*time.Second, 3*time.Second)
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.ModifyDBClusterAccessWhitelist(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR)
}
if err := s.WaitForCluster(d.Id(), Running, DefaultTimeoutMedium); err != nil {
return WrapError(err)
}
}
d.SetPartial("db_cluster_ip_array")
}
return nil
}
func (s *PolarDBService) DescribeDBClusterAccessWhitelist(id string) (instance *polardb.DescribeDBClusterAccessWhitelistResponse, err error) {
request := polardb.CreateDescribeDBClusterAccessWhitelistRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
var response *polardb.DescribeDBClusterAccessWhitelistResponse
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterAccessWhitelist(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeDBClusterAccessWhitelistResponse)
return nil
})
if err != nil {
return nil, WrapError(err)
}
return response, nil
}
func convertPolarDBIpsSetListToString(arr1 *schema.Set) []string {
var ips []string
for _, v := range arr1.List() {
ips = append(ips, v.(string))
}
return ips
}
func convertPolarDBIpsSetToString(sourceIps string) []string {
ipsMap := make(map[string]string)
for _, ip := range strings.Split(sourceIps, COMMA_SEPARATED) {
ipsMap[ip] = ip
}
var ips []string
if len(ipsMap) > 0 {
for key := range ipsMap {
ips = append(ips, key)
}
}
return ips
}
func arrValueEqual(arr1, arr2 []string) bool {
sort.Strings(arr2)
sort.Strings(arr1)
for i, v := range arr1 {
if v != arr2[i] {
return false
}
}
return true
}
func (s *PolarDBService) PolarDBClusterCategoryRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := s.DescribePolarDBClusterAttribute(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.Category == failState {
return object, object.Category, WrapError(Error(FailedToReachTargetStatus, object.Category))
}
}
return object, object.Category, nil
}
}
func (s *PolarDBService) DescribePolarDBGlobalDatabaseNetwork(id string) (object map[string]interface{}, err error) {
var response map[string]interface{}
client := s.client
action := "DescribeGlobalDatabaseNetwork"
request := map[string]interface{}{
"GDNId": id,
}
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 {
if IsExpectedErrors(err, []string{"GDN.NotFound"}) {
return object, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
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 *PolarDBService) PolarDBGlobalDatabaseNetworkRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := s.DescribePolarDBGlobalDatabaseNetwork(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 fmt.Sprint(object["GDNStatus"]) == failState {
return object, fmt.Sprint(object["GDNStatus"]), WrapError(Error(FailedToReachTargetStatus, fmt.Sprint(object["GDNStatus"])))
}
}
return object, fmt.Sprint(object["GDNStatus"]), nil
}
}
func (s *PolarDBService) DescribePolarDBParameterGroup(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,
}
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 {
if IsExpectedErrors(err, []string{"ParamGroupsNotExist"}) {
return object, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)
}
v, err := jsonpath.Get("$.ParameterGroup", response)
if err != nil {
return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.ParameterGroup", response)
}
if len(v.([]interface{})) < 1 {
return object, WrapErrorf(NotFoundErr("PolarDB", id), NotFoundWithResponse, response)
} else {
if fmt.Sprint(v.([]interface{})[0].(map[string]interface{})["ParameterGroupId"]) != id {
return object, WrapErrorf(NotFoundErr("PolarDB", id), NotFoundWithResponse, response)
}
}
object = v.([]interface{})[0].(map[string]interface{})
return object, nil
}
func (s *PolarDBService) DescribeDBClusterServerlessConfig(id string) (object map[string]interface{}, err error) {
action := "DescribeDBClusterServerlessConf"
request := map[string]interface{}{
"RegionId": s.client.RegionId,
"DBClusterId": id,
}
var response map[string]interface{}
client := s.client
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 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 *PolarDBService) DescribeDBClusterVersion(id string) (object map[string]interface{}, err error) {
action := "DescribeDBClusterVersion"
request := map[string]interface{}{
"RegionId": s.client.RegionId,
"DBClusterId": id,
}
var response map[string]interface{}
client := s.client
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RpcPost("polardb", "2017-08-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 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 *PolarDBService) DescribeDBClusterAvailableVersion(id string) (instance *polardb.DescribeDBClusterVersionResponse, err error) {
request := polardb.CreateDescribeDBClusterVersionRequest()
request.RegionId = s.client.RegionId
request.DBClusterId = id
request.DescribeType = "AVAILABLE_VERSION"
var response *polardb.DescribeDBClusterVersionResponse
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
raw, err := s.client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) {
return polarDBClient.DescribeDBClusterVersion(request)
})
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
response, _ = raw.(*polardb.DescribeDBClusterVersionResponse)
return nil
})
if err != nil {
return nil, WrapError(err)
}
return response, nil
}
func (s *PolarDBService) PolarDBClusterProxyStateRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := s.DescribePolarDBClusterAttribute(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.ProxyStatus == failState {
return object, object.ProxyStatus, WrapError(Error(FailedToReachTargetStatus, object.ProxyStatus))
}
}
return object, object.ProxyStatus, nil
}
}
func (s *PolarDBService) DescribeDBClusterStandbyAz(id string, timeout int) (zoneId string, err error) {
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
standbyAz := ""
for {
clusterAttribute, err := s.DescribePolarDBClusterAttribute(id)
if err != nil {
return "", WrapError(err)
}
primaryZone := ""
if len(clusterAttribute.DBNodes) > 0 {
primaryZone = clusterAttribute.DBNodes[0].ZoneId
}
exist := true
if clusterAttribute.HotStandbyCluster != "OFF" {
exist = false
for _, zoneId := range strings.Split(clusterAttribute.ZoneIds, ",") {
if zoneId != primaryZone && zoneId != "" {
standbyAz = zoneId
exist = true
break
}
}
}
if exist {
return standbyAz, nil
}
if time.Now().After(deadline) {
return standbyAz, WrapErrorf(err, RequiredWhenMsg, "standby_az", "hot_standby_cluster", clusterAttribute.HotStandbyCluster)
}
time.Sleep(DefaultIntervalShort * time.Second)
}
}