func (c *DDCClient) GetDetail(instanceId string) (*Instance, error) {
	detail, err := c.GetDdcDetail(instanceId)
	result := &Instance{
		InstanceName:            detail.Instance.InstanceName,
		InstanceId:              detail.Instance.InstanceId,
		SourceInstanceId:        detail.Instance.SourceInstanceId,
		Endpoint:                detail.Instance.Endpoint,
		Engine:                  detail.Instance.Engine,
		EngineVersion:           detail.Instance.EngineVersion,
		InstanceStatus:          detail.Instance.InstanceStatus,
		CpuCount:                detail.Instance.CpuCount,
		MemoryCapacity:          detail.Instance.AllocatedMemoryInGB,
		VolumeCapacity:          detail.Instance.AllocatedStorageInGB,
		UsedStorage:             detail.Instance.UsedStorageInGB,
		InstanceType:            detail.Instance.Type,
		InstanceCreateTime:      detail.Instance.InstanceCreateTime,
		InstanceExpireTime:      detail.Instance.InstanceExpireTime,
		PubliclyAccessible:      detail.Instance.PublicAccessStatus,
		PaymentTiming:           detail.Instance.PaymentTiming,
		SyncMode:                detail.Instance.SyncMode,
		Region:                  detail.Instance.Region,
		VpcId:                   detail.Instance.VpcId,
		BackupPolicy:            detail.Instance.BackupPolicy,
		RoGroupList:             detail.Instance.RoGroupList,
		NodeMaster:              detail.Instance.NodeMaster,
		NodeSlave:               detail.Instance.NodeSlave,
		NodeReadReplica:         detail.Instance.NodeReadReplica,
		Subnets:                 detail.Instance.Subnets,
		DeployId:                detail.Instance.DeployId,
		ZoneNames:               detail.Instance.ZoneNames,
		Category:                detail.Instance.Category,
		LongBBCId:               detail.Instance.LongBBCId,
		InstanceTopoForReadonly: detail.Instance.InstanceTopoForReadonly,
		AutoRenewRule:           detail.Instance.AutoRenewRule,
	}
	result.PublicAccessStatus = strconv.FormatBool(result.PubliclyAccessible)
	return result, err
}
GetDetail - get a specific ddc Instance's detail

