yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/dbinstance.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aliyun
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  	"yunion.io/x/pkg/utils"
    27  
    28  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    29  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    30  	"yunion.io/x/cloudmux/pkg/multicloud"
    31  	"yunion.io/x/onecloud/pkg/util/billing"
    32  	"yunion.io/x/onecloud/pkg/util/rand"
    33  )
    34  
    35  type SReadOnlyDBInstanceIds struct {
    36  	ReadOnlyDBInstanceId []string
    37  }
    38  
    39  type SDBInstanceId struct {
    40  	DBInstanceId []string
    41  }
    42  
    43  type SDBInstanceExtra struct {
    44  	DBInstanceId SDBInstanceId
    45  }
    46  
    47  type SDBInstance struct {
    48  	multicloud.SDBInstanceBase
    49  
    50  	netInfo []SDBInstanceNetwork
    51  
    52  	region *SRegion
    53  
    54  	AccountMaxQuantity        int
    55  	AccountType               string
    56  	CanTempUpgrade            bool
    57  	Category                  string
    58  	AvailabilityValue         string
    59  	DBInstanceDescription     string
    60  	DBInstanceId              string
    61  	ConnectionMode            string
    62  	ConnectionString          string
    63  	ConnectionDomain          string
    64  	CurrentKernelVersion      string
    65  	DBInstanceCPU             int
    66  	CreateTime                time.Time
    67  	DBInstanceClass           string
    68  	DBInstanceClassType       string
    69  	DBInstanceNetType         string
    70  	DBInstanceStatus          string
    71  	DBInstanceType            string
    72  	DBInstanceDiskUsed        int64
    73  	DBInstanceStorage         int
    74  	DBInstanceStorageType     string
    75  	MasterInstanceId          string
    76  	DBInstanceMemory          int
    77  	DBMaxQuantity             int
    78  	IPType                    string
    79  	LatestKernelVersion       string
    80  	DispenseMode              string
    81  	Engine                    string
    82  	EngineVersion             string
    83  	ExpireTime                time.Time
    84  	InstanceNetworkType       string
    85  	LockMode                  string
    86  	LockReason                string
    87  	MutriORsignle             bool
    88  	MaintainTime              string
    89  	MaxConnections            int
    90  	MaxIOPS                   int
    91  	Port                      int
    92  	PayType                   TChargeType
    93  	ReadOnlyDBInstanceIds     SReadOnlyDBInstanceIds
    94  	RegionId                  string
    95  	ResourceGroupId           string
    96  	VSwitchId                 string
    97  	VpcCloudInstanceId        string
    98  	VpcId                     string
    99  	ZoneId                    string
   100  	Extra                     SDBInstanceExtra
   101  	SecurityIPList            string
   102  	SecurityIPMode            string
   103  	SupportCreateSuperAccount string
   104  	SupportUpgradeAccountType string
   105  	TempUpgradeTimeEnd        time.Time
   106  	TempUpgradeTimeStart      time.Time
   107  }
   108  
   109  func (rds *SDBInstance) GetName() string {
   110  	if len(rds.DBInstanceDescription) > 0 {
   111  		return rds.DBInstanceDescription
   112  	}
   113  	return rds.DBInstanceId
   114  }
   115  
   116  func (rds *SDBInstance) GetId() string {
   117  	return rds.DBInstanceId
   118  }
   119  
   120  func (rds *SDBInstance) GetGlobalId() string {
   121  	return rds.GetId()
   122  }
   123  
   124  // Creating	创建中
   125  // Running	使用中
   126  // Deleting	删除中
   127  // Rebooting	重启中
   128  // DBInstanceClassChanging	升降级中
   129  // TRANSING	迁移中
   130  // EngineVersionUpgrading	迁移版本中
   131  // TransingToOthers	迁移数据到其他RDS中
   132  // GuardDBInstanceCreating	生产灾备实例中
   133  // Restoring	备份恢复中
   134  // Importing	数据导入中
   135  // ImportingFromOthers	从其他RDS实例导入数据中
   136  // DBInstanceNetTypeChanging	内外网切换中
   137  // GuardSwitching	容灾切换中
   138  // INS_CLONING	实例克隆中
   139  func (rds *SDBInstance) GetStatus() string {
   140  	switch rds.DBInstanceStatus {
   141  	case "Creating", "GuardDBInstanceCreating", "DBInstanceNetTypeChanging", "GuardSwitching", "NET_CREATING", "NET_DELETING":
   142  		return api.DBINSTANCE_DEPLOYING
   143  	case "DBInstanceClassChanging":
   144  		return api.DBINSTANCE_CHANGE_CONFIG
   145  	case "Running":
   146  		return api.DBINSTANCE_RUNNING
   147  	case "Deleting":
   148  		return api.DBINSTANCE_DELETING
   149  	case "Rebooting":
   150  		return api.DBINSTANCE_REBOOTING
   151  	case "TRANSING", "EngineVersionUpgrading", "TransingToOthers":
   152  		return api.DBINSTANCE_MIGRATING
   153  	case "Restoring":
   154  		return api.DBINSTANCE_RESTORING
   155  	case "Importing", "ImportingFromOthers":
   156  		return api.DBINSTANCE_IMPORTING
   157  	case "INS_CLONING":
   158  		return api.DBINSTANCE_CLONING
   159  	default:
   160  		log.Errorf("Unknown dbinstance status %s", rds.DBInstanceStatus)
   161  		return api.DBINSTANCE_UNKNOWN
   162  	}
   163  }
   164  
   165  func (rds *SDBInstance) GetBillingType() string {
   166  	return convertChargeType(rds.PayType)
   167  }
   168  
   169  func (rds *SDBInstance) GetExpiredAt() time.Time {
   170  	return rds.ExpireTime
   171  }
   172  
   173  func (rds *SDBInstance) GetCreatedAt() time.Time {
   174  	return rds.CreateTime
   175  }
   176  
   177  func (rds *SDBInstance) GetStorageType() string {
   178  	return rds.DBInstanceStorageType
   179  }
   180  
   181  func (rds *SDBInstance) GetEngine() string {
   182  	switch rds.Engine {
   183  	case "MySQL":
   184  		return api.DBINSTANCE_TYPE_MYSQL
   185  	case "SQLServer":
   186  		return api.DBINSTANCE_TYPE_SQLSERVER
   187  	case "PostgreSQL":
   188  		return api.DBINSTANCE_TYPE_POSTGRESQL
   189  	case "PPAS":
   190  		return api.DBINSTANCE_TYPE_PPAS
   191  	case "MariaDB":
   192  		return api.DBINSTANCE_TYPE_MARIADB
   193  	}
   194  	return rds.Engine
   195  }
   196  
   197  func (rds *SDBInstance) GetEngineVersion() string {
   198  	return rds.EngineVersion
   199  }
   200  
   201  func (rds *SDBInstance) GetInstanceType() string {
   202  	return rds.DBInstanceClass
   203  }
   204  
   205  func (rds *SDBInstance) GetCategory() string {
   206  	switch rds.Category {
   207  	case "Basic":
   208  		return api.ALIYUN_DBINSTANCE_CATEGORY_BASIC
   209  	case "HighAvailability":
   210  		return api.ALIYUN_DBINSTANCE_CATEGORY_HA
   211  	case "AlwaysOn":
   212  		return api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON
   213  	case "Finance":
   214  		return api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE
   215  	}
   216  	return rds.Category
   217  }
   218  
   219  func (rds *SDBInstance) GetVcpuCount() int {
   220  	if rds.DBInstanceCPU == 0 {
   221  		rds.Refresh()
   222  	}
   223  	return rds.DBInstanceCPU
   224  }
   225  
   226  func (rds *SDBInstance) GetVmemSizeMB() int {
   227  	if rds.DBInstanceMemory == 0 {
   228  		rds.Refresh()
   229  	}
   230  	return rds.DBInstanceMemory
   231  }
   232  
   233  func (rds *SDBInstance) GetDiskSizeGB() int {
   234  	if rds.DBInstanceStorage == 0 {
   235  		rds.Refresh()
   236  	}
   237  	return rds.DBInstanceStorage
   238  }
   239  
   240  func (rds *SDBInstance) GetDiskSizeUsedMB() int {
   241  	if rds.DBInstanceDiskUsed == 0 {
   242  		rds.Refresh()
   243  	}
   244  	return int(rds.DBInstanceDiskUsed / 1024 / 1024)
   245  }
   246  
   247  func (rds *SDBInstance) GetPort() int {
   248  	if rds.Port == 0 {
   249  		rds.Refresh()
   250  	}
   251  	return rds.Port
   252  }
   253  
   254  func (rds *SDBInstance) GetMaintainTime() string {
   255  	return rds.MaintainTime
   256  }
   257  
   258  func (rds *SDBInstance) GetIVpcId() string {
   259  	return rds.VpcId
   260  }
   261  
   262  func (rds *SDBInstance) Refresh() error {
   263  	instance, err := rds.region.GetDBInstanceDetail(rds.DBInstanceId)
   264  	if err != nil {
   265  		return err
   266  	}
   267  	return jsonutils.Update(rds, instance)
   268  }
   269  
   270  func (rds *SDBInstance) getZoneId(index int) string {
   271  	zoneId := rds.getZone(index)
   272  	if len(zoneId) > 0 {
   273  		zone, err := rds.region.getZoneById(zoneId)
   274  		if err != nil {
   275  			log.Errorf("failed to found zone %s for rds %s", zoneId, rds.GetName())
   276  			return ""
   277  		}
   278  		return zone.GetGlobalId()
   279  	}
   280  	return ""
   281  }
   282  
   283  func (rds *SDBInstance) GetZone1Id() string {
   284  	return rds.getZoneId(1)
   285  }
   286  
   287  func (rds *SDBInstance) GetZone2Id() string {
   288  	return rds.getZoneId(2)
   289  }
   290  
   291  func (rds *SDBInstance) GetZone3Id() string {
   292  	return rds.getZoneId(3)
   293  }
   294  
   295  func (rds *SDBInstance) GetIOPS() int {
   296  	if rds.MaxIOPS == 0 {
   297  		rds.Refresh()
   298  	}
   299  	return rds.MaxIOPS
   300  }
   301  
   302  func (rds *SDBInstance) GetNetworkAddress() string {
   303  	return rds.ConnectionDomain
   304  }
   305  
   306  func (rds *SDBInstance) getZone(index int) string {
   307  	zoneStr := strings.Replace(rds.ZoneId, ")", "", -1)
   308  	zoneInfo := strings.Split(zoneStr, ",")
   309  	if len(zoneInfo) < index {
   310  		return ""
   311  	}
   312  	zone := zoneInfo[index-1]
   313  	zoneCode := zone[len(zone)-1]
   314  	if strings.HasPrefix(rds.ZoneId, fmt.Sprintf("%s-", rds.RegionId)) {
   315  		return fmt.Sprintf("%s-%s", rds.RegionId, string(zoneCode))
   316  	}
   317  	return fmt.Sprintf("%s%s", rds.RegionId, string(zoneCode))
   318  }
   319  
   320  func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) {
   321  	netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId)
   322  	if err != nil {
   323  		return nil, errors.Wrapf(err, "GetDBInstanceNetInfo")
   324  	}
   325  	networks := []cloudprovider.SDBInstanceNetwork{}
   326  	for _, net := range netInfo {
   327  		if net.IPType == "Private" {
   328  			network := cloudprovider.SDBInstanceNetwork{}
   329  			network.IP = net.IPAddress
   330  			network.NetworkId = net.VSwitchId
   331  			networks = append(networks, network)
   332  		}
   333  	}
   334  	return networks, nil
   335  }
   336  
   337  func (rds *SDBInstance) fetchNetInfo() error {
   338  	if len(rds.netInfo) > 0 {
   339  		return nil
   340  	}
   341  	netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId)
   342  	if err != nil {
   343  		return errors.Wrap(err, "GetDBInstanceNetInfo")
   344  	}
   345  	rds.netInfo = netInfo
   346  	return nil
   347  }
   348  
   349  func (rds *SDBInstance) GetInternalConnectionStr() string {
   350  	err := rds.fetchNetInfo()
   351  	if err != nil {
   352  		log.Errorf("failed to fetch netInfo error: %v", err)
   353  		return ""
   354  	}
   355  
   356  	str := ""
   357  	for _, net := range rds.netInfo {
   358  		if net.IPType != "Public" {
   359  			if net.IPType == "Private" {
   360  				return net.ConnectionString
   361  			} else if net.IPType == "Inner" {
   362  				str = net.ConnectionString
   363  			}
   364  		}
   365  	}
   366  	return str
   367  }
   368  
   369  func (rds *SDBInstance) GetConnectionStr() string {
   370  	err := rds.fetchNetInfo()
   371  	if err != nil {
   372  		log.Errorf("failed to fetch netInfo error: %v", err)
   373  		return ""
   374  	}
   375  
   376  	for _, net := range rds.netInfo {
   377  		if net.IPType == "Public" {
   378  			return net.ConnectionString
   379  		}
   380  	}
   381  	return ""
   382  }
   383  
   384  func (region *SRegion) GetDBInstances(ids []string, offset int, limit int) ([]SDBInstance, int, error) {
   385  	if limit > 50 || limit <= 0 {
   386  		limit = 50
   387  	}
   388  	params := make(map[string]string)
   389  	params["RegionId"] = region.RegionId
   390  	params["PageSize"] = fmt.Sprintf("%d", limit)
   391  	params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
   392  
   393  	body, err := region.rdsRequest("DescribeDBInstances", params)
   394  	if err != nil {
   395  		return nil, 0, errors.Wrapf(err, "GetDBInstances")
   396  	}
   397  	instances := []SDBInstance{}
   398  	err = body.Unmarshal(&instances, "Items", "DBInstance")
   399  	if err != nil {
   400  		return nil, 0, errors.Wrapf(err, "GetDBInstances.Unmarshal")
   401  	}
   402  	total, _ := body.Int("TotalRecordCount")
   403  	return instances, int(total), nil
   404  }
   405  
   406  func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) {
   407  	rds, err := region.GetDBInstanceDetail(instanceId)
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  	rds.region = region
   412  	return rds, nil
   413  }
   414  
   415  func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) {
   416  	instances := []SDBInstance{}
   417  	for {
   418  		part, total, err := region.GetDBInstances([]string{}, len(instances), 50)
   419  		if err != nil {
   420  			return nil, err
   421  		}
   422  		instances = append(instances, part...)
   423  		if len(instances) >= total {
   424  			break
   425  		}
   426  	}
   427  	idbinstances := []cloudprovider.ICloudDBInstance{}
   428  	for i := 0; i < len(instances); i++ {
   429  		instances[i].region = region
   430  		idbinstances = append(idbinstances, &instances[i])
   431  	}
   432  	return idbinstances, nil
   433  }
   434  
   435  func (region *SRegion) GetDBInstanceDetail(instanceId string) (*SDBInstance, error) {
   436  	if len(instanceId) == 0 {
   437  		return nil, cloudprovider.ErrNotFound
   438  	}
   439  	params := map[string]string{}
   440  	params["RegionId"] = region.RegionId
   441  	params["DBInstanceId"] = instanceId
   442  	body, err := region.rdsRequest("DescribeDBInstanceAttribute", params)
   443  	if err != nil {
   444  		return nil, errors.Wrapf(err, "GetDBInstanceDetail")
   445  	}
   446  	instances := []SDBInstance{}
   447  	err = body.Unmarshal(&instances, "Items", "DBInstanceAttribute")
   448  	if err != nil {
   449  		return nil, errors.Wrapf(err, "GetDBInstanceDetail.Unmarshal")
   450  	}
   451  	if len(instances) == 1 {
   452  		instances[0].region = region
   453  		return &instances[0], nil
   454  	}
   455  	if len(instances) == 0 {
   456  		return nil, cloudprovider.ErrNotFound
   457  	}
   458  	return nil, cloudprovider.ErrDuplicateId
   459  }
   460  
   461  func (region *SRegion) DeleteDBInstance(instanceId string) error {
   462  	params := map[string]string{}
   463  	params["RegionId"] = region.RegionId
   464  	params["DBInstanceId"] = instanceId
   465  	_, err := region.rdsRequest("DeleteDBInstance", params)
   466  	return err
   467  }
   468  
   469  type SDBInstanceWeight struct {
   470  }
   471  
   472  type SDBInstanceWeights struct {
   473  	DBInstanceWeight []SDBInstanceWeight
   474  }
   475  
   476  type SsecurityIPGroup struct {
   477  }
   478  
   479  type SSecurityIPGroups struct {
   480  	securityIPGroup []SsecurityIPGroup
   481  }
   482  
   483  type SDBInstanceNetwork struct {
   484  	ConnectionString     string
   485  	ConnectionStringType string
   486  	DBInstanceWeights    SDBInstanceWeights
   487  	IPAddress            string
   488  	IPType               string
   489  	Port                 int
   490  	SecurityIPGroups     SSecurityIPGroups
   491  	Upgradeable          string
   492  	VPCId                string
   493  	VSwitchId            string
   494  }
   495  
   496  func (network *SDBInstanceNetwork) GetGlobalId() string {
   497  	return network.IPAddress
   498  }
   499  
   500  func (network *SDBInstanceNetwork) GetINetworkId() string {
   501  	return network.VSwitchId
   502  }
   503  
   504  func (network *SDBInstanceNetwork) GetIP() string {
   505  	return network.IPAddress
   506  }
   507  
   508  func (region *SRegion) GetDBInstanceNetInfo(instanceId string) ([]SDBInstanceNetwork, error) {
   509  	params := map[string]string{}
   510  	params["RegionId"] = region.RegionId
   511  	params["DBInstanceId"] = instanceId
   512  	body, err := region.rdsRequest("DescribeDBInstanceNetInfo", params)
   513  	if err != nil {
   514  		return nil, errors.Wrapf(err, "GetDBInstanceNetwork")
   515  	}
   516  	networks := []SDBInstanceNetwork{}
   517  	err = body.Unmarshal(&networks, "DBInstanceNetInfos", "DBInstanceNetInfo")
   518  	if err != nil {
   519  		return nil, err
   520  	}
   521  	return networks, nil
   522  }
   523  
   524  func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) {
   525  	parameters, err := rds.region.GetDBInstanceParameters(rds.DBInstanceId)
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  	iparameters := []cloudprovider.ICloudDBInstanceParameter{}
   530  	for i := 0; i < len(parameters); i++ {
   531  		iparameters = append(iparameters, &parameters[i])
   532  	}
   533  	return iparameters, nil
   534  }
   535  
   536  func (self *SDBInstance) GetSecurityGroupIds() ([]string, error) {
   537  	return self.region.GetRdsSecgroupIds(self.DBInstanceId)
   538  }
   539  
   540  func (self *SDBInstance) SetSecurityGroups(ids []string) error {
   541  	return self.region.SetRdsSecgroups(self.DBInstanceId, ids)
   542  }
   543  
   544  func (self *SRegion) SetRdsSecgroups(rdsId string, secIds []string) error {
   545  	params := map[string]string{
   546  		"DBInstanceId":    rdsId,
   547  		"SecurityGroupId": strings.Join(secIds, ","),
   548  	}
   549  	_, err := self.rdsRequest("ModifySecurityGroupConfiguration", params)
   550  	if err != nil {
   551  		return errors.Wrapf(err, "ModifySecurityGroupConfiguration")
   552  	}
   553  	return nil
   554  }
   555  
   556  func (self *SRegion) GetRdsSecgroupIds(rdsId string) ([]string, error) {
   557  	params := map[string]string{
   558  		"DBInstanceId": rdsId,
   559  	}
   560  	resp, err := self.rdsRequest("DescribeSecurityGroupConfiguration", params)
   561  	if err != nil {
   562  		return nil, errors.Wrapf(err, "DescribeSecurityGroupConfiguration")
   563  	}
   564  	items := []struct {
   565  		NetworkType     string
   566  		SecurityGroupId string
   567  		RegionId        string
   568  	}{}
   569  	err = resp.Unmarshal(&items, "Items", "EcsSecurityGroupRelation")
   570  	if err != nil {
   571  		return nil, errors.Wrapf(err, "resp.Unmarshal")
   572  	}
   573  	ids := []string{}
   574  	for _, item := range items {
   575  		ids = append(ids, item.SecurityGroupId)
   576  	}
   577  	return ids, nil
   578  }
   579  
   580  func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) {
   581  	backups, err := region.GetIDBInstanceBackups()
   582  	if err != nil {
   583  		return nil, errors.Wrap(err, "region.GetIDBInstanceBackups")
   584  	}
   585  	for _, backup := range backups {
   586  		if backup.GetGlobalId() == backupId {
   587  			return backup, nil
   588  		}
   589  	}
   590  	return nil, cloudprovider.ErrNotFound
   591  }
   592  
   593  func (rds *SDBInstance) Reboot() error {
   594  	return rds.region.RebootDBInstance(rds.DBInstanceId)
   595  }
   596  
   597  func (rds *SDBInstance) Delete() error {
   598  	return rds.region.DeleteDBInstance(rds.DBInstanceId)
   599  }
   600  
   601  func (region *SRegion) RebootDBInstance(instanceId string) error {
   602  	params := map[string]string{}
   603  	params["RegionId"] = region.RegionId
   604  	params["DBInstanceId"] = instanceId
   605  	_, err := region.rdsRequest("RestartDBInstance", params)
   606  	return err
   607  }
   608  
   609  func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) {
   610  	databases := []SDBInstanceDatabase{}
   611  	for {
   612  		parts, total, err := rds.region.GetDBInstanceDatabases(rds.DBInstanceId, "", len(databases), 500)
   613  		if err != nil {
   614  			return nil, err
   615  		}
   616  		databases = append(databases, parts...)
   617  		if len(databases) >= total {
   618  			break
   619  		}
   620  	}
   621  
   622  	idatabase := []cloudprovider.ICloudDBInstanceDatabase{}
   623  	for i := 0; i < len(databases); i++ {
   624  		databases[i].instance = rds
   625  		idatabase = append(idatabase, &databases[i])
   626  	}
   627  	return idatabase, nil
   628  }
   629  
   630  func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) {
   631  	accounts := []SDBInstanceAccount{}
   632  	for {
   633  		parts, total, err := rds.region.GetDBInstanceAccounts(rds.DBInstanceId, len(accounts), 50)
   634  		if err != nil {
   635  			return nil, err
   636  		}
   637  		accounts = append(accounts, parts...)
   638  		if len(accounts) >= total {
   639  			break
   640  		}
   641  	}
   642  
   643  	iaccounts := []cloudprovider.ICloudDBInstanceAccount{}
   644  	for i := 0; i < len(accounts); i++ {
   645  		accounts[i].instance = rds
   646  		iaccounts = append(iaccounts, &accounts[i])
   647  	}
   648  	return iaccounts, nil
   649  }
   650  
   651  func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error {
   652  	return rds.region.ChangeDBInstanceConfig(rds.DBInstanceId, string(rds.PayType), desc)
   653  }
   654  
   655  func (region *SRegion) ChangeDBInstanceConfig(instanceId, payType string, desc *cloudprovider.SManagedDBInstanceChangeConfig) error {
   656  	params := map[string]string{
   657  		"RegionId":     region.RegionId,
   658  		"DBInstanceId": instanceId,
   659  		"PayType":      payType,
   660  	}
   661  	if len(desc.InstanceType) > 0 {
   662  		params["DBInstanceClass"] = desc.InstanceType
   663  	}
   664  	if desc.DiskSizeGB > 0 {
   665  		params["DBInstanceStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB)
   666  	}
   667  
   668  	_, err := region.rdsRequest("ModifyDBInstanceSpec", params)
   669  	if err != nil {
   670  		return errors.Wrap(err, "region.rdsRequest.ModifyDBInstanceSpec")
   671  	}
   672  	return nil
   673  }
   674  
   675  func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
   676  	params := map[string]string{
   677  		"RegionId":              region.RegionId,
   678  		"Engine":                desc.Engine,
   679  		"EngineVersion":         desc.EngineVersion,
   680  		"DBInstanceStorage":     fmt.Sprintf("%d", desc.DiskSizeGB),
   681  		"DBInstanceNetType":     "Intranet",
   682  		"PayType":               "Postpaid",
   683  		"SecurityIPList":        "0.0.0.0/0",
   684  		"DBInstanceDescription": desc.Name,
   685  		"InstanceNetworkType":   "VPC",
   686  		"VPCId":                 desc.VpcId,
   687  		"VSwitchId":             desc.NetworkId,
   688  		"DBInstanceStorageType": desc.StorageType,
   689  		"DBInstanceClass":       desc.InstanceType,
   690  		"ZoneId":                desc.ZoneId,
   691  		"ClientToken":           utils.GenRequestId(20),
   692  	}
   693  	switch desc.Category {
   694  	case api.ALIYUN_DBINSTANCE_CATEGORY_HA:
   695  		params["Category"] = "HighAvailability"
   696  	case api.ALIYUN_DBINSTANCE_CATEGORY_BASIC:
   697  		params["Category"] = "Basic"
   698  	case api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON:
   699  		params["Category"] = "AlwaysOn"
   700  	case api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE:
   701  		params["Category"] = "Finance"
   702  	}
   703  
   704  	if len(desc.Address) > 0 {
   705  		params["PrivateIpAddress"] = desc.Address
   706  	}
   707  	if len(desc.ProjectId) > 0 {
   708  		params["ResourceGroupId"] = desc.ProjectId
   709  	}
   710  	if desc.BillingCycle != nil {
   711  		params["PayType"] = "Prepaid"
   712  		if desc.BillingCycle.GetYears() > 0 {
   713  			params["Period"] = "Year"
   714  			params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetYears())
   715  		} else {
   716  			params["Period"] = "Month"
   717  			params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetMonths())
   718  		}
   719  		params["AutoRenew"] = "False"
   720  		if desc.BillingCycle.AutoRenew {
   721  			params["AutoRenew"] = "True"
   722  		}
   723  	}
   724  
   725  	action := "CreateDBInstance"
   726  	if len(desc.MasterInstanceId) > 0 {
   727  		action = "CreateReadOnlyDBInstance"
   728  		params["DBInstanceId"] = desc.MasterInstanceId
   729  	}
   730  
   731  	resp, err := region.rdsRequest(action, params)
   732  	if err != nil {
   733  		return nil, errors.Wrapf(err, "rdsRequest")
   734  	}
   735  	instanceId, err := resp.GetString("DBInstanceId")
   736  	if err != nil {
   737  		return nil, errors.Wrap(err, `resp.GetString("DBInstanceId")`)
   738  	}
   739  	region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", instanceId, desc.Tags, false)
   740  	return region.GetIDBInstanceById(instanceId)
   741  }
   742  
   743  func (rds *SDBInstance) GetMasterInstanceId() string {
   744  	if len(rds.MasterInstanceId) > 0 {
   745  		return rds.MasterInstanceId
   746  	}
   747  	rds.Refresh()
   748  	return rds.MasterInstanceId
   749  }
   750  
   751  func (region *SRegion) OpenPublicConnection(instanceId string) error {
   752  	rds, err := region.GetDBInstanceDetail(instanceId)
   753  	if err != nil {
   754  		return err
   755  	}
   756  	params := map[string]string{
   757  		"RegionId":               region.RegionId,
   758  		"ConnectionStringPrefix": rds.DBInstanceId + rand.String(3),
   759  		"DBInstanceId":           rds.DBInstanceId,
   760  		"Port":                   fmt.Sprintf("%d", rds.Port),
   761  	}
   762  	_, err = rds.region.rdsRequest("AllocateInstancePublicConnection", params)
   763  	if err != nil {
   764  		return errors.Wrap(err, "rdsRequest(AllocateInstancePublicConnection)")
   765  	}
   766  	return nil
   767  }
   768  
   769  func (rds *SDBInstance) OpenPublicConnection() error {
   770  	if url := rds.GetConnectionStr(); len(url) == 0 {
   771  		err := rds.region.OpenPublicConnection(rds.DBInstanceId)
   772  		if err != nil {
   773  			return err
   774  		}
   775  		rds.netInfo = []SDBInstanceNetwork{}
   776  	}
   777  	return nil
   778  }
   779  
   780  func (region *SRegion) ClosePublicConnection(instanceId string) error {
   781  	netInfo, err := region.GetDBInstanceNetInfo(instanceId)
   782  	if err != nil {
   783  		return errors.Wrap(err, "GetDBInstanceNetInfo")
   784  	}
   785  
   786  	for _, net := range netInfo {
   787  		if net.IPType == "Public" {
   788  			params := map[string]string{
   789  				"RegionId":                region.RegionId,
   790  				"CurrentConnectionString": net.ConnectionString,
   791  				"DBInstanceId":            instanceId,
   792  			}
   793  			_, err = region.rdsRequest("ReleaseInstancePublicConnection", params)
   794  			if err != nil {
   795  				return errors.Wrap(err, "rdsRequest(ReleaseInstancePublicConnection)")
   796  			}
   797  
   798  		}
   799  	}
   800  	return nil
   801  
   802  }
   803  
   804  func (rds *SDBInstance) ClosePublicConnection() error {
   805  	return rds.region.ClosePublicConnection(rds.DBInstanceId)
   806  }
   807  
   808  func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error {
   809  	if len(conf.OriginDBInstanceExternalId) == 0 {
   810  		conf.OriginDBInstanceExternalId = rds.DBInstanceId
   811  	}
   812  	return rds.region.RecoveryDBInstanceFromBackup(conf.OriginDBInstanceExternalId, rds.DBInstanceId, conf.BackupId, conf.Databases)
   813  }
   814  
   815  func (region *SRegion) RecoveryDBInstanceFromBackup(srcId, destId string, backupId string, databases map[string]string) error {
   816  	params := map[string]string{
   817  		"RegionId":           region.RegionId,
   818  		"DBInstanceId":       srcId,
   819  		"TargetDBInstanceId": destId,
   820  		"BackupId":           backupId,
   821  		"DbNames":            jsonutils.Marshal(databases).String(),
   822  	}
   823  	_, err := region.rdsRequest("RecoveryDBInstance", params)
   824  	if err != nil {
   825  		return errors.Wrap(err, "rdsRequest.RecoveryDBInstance")
   826  	}
   827  	return nil
   828  }
   829  
   830  func (rds *SDBInstance) GetProjectId() string {
   831  	return rds.ResourceGroupId
   832  }
   833  
   834  func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error {
   835  	return rds.region.CreateDBInstanceDatabae(rds.DBInstanceId, conf.CharacterSet, conf.Name, conf.Description)
   836  }
   837  
   838  func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error {
   839  	return rds.region.CreateDBInstanceAccount(rds.DBInstanceId, conf.Name, conf.Password, conf.Description)
   840  }
   841  
   842  func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error {
   843  	return rds.region.RenewInstance(rds.DBInstanceId, bc)
   844  }
   845  
   846  func (rds *SDBInstance) SetAutoRenew(bc billing.SBillingCycle) error {
   847  	month := 1
   848  	if bc.GetMonths() > 0 {
   849  		month = bc.GetMonths()
   850  	}
   851  	return rds.region.ModifyInstanceAutoRenewalAttribute(rds.DBInstanceId, month, bc.AutoRenew)
   852  }
   853  
   854  func (region *SRegion) ModifyInstanceAutoRenewalAttribute(rdsId string, month int, autoRenew bool) error {
   855  	params := map[string]string{
   856  		"RegionId":     region.RegionId,
   857  		"DBInstanceId": rdsId,
   858  		"AutoRenew":    "False",
   859  		"ClientToken":  utils.GenRequestId(20),
   860  	}
   861  	if autoRenew {
   862  		params["AutoRenew"] = "True"
   863  		params["Duration"] = fmt.Sprintf("%d", month)
   864  	}
   865  	_, err := region.rdsRequest("ModifyInstanceAutoRenewalAttribute", params)
   866  	if err != nil {
   867  		return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute")
   868  	}
   869  	return nil
   870  }
   871  
   872  func (region *SRegion) RenewDBInstance(instanceId string, bc billing.SBillingCycle) error {
   873  	params := map[string]string{
   874  		"DBInstanceId": instanceId,
   875  		"Period":       fmt.Sprintf("%d", bc.GetMonths()),
   876  		"ClientToken":  utils.GenRequestId(20),
   877  	}
   878  	_, err := region.rdsRequest("RenewInstance", params)
   879  	return err
   880  }
   881  
   882  func (self *SDBInstance) GetTags() (map[string]string, error) {
   883  	_, tags, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId)
   884  	if err != nil {
   885  		return nil, errors.Wrapf(err, "ListTags")
   886  	}
   887  	tagMaps := map[string]string{}
   888  	for k, v := range tags {
   889  		tagMaps[strings.ToLower(k)] = v
   890  	}
   891  	return tagMaps, nil
   892  }
   893  
   894  func (self *SDBInstance) GetSysTags() map[string]string {
   895  	tags, _, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId)
   896  	if err != nil {
   897  		return nil
   898  	}
   899  	tagMaps := map[string]string{}
   900  	for k, v := range tags {
   901  		tagMaps[strings.ToLower(k)] = v
   902  	}
   903  	return tagMaps
   904  }
   905  
   906  func (rds *SDBInstance) SetTags(tags map[string]string, replace bool) error {
   907  	return rds.region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", rds.GetId(), tags, replace)
   908  }