PARAMS:
- instanceId: the specific ddc Instance's ID
RETURNS:
- *Instance: the specific ddc Instance's detail
- error: nil if success otherwise the specific error
package ddcrds
import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
	"github.com/baidubce/bce-sdk-go/bce"
	"github.com/baidubce/bce-sdk-go/http"
)
const (
	KEY_CLIENT_TOKEN = "clientToken"
	KEY_MARKER       = "marker"
	KEY_MAX_KEYS     = "maxKeys"
	COMMA            = ","
)
func getMarkerParams(marker *Marker) map[string]string {
	if marker == nil {
		marker = &Marker{Marker: "-1"}
	}
	params := make(map[string]string, 2)
	params[KEY_MARKER] = marker.Marker
	if marker.MaxKeys > 0 {
		params[KEY_MAX_KEYS] = strconv.Itoa(marker.MaxKeys)
	}
	return params
}
func getQueryParams(val interface{}) (map[string]string, error) {
	var params map[string]string
	if val != nil {
		err := json.Unmarshal([]byte(Json(val)), &params)
		if err != nil {
			return nil, err
		}
	}
	return params, nil
}
func (c *DDCClient) CreateInstance(args *CreateInstanceArgs) (*CreateResult, error) {
	if args == nil {
		return nil, fmt.Errorf("unset args")
	}
	result := &CreateResult{}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.POST).
		WithURL(getDdcInstanceUri()).
		WithQueryParamFilter("clientToken", args.ClientToken).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(args).
		WithResult(result).
		Do()
	return result, err
}
func (c *DDCClient) CreateRds(args *CreateRdsArgs) (*CreateResult, error) {
	if args == nil {
		return nil, fmt.Errorf("unset args")
	}
	if args.Engine == "" {
		return nil, fmt.Errorf("unset Engine")
	}
	if args.EngineVersion == "" {
		return nil, fmt.Errorf("unset EngineVersion")
	}
	if args.Billing.PaymentTiming == "" {
		return nil, fmt.Errorf("unset PaymentTiming")
	}
	newArgs := &CreateInstanceArgs{
		InstanceType: "RDS",
		Number:       args.PurchaseCount,
		ClientToken:  args.ClientToken,
		Instance: CreateInstance{
			InstanceName:         args.InstanceName,
			Engine:               strings.ToLower(args.Engine),
			EngineVersion:        args.EngineVersion,
			CpuCount:             args.CpuCount,
			AllocatedMemoryInGB:  int(args.MemoryCapacity),
			AllocatedStorageInGB: args.VolumeCapacity,
			DiskIoType:           "ssd",
			DeployId:             args.DeployId,
			PoolId:               args.PoolId,
			IsDirectPay:          args.IsDirectPay,
			Billing:              args.Billing,
			AutoRenewTime:        args.AutoRenewTime,
			AutoRenewTimeUnit:    args.AutoRenewTimeUnit,
			Tags:                 args.Tags,
			Category:             args.Category,
			SyncMode:             strings.ToLower(args.SyncMode),
		},
	}
	info, err := c.SupplyVpcInfo(newArgs, args)
	if err != nil {
		return nil, err
	}
	result, err2 := c.CreateInstance(info)
	if err2 != nil {
		return nil, err2
	}
	return result, nil
}
func (c *DDCClient) SupplyVpcInfo(newArgs *CreateInstanceArgs, args *CreateRdsArgs) (*CreateInstanceArgs, error) {
	info := newArgs
	vpc, err := c.ListVpc()
	if err != nil {
		fmt.Printf("list vpc error: %+v\n", err)
		return nil, err
	}
	defaultVpcId := ""
	if args.VpcId == "" {
		for _, e := range *vpc {
			defaultVpcId = e.VpcId
			info.Instance.VpcId = e.VpcId
			args.VpcId = e.VpcId
		}
	}
	if args.VpcId == defaultVpcId {
		for _, e := range *vpc {
			if e.VpcId == args.VpcId {
				info.Instance.VpcId = e.VpcId
				args.VpcId = e.VpcId
			}
		}
		info, err = c.UnDefaultVpcInfo(info, args)
		if err != nil {
			fmt.Printf("set vpc error: %+v\n", err)
			return nil, err
		}
	} else {
		for _, e := range *vpc {
			if args.VpcId == e.ShortId {
				info.Instance.VpcId = e.VpcId
				args.VpcId = e.VpcId
			}
		}
		info, err = c.UnDefaultVpcInfo(info, args)
		if err != nil {
			fmt.Printf("supply zoneAndSubnet info error: %+v\n", err)
			return nil, err
		}
	}
	return info, nil
}
func (c *DDCClient) SupplyZoneAndSubnetInfo(newArgs *CreateInstanceArgs, args *CreateRdsArgs) (*CreateInstanceArgs, error) {
	newZoneName := ""
	if args.Subnets != nil {
		for _, e := range args.Subnets {
			newZoneName += e.ZoneName + ","
		}
		if newZoneName != "" && newZoneName[0:len(newZoneName)-1] != strings.Join(args.ZoneNames, ",") {
			fmt.Printf("subnets and zoneNames not matcher: %+v\n", nil)
			return nil, errors.New("subnets and zoneNames not matcher")
		} else {
			listSubnetsArgs := &ListSubnetsArgs{
				VpcId: args.VpcId,
			}
			subnets, err1 := c.ListSubnets(listSubnetsArgs)
			if err1 != nil {
				fmt.Printf("list subnets error: %+v\n", err1)
				return nil, err1
			}
			subnetId := ""
			if args.Subnets != nil {
				for _, e := range subnets.Subnets {
					for _, e1 := range args.Subnets {
						if e.ShortId == e1.SubnetId {
							subnetId += e.Az + ":" + e.LongId + ","
						}
					}
				}
				if subnetId == "" {
					return nil, errors.New("subnetId no match vpc or pool")
				}
				newArgs.Instance.SubnetId = subnetId[0 : len(subnetId)-1]
			}
		}
	} else {
		var subnetStr string
		for _, e := range args.ZoneNames {
			if !strings.Contains(e, ",") {
				listSubnetsArgs := &ListSubnetsArgs{
					VpcId:    args.VpcId,
					ZoneName: e,
				}
				subnets, err := c.ListSubnets(listSubnetsArgs)
				if err != nil {
					fmt.Printf("list subnets error: %+v\n", err)
					return nil, err
				}
				if subnets != nil && len(subnets.Subnets) > 0 {
					subnetId := subnets.Subnets[0].LongId
					subnetStr += e + ":" + subnetId + ","
				}
			}
		}
		if len(subnetStr) < 1 {
			return nil, errors.New("Have no available subnet")
		}
		newArgs.Instance.SubnetId = subnetStr[:len(subnetStr)-1]
	}
	return newArgs, nil
}
func (c *DDCClient) UnDefaultVpcInfo(newArgs *CreateInstanceArgs, args *CreateRdsArgs) (*CreateInstanceArgs, error) {
	info := newArgs
	list, err2 := c.GetZoneList()
	if err2 != nil {
		fmt.Printf("get zone list error: %+v\n", err2)
		return nil, err2
	}
	newZoneName := ""
	if args.ZoneNames == nil {
		if args.Subnets == nil {
			subnets, _ := c.ListSubnets(&ListSubnetsArgs{VpcId: args.VpcId})
			if subnets == nil || len(subnets.Subnets) == 0 {
				return nil, errors.New("Have no available subnet or zone")
			}
			for _, e := range subnets.Subnets {
				info.Instance.AZone = e.Az
				args.ZoneNames = append(args.ZoneNames, e.Az)
				break
			}
		} else {
			for _, e := range args.Subnets {
				newZoneName += e.ZoneName + ","
				args.ZoneNames = append(args.ZoneNames, e.ZoneName)
			}
			for _, e := range list.Zones {
				if newZoneName == strings.Join(e.ApiZoneNames, ",") {
					info.Instance.AZone = strings.Join(e.ApiZoneNames, ",")
				}
			}
		}
		if args.ZoneNames == nil {
			return nil, errors.New("Have no available zone for your operation.")
		}
	} else {
		newZoneName = ""
		for _, e1 := range list.Zones {
			if strings.Join(args.ZoneNames, ",") == strings.Join(e1.ZoneNames, ",") {
				newZoneName = strings.Join(e1.ApiZoneNames, ",")
			}
		}
		info.Instance.AZone = newZoneName
	}
	info, err2 = c.SupplyZoneAndSubnetInfo(info, args)
	if err2 != nil {
		return nil, err2
	}
	return info, nil
}
func (c *DDCClient) CreateReadReplica(args *CreateReadReplicaArgs) (*CreateResult, error) {
	if args == nil {
		return nil, fmt.Errorf("unset args")
	}
	if args.SourceInstanceId == "" {
		return nil, fmt.Errorf("unset SourceInstanceId")
	}
	if args.Billing.PaymentTiming == "" {
		return nil, fmt.Errorf("unset PaymentTiming")
	}
	detail, err2 := c.GetDdcDetail(args.SourceInstanceId)
	if err2 != nil {
		return nil, err2
	}
	newArgs := &CreateInstanceArgs{
		InstanceType: "RDS",
		Number:       args.PurchaseCount,
		ClientToken:  args.ClientToken,
		Instance: CreateInstance{
			SourceInstanceId:     args.SourceInstanceId,
			InstanceName:         args.InstanceName,
			Engine:               strings.ToLower(detail.Instance.Engine),
			EngineVersion:        detail.Instance.EngineVersion,
			CpuCount:             args.CpuCount,
			AllocatedMemoryInGB:  int(args.MemoryCapacity),
			AllocatedStorageInGB: args.VolumeCapacity,
			DiskIoType:           "ssd",
			DeployId:             args.DeployId,
			PoolId:               args.PoolId,
			RoGroupId:            args.RoGroupId,
			RoGroupWeight:        Int(args.RoGroupWeight),
			EnableDelayOff:       Int(args.EnableDelayOff),
			DelayThreshold:       Int(args.DelayThreshold),
			LeastInstanceAmount:  Int(args.LeastInstanceAmount),
			Billing:              args.Billing,
			IsDirectPay:          args.IsDirectPay,
			AutoRenewTime:        args.AutoRenewTime,
			AutoRenewTimeUnit:    args.AutoRenewTimeUnit,
			Tags:                 args.Tags,
		},
	}
	createRdsArgs := &CreateRdsArgs{
		VpcId:     args.VpcId,
		Subnets:   args.Subnets,
		ZoneNames: args.ZoneNames,
	}
	info, err := c.SupplyVpcInfo(newArgs, createRdsArgs)
	if err != nil {
		return nil, err
	}
	result, err2 := c.CreateInstance(info)
	if err2 != nil {
		return nil, err2
	}
	return result, err
}
func (c *DDCClient) UpdateRoGroup(roGroupId string, args *UpdateRoGroupArgs) error {
	if args == nil {
		return fmt.Errorf("unset args")
	}
	body := &UpdateRoGroupRealArgs{
		RoGroupName: args.RoGroupName,
		EnableDelayOff:      Int(args.EnableDelayOff),
		DelayThreshold:      Int(args.DelayThreshold),
		LeastInstanceAmount: Int(args.LeastInstanceAmount),
		IsBalanceRoLoad:     Int(args.IsBalanceRoLoad),
	}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.PUT).
		WithURL(getUpdateRoGroupUriWithId(roGroupId)).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(body).
		Do()
	return err
}
func (c *DDCClient) UpdateRoGroupReplicaWeight(roGroupId string, args *UpdateRoGroupWeightArgs) error {
	if args == nil {
		return fmt.Errorf("unset args")
	}
	body := &UpdateRoGroupWeightRealArgs{
		RoGroupName: args.RoGroupName,
		EnableDelayOff:      Int(args.EnableDelayOff),
		DelayThreshold:      Int(args.DelayThreshold),
		LeastInstanceAmount: Int(args.LeastInstanceAmount),
		IsBalanceRoLoad:     Int(args.IsBalanceRoLoad),
		ReplicaList:         args.ReplicaList,
	}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.PUT).
		WithURL(getUpdateRoGroupWeightUriWithId(roGroupId)).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(body).
		Do()
	return err
}
func (c *DDCClient) ReBalanceRoGroup(roGroupId string) error {
	err := bce.NewRequestBuilder(c).
		WithMethod(http.POST).
		WithURL(getReBalanceRoGroupUriWithId(roGroupId)).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		Do()
	return err
}
func (c *DDCClient) CreateDeploySet(poolId string, args *CreateDeployRequest) (*CreateDeployResult, error) {
	if args == nil {
		return nil, fmt.Errorf("unset args")
	}
	if len(args.Strategy) < 1 {
		args.Strategy = "centralized"
	}
	if !(args.Strategy == "distributed" || args.Strategy == "centralized") {
		return nil, fmt.Errorf("Only support strategy centralized, current strategy: %v", args.Strategy)
	}
	result := &CreateDeployResult{}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.POST).
		WithURL(getDeploySetUri(poolId)).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(args).
		WithResult(result).
		Do()
	return result, err
}
func (c *DDCClient) UpdateDeploySet(poolId string, deployId string, args *UpdateDeployRequest) error {
	if args == nil {
		return fmt.Errorf("unset args")
	}
	if !(args.Strategy == "distributed" || args.Strategy == "centralized") {
		return fmt.Errorf("Only support strategy distributed/centralized, current strategy: %v", args.Strategy)
	}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.PUT).
		WithURL(getDeploySetUriWithId(poolId, deployId)).
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(args).
		Do()
	return err
}
func (c *DDCClient) ListRds(marker *ListRdsArgs) (*ListRdsResult, error) {
	req := &bce.BceRequest{}
	req.SetUri(getDdcInstanceUri() + "/list")
	req.SetMethod(http.GET)
	if marker != nil {
		req.SetParam(KEY_MARKER, marker.Marker)
		req.SetParam(KEY_MAX_KEYS, strconv.Itoa(marker.MaxKeys))
	}
	resp := &bce.BceResponse{}
	if err := c.SendRequest(req, resp); err != nil {
		return nil, err
	}
	if resp.IsFail() {
		return nil, resp.ServiceError()
	}
	jsonBody := &ListRdsResult{}
	if err := resp.ParseJsonBody(jsonBody); err != nil {
		return nil, err
	}
	return jsonBody, nil
}
func (c *DDCClient) ListPage(args *ListPageArgs) (*ListPageResult, error) {
	if args == nil {
		return nil, fmt.Errorf("unset args")
	}
	result := &ListPageResult{}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.POST).
		WithURL(getDdcInstanceUri()+"/listPage").
		WithHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE).
		WithBody(args).
		WithResult(result).
		Do()
	return result, err
}
func (c *DDCClient) GetDdcDetail(instanceId string) (*InstanceModelResult, error) {
	result := &InstanceModelResult{}
	err := bce.NewRequestBuilder(c).
		WithMethod(http.GET).
		WithURL(getDdcUriWithInstanceId(instanceId)).
		WithResult(result).
		Do()
	return result, err
}