yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/elasticcache_instance.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  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/aokoli/goutils"
    24  	"github.com/pkg/errors"
    25  
    26  	"yunion.io/x/jsonutils"
    27  	"yunion.io/x/log"
    28  
    29  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    30  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    31  	"yunion.io/x/cloudmux/pkg/multicloud"
    32  	"yunion.io/x/onecloud/pkg/util/billing"
    33  )
    34  
    35  // https://help.aliyun.com/document_detail/60933.html?spm=a2c4g.11186623.6.726.38f82ca9U1Gtxw
    36  type SElasticcache struct {
    37  	multicloud.SElasticcacheBase
    38  	AliyunTags
    39  
    40  	region    *SRegion
    41  	attribute *SElasticcacheAttribute
    42  	netinfo   []SNetInfo
    43  
    44  	Config              string      `json:"Config"`
    45  	HasRenewChangeOrder bool        `json:"HasRenewChangeOrder"`
    46  	InstanceID          string      `json:"InstanceId"`
    47  	UserName            string      `json:"UserName"`
    48  	ArchitectureType    string      `json:"ArchitectureType"`
    49  	ZoneID              string      `json:"ZoneId"`
    50  	PrivateIP           string      `json:"PrivateIp"`
    51  	VSwitchID           string      `json:"VSwitchId"`
    52  	VpcID               string      `json:"VpcId"`
    53  	NetworkType         string      `json:"NetworkType"`
    54  	Qps                 int64       `json:"QPS"`
    55  	PackageType         string      `json:"PackageType"`
    56  	IsRDS               bool        `json:"IsRds"`
    57  	EngineVersion       string      `json:"EngineVersion"`
    58  	ConnectionDomain    string      `json:"ConnectionDomain"`
    59  	InstanceName        string      `json:"InstanceName"`
    60  	ReplacateID         string      `json:"ReplacateId"`
    61  	Bandwidth           int64       `json:"Bandwidth"`
    62  	ChargeType          TChargeType `json:"ChargeType"`
    63  	InstanceType        string      `json:"InstanceType"`
    64  	InstanceStatus      string      `json:"InstanceStatus"`
    65  	Port                int         `json:"Port"`
    66  	InstanceClass       string      `json:"InstanceClass"`
    67  	CreateTime          time.Time   `json:"CreateTime"`
    68  	EndTime             time.Time   `json:"EndTime"`
    69  	RegionID            string      `json:"RegionId"`
    70  	NodeType            string      `json:"NodeType"`
    71  	CapacityMB          int         `json:"Capacity"`
    72  	Connections         int64       `json:"Connections"`
    73  	ResourceGroupId     string      `json:"ResourceGroupId"`
    74  }
    75  
    76  type SElasticcacheAttribute struct {
    77  	Config              string      `json:"Config"`
    78  	HasRenewChangeOrder string      `json:"HasRenewChangeOrder"`
    79  	InstanceID          string      `json:"InstanceId"`
    80  	ZoneID              string      `json:"ZoneId"`
    81  	ArchitectureType    string      `json:"ArchitectureType"`
    82  	PrivateIP           string      `json:"PrivateIp"`
    83  	VSwitchID           string      `json:"VSwitchId"`
    84  	Engine              string      `json:"Engine"`
    85  	VpcID               string      `json:"VpcId"`
    86  	NetworkType         string      `json:"NetworkType"`
    87  	Qps                 int64       `json:"QPS"`
    88  	PackageType         string      `json:"PackageType"`
    89  	ReplicaID           string      `json:"ReplicaId"`
    90  	IsRDS               bool        `json:"IsRds"`
    91  	MaintainStartTime   string      `json:"MaintainStartTime"`
    92  	VpcAuthMode         string      `json:"VpcAuthMode"`
    93  	ConnectionDomain    string      `json:"ConnectionDomain"`
    94  	EngineVersion       string      `json:"EngineVersion"`
    95  	InstanceName        string      `json:"InstanceName"`
    96  	Bandwidth           int64       `json:"Bandwidth"`
    97  	ChargeType          TChargeType `json:"ChargeType"`
    98  	AuditLogRetention   string      `json:"AuditLogRetention"`
    99  	MaintainEndTime     string      `json:"MaintainEndTime"`
   100  	ReplicationMode     string      `json:"ReplicationMode"`
   101  	InstanceType        string      `json:"InstanceType"`
   102  	InstanceStatus      string      `json:"InstanceStatus"`
   103  	Port                int64       `json:"Port"`
   104  	InstanceClass       string      `json:"InstanceClass"`
   105  	CreateTime          time.Time   `json:"CreateTime"`
   106  	NodeType            string      `json:"NodeType"`
   107  	RegionID            string      `json:"RegionId"`
   108  	AvailabilityValue   string      `json:"AvailabilityValue"`
   109  	CapacityMB          int         `json:"Capacity"`
   110  	Connections         int64       `json:"Connections"`
   111  	SecurityIPList      string      `json:"SecurityIPList"`
   112  }
   113  
   114  type SNetInfo struct {
   115  	ConnectionString  string  `json:"ConnectionString"`
   116  	Port              string  `json:"Port"`
   117  	DBInstanceNetType string  `json:"DBInstanceNetType"`
   118  	VPCID             string  `json:"VPCId"`
   119  	VPCInstanceID     string  `json:"VPCInstanceId"`
   120  	IPAddress         string  `json:"IPAddress"`
   121  	IPType            string  `json:"IPType"`
   122  	Upgradeable       string  `json:"Upgradeable"`
   123  	ExpiredTime       *string `json:"ExpiredTime,omitempty"`
   124  }
   125  
   126  func (self *SElasticcache) GetId() string {
   127  	return self.InstanceID
   128  }
   129  
   130  func (self *SElasticcache) GetName() string {
   131  	if len(self.InstanceName) > 0 {
   132  		return self.InstanceName
   133  	}
   134  
   135  	return self.InstanceID
   136  }
   137  
   138  func (self *SElasticcache) GetGlobalId() string {
   139  	return self.GetId()
   140  }
   141  
   142  func (self *SElasticcache) GetStatus() string {
   143  	switch self.InstanceStatus {
   144  	case "Normal":
   145  		return api.ELASTIC_CACHE_STATUS_RUNNING
   146  	case "Creating":
   147  		return api.ELASTIC_CACHE_STATUS_DEPLOYING
   148  	case "Changing":
   149  		return api.ELASTIC_CACHE_STATUS_CHANGING
   150  	case "Inactive":
   151  		return api.ELASTIC_CACHE_STATUS_INACTIVE
   152  	case "Flushing":
   153  		return api.ELASTIC_CACHE_STATUS_FLUSHING
   154  	case "Released":
   155  		return api.ELASTIC_CACHE_STATUS_RELEASED
   156  	case "Transforming":
   157  		return api.ELASTIC_CACHE_STATUS_TRANSFORMING
   158  	case "Unavailable":
   159  		return api.ELASTIC_CACHE_STATUS_UNAVAILABLE
   160  	case "Error":
   161  		return api.ELASTIC_CACHE_STATUS_ERROR
   162  	case "Migrating":
   163  		return api.ELASTIC_CACHE_STATUS_MIGRATING
   164  	case "BackupRecovering":
   165  		return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING
   166  	case "MinorVersionUpgrading":
   167  		return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING
   168  	case "NetworkModifying":
   169  		return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING
   170  	case "SSLModifying":
   171  		return api.ELASTIC_CACHE_STATUS_SSLMODIFYING
   172  	case "MajorVersionUpgrading":
   173  		return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING
   174  	default:
   175  		return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING
   176  	}
   177  }
   178  
   179  func (self *SElasticcache) Refresh() error {
   180  	cache, err := self.region.GetElasticCacheById(self.GetId())
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	err = jsonutils.Update(self, cache)
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	return nil
   191  }
   192  
   193  func (self *SElasticcache) GetBillingType() string {
   194  	return convertChargeType(self.ChargeType)
   195  }
   196  
   197  func (self *SElasticcache) GetCreatedAt() time.Time {
   198  	return self.CreateTime
   199  }
   200  
   201  func (self *SElasticcache) GetExpiredAt() time.Time {
   202  	return convertExpiredAt(self.EndTime)
   203  }
   204  
   205  func (self *SElasticcache) GetInstanceType() string {
   206  	return self.InstanceClass
   207  }
   208  
   209  func (self *SElasticcache) GetCapacityMB() int {
   210  	return self.CapacityMB
   211  }
   212  
   213  func (self *SElasticcache) GetArchType() string {
   214  	switch self.ArchitectureType {
   215  	case "rwsplit":
   216  		return api.ELASTIC_CACHE_ARCH_TYPE_RWSPLIT
   217  	case "cluster":
   218  		return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER
   219  	case "standard":
   220  		if self.NodeType == "single" {
   221  			return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE
   222  		} else if self.NodeType == "double" {
   223  			return api.ELASTIC_CACHE_ARCH_TYPE_MASTER
   224  		}
   225  	}
   226  
   227  	return ""
   228  }
   229  
   230  func (self *SElasticcache) GetNodeType() string {
   231  	return self.NodeType
   232  }
   233  
   234  func (self *SElasticcache) GetEngine() string {
   235  	return self.InstanceType
   236  }
   237  
   238  func (self *SElasticcache) GetEngineVersion() string {
   239  	return self.EngineVersion
   240  }
   241  
   242  func (self *SElasticcache) GetVpcId() string {
   243  	return self.VpcID
   244  }
   245  
   246  func (self *SElasticcache) GetZoneId() string {
   247  	zoneId := transZoneIdToEcsZoneId(self.region, "redis", self.ZoneID)
   248  	zone, err := self.region.getZoneById(fetchMasterZoneId(zoneId))
   249  	if err != nil {
   250  		log.Errorf("failed to find zone for elasticcache %s error: %v", self.GetId(), err)
   251  		return ""
   252  	}
   253  
   254  	return zone.GetGlobalId()
   255  }
   256  
   257  func (self *SElasticcache) GetNetworkType() string {
   258  	switch self.NetworkType {
   259  	case "VPC":
   260  		return api.LB_NETWORK_TYPE_VPC
   261  	case "CLASSIC":
   262  		return api.LB_NETWORK_TYPE_CLASSIC
   263  	default:
   264  		return api.LB_NETWORK_TYPE_VPC
   265  	}
   266  }
   267  
   268  func (self *SElasticcache) GetNetworkId() string {
   269  	return self.VSwitchID
   270  }
   271  
   272  func (self *SElasticcache) GetPrivateDNS() string {
   273  	return self.ConnectionDomain
   274  }
   275  
   276  func (self *SElasticcache) GetPrivateIpAddr() string {
   277  	return self.PrivateIP
   278  }
   279  
   280  func (self *SElasticcache) GetPrivateConnectPort() int {
   281  	return self.Port
   282  }
   283  
   284  func (self *SElasticcache) GetPublicDNS() string {
   285  	pub, err := self.GetPublicNetInfo()
   286  	if err != nil {
   287  		log.Errorf("SElasticcache.GetPublicDNS %s", err)
   288  		return ""
   289  	}
   290  
   291  	if pub != nil {
   292  		return pub.ConnectionString
   293  	}
   294  
   295  	return ""
   296  }
   297  
   298  func (self *SElasticcache) GetPublicIpAddr() string {
   299  	pub, err := self.GetPublicNetInfo()
   300  	if err != nil {
   301  		log.Errorf("SElasticcache.GetPublicIpAddr %s", err)
   302  	}
   303  
   304  	if pub != nil {
   305  		return pub.IPAddress
   306  	}
   307  
   308  	return ""
   309  }
   310  
   311  func (self *SElasticcache) GetPublicConnectPort() int {
   312  	pub, err := self.GetPublicNetInfo()
   313  	if err != nil {
   314  		log.Errorf("SElasticcache.GetPublicConnectPort %s", err)
   315  	}
   316  
   317  	if pub != nil {
   318  		port, _ := strconv.Atoi(pub.Port)
   319  		return port
   320  	}
   321  
   322  	return 0
   323  }
   324  
   325  func (self *SElasticcache) GetMaintainStartTime() string {
   326  	attr, err := self.GetAttribute()
   327  	if err != nil {
   328  		log.Errorf("SElasticcache.GetMaintainStartTime %s", err)
   329  	}
   330  
   331  	if attr != nil {
   332  		return attr.MaintainStartTime
   333  	}
   334  
   335  	return ""
   336  }
   337  
   338  func (self *SElasticcache) GetBandwidth() int {
   339  	return int(self.Bandwidth)
   340  }
   341  
   342  func (self *SElasticcache) GetConnections() int {
   343  	attr, err := self.GetAttribute()
   344  	if err != nil {
   345  		log.Errorf("SElasticcache.GetMaintainEndTime %s", err)
   346  	}
   347  
   348  	if attr != nil {
   349  		return int(attr.Connections)
   350  	}
   351  	return 0
   352  }
   353  
   354  func (self *SElasticcache) GetMaintainEndTime() string {
   355  	attr, err := self.GetAttribute()
   356  	if err != nil {
   357  		log.Errorf("SElasticcache.GetMaintainEndTime %s", err)
   358  	}
   359  
   360  	if attr != nil {
   361  		return attr.MaintainEndTime
   362  	}
   363  
   364  	return ""
   365  }
   366  
   367  func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) {
   368  	accounts, err := self.region.GetElasticCacheAccounts(self.GetId())
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  
   373  	iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts))
   374  	for i := range accounts {
   375  		accounts[i].cacheDB = self
   376  		iaccounts[i] = &accounts[i]
   377  	}
   378  
   379  	return iaccounts, nil
   380  }
   381  
   382  func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) {
   383  	account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName)
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  
   388  	account.cacheDB = self
   389  	return account, nil
   390  }
   391  
   392  func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) {
   393  	acls, err := self.region.GetElasticCacheAcls(self.GetId())
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  
   398  	iacls := make([]cloudprovider.ICloudElasticcacheAcl, len(acls))
   399  	for i := range acls {
   400  		acls[i].cacheDB = self
   401  		iacls[i] = &acls[i]
   402  	}
   403  
   404  	return iacls, nil
   405  }
   406  
   407  func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) {
   408  	start := self.CreateTime.Format("2006-01-02T15:04Z")
   409  	end := time.Now().Format("2006-01-02T15:04Z")
   410  	backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end)
   411  	if err != nil {
   412  		return nil, err
   413  	}
   414  
   415  	ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups))
   416  	for i := range backups {
   417  		backups[i].cacheDB = self
   418  		ibackups[i] = &backups[i]
   419  	}
   420  
   421  	return ibackups, nil
   422  }
   423  
   424  func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) {
   425  	parameters, err := self.region.GetElasticCacheParameters(self.GetId())
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  
   430  	iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters))
   431  	for i := range parameters {
   432  		parameters[i].cacheDB = self
   433  		iparameters[i] = &parameters[i]
   434  	}
   435  
   436  	return iparameters, nil
   437  }
   438  
   439  func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) {
   440  	if self.attribute != nil {
   441  		return self.attribute, nil
   442  	}
   443  
   444  	params := make(map[string]string)
   445  	params["RegionId"] = self.region.RegionId
   446  	params["InstanceId"] = self.GetId()
   447  
   448  	rets := []SElasticcacheAttribute{}
   449  	err := DoListAll(self.region.kvsRequest, "DescribeInstanceAttribute", params, []string{"Instances", "DBInstanceAttribute"}, &rets)
   450  	if err != nil {
   451  		return nil, errors.Wrap(err, "elasticcache.GetAttribute")
   452  	}
   453  
   454  	count := len(rets)
   455  	if count >= 1 {
   456  		self.attribute = &rets[0]
   457  		return self.attribute, nil
   458  	} else {
   459  		return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId())
   460  	}
   461  }
   462  
   463  func (self *SElasticcache) GetNetInfo() ([]SNetInfo, error) {
   464  	params := make(map[string]string)
   465  	params["RegionId"] = self.region.RegionId
   466  	params["InstanceId"] = self.GetId()
   467  
   468  	rets := []SNetInfo{}
   469  	err := DoListAll(self.region.kvsRequest, "DescribeDBInstanceNetInfo", params, []string{"NetInfoItems", "InstanceNetInfo"}, &rets)
   470  	if err != nil {
   471  		return nil, errors.Wrap(err, "elasticcache.GetNetInfo")
   472  	}
   473  
   474  	self.netinfo = rets
   475  	return self.netinfo, nil
   476  }
   477  
   478  // https://help.aliyun.com/document_detail/66742.html?spm=a2c4g.11186623.6.731.54c123d2P02qhk
   479  func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) {
   480  	nets, err := self.GetNetInfo()
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  
   485  	for i := range nets {
   486  		if nets[i].IPType == "Public" {
   487  			return &nets[i], nil
   488  		}
   489  	}
   490  
   491  	return nil, nil
   492  }
   493  
   494  func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, error) {
   495  	params := make(map[string]string)
   496  	params["RegionId"] = self.RegionId
   497  	if instanceIds != nil && len(instanceIds) > 0 {
   498  		params["InstanceIds"] = strings.Join(instanceIds, ",")
   499  	}
   500  
   501  	ret := []SElasticcache{}
   502  	err := DoListAll(self.kvsRequest, "DescribeInstances", params, []string{"Instances", "KVStoreInstance"}, &ret)
   503  	if err != nil {
   504  		return nil, errors.Wrap(err, "region.GetElasticCaches")
   505  	}
   506  
   507  	for i := range ret {
   508  		ret[i].region = self
   509  	}
   510  
   511  	return ret, nil
   512  }
   513  
   514  func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, error) {
   515  	caches, err := self.GetElasticCaches([]string{instanceId})
   516  	if err != nil {
   517  		return nil, errors.Wrapf(err, "region.GetElasticCacheById %s", instanceId)
   518  	}
   519  
   520  	if len(caches) == 1 {
   521  		return &caches[0], nil
   522  	} else if len(caches) == 0 {
   523  		return nil, cloudprovider.ErrNotFound
   524  	} else {
   525  		return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches))
   526  	}
   527  }
   528  
   529  func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) {
   530  	ec, err := self.GetElasticCacheById(id)
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  
   535  	return ec, nil
   536  }
   537  
   538  // https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg
   539  func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) {
   540  	params := make(map[string]string)
   541  	params["RegionId"] = self.RegionId
   542  	params["InstanceId"] = instanceId
   543  
   544  	ret := []SElasticcacheAccount{}
   545  	err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret)
   546  	if err != nil {
   547  		return nil, errors.Wrap(err, "region.GetElasticCacheAccounts")
   548  	}
   549  
   550  	return ret, nil
   551  }
   552  
   553  func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) {
   554  	params := make(map[string]string)
   555  	params["RegionId"] = self.RegionId
   556  	params["InstanceId"] = instanceId
   557  	params["AccountName"] = accountName
   558  
   559  	ret := []SElasticcacheAccount{}
   560  	err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret)
   561  	if err != nil {
   562  		return nil, errors.Wrap(err, "region.GetElasticCacheAccounts")
   563  	}
   564  
   565  	if len(ret) == 1 {
   566  		return &ret[0], nil
   567  	} else if len(ret) == 0 {
   568  		return nil, cloudprovider.ErrNotFound
   569  	} else {
   570  		return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName")
   571  	}
   572  }
   573  
   574  // https://help.aliyun.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS
   575  func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) {
   576  	params := make(map[string]string)
   577  	params["RegionId"] = self.RegionId
   578  	params["InstanceId"] = instanceId
   579  
   580  	ret := []SElasticcacheAcl{}
   581  	err := DoListAll(self.kvsRequest, "DescribeSecurityIps", params, []string{"SecurityIpGroups", "SecurityIpGroup"}, &ret)
   582  	if err != nil {
   583  		return nil, errors.Wrap(err, "region.GetElasticCacheAcls")
   584  	}
   585  
   586  	return ret, nil
   587  }
   588  
   589  // https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.754.10613852qAbEQV
   590  func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) {
   591  	params := make(map[string]string)
   592  	params["RegionId"] = self.RegionId
   593  	params["InstanceId"] = instanceId
   594  	params["StartTime"] = startTime
   595  	params["EndTime"] = endTime
   596  
   597  	ret := []SElasticcacheBackup{}
   598  	err := DoListAll(self.kvsRequest, "DescribeBackups", params, []string{"Backups", "Backup"}, &ret)
   599  	if err != nil {
   600  		return nil, errors.Wrap(err, "region.GetElasticCacheBackups")
   601  	}
   602  
   603  	return ret, nil
   604  }
   605  
   606  // https://help.aliyun.com/document_detail/93078.html?spm=a2c4g.11186623.6.769.58011975YYL5Gl
   607  func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) {
   608  	params := make(map[string]string)
   609  	params["RegionId"] = self.RegionId
   610  	params["DBInstanceId"] = instanceId
   611  
   612  	ret := []SElasticcacheParameter{}
   613  	err := DoListAll(self.kvsRequest, "DescribeParameters", params, []string{"RunningParameters", "Parameter"}, &ret)
   614  	if err != nil {
   615  		return nil, errors.Wrap(err, "region.GetElasticCacheParameters")
   616  	}
   617  
   618  	return ret, nil
   619  }
   620  
   621  // https://help.aliyun.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb
   622  func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) {
   623  	params := make(map[string]string)
   624  	params["RegionId"] = self.RegionId
   625  	params["InstanceClass"] = ec.InstanceType
   626  	params["InstanceName"] = ec.InstanceName
   627  	params["InstanceType"] = ec.Engine
   628  	params["EngineVersion"] = ec.EngineVersion
   629  
   630  	if len(ec.Password) > 0 {
   631  		params["UserName"] = ec.UserName
   632  		params["Password"] = ec.Password
   633  	}
   634  
   635  	if len(ec.ZoneIds) > 0 {
   636  		params["ZoneId"] = transZoneIdFromEcsZoneId(self, "redis", ec.ZoneIds[0])
   637  	}
   638  
   639  	if len(ec.PrivateIpAddress) > 0 {
   640  		params["PrivateIpAddress"] = ec.PrivateIpAddress
   641  	}
   642  
   643  	if len(ec.NodeType) > 0 {
   644  		switch ec.NodeType {
   645  		case "single":
   646  			params["NodeType"] = "STAND_ALONE"
   647  		case "double":
   648  			params["NodeType"] = "MASTER_SLAVE"
   649  		}
   650  	}
   651  
   652  	if len(ec.ProjectId) > 0 {
   653  		params["ResourceGroupId"] = ec.ProjectId
   654  	}
   655  
   656  	params["NetworkType"] = ec.NetworkType
   657  	params["VpcId"] = ec.VpcId
   658  	params["VSwitchId"] = ec.NetworkId
   659  	params["ChargeType"] = "PostPaid"
   660  	if ec.BillingCycle != nil {
   661  		params["ChargeType"] = "PrePaid"
   662  		if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() <= 9 {
   663  			params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths())
   664  		} else if ec.BillingCycle.GetMonths() == 12 || ec.BillingCycle.GetMonths() == 24 || ec.BillingCycle.GetMonths() == 36 {
   665  			params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths())
   666  		} else {
   667  			return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or  year(1~3)")
   668  		}
   669  	}
   670  
   671  	ret := &SElasticcache{region: self}
   672  	err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret)
   673  	if err != nil {
   674  		return nil, errors.Wrap(err, "region.CreateIElasticcaches")
   675  	}
   676  	self.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", ret.InstanceID, ec.Tags, true)
   677  	return ret, nil
   678  }
   679  
   680  // https://help.aliyun.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6
   681  func (self *SElasticcache) Restart() error {
   682  	params := make(map[string]string)
   683  	params["InstanceId"] = self.GetId()
   684  	params["EffectiveTime"] = "0" // 立即重启
   685  
   686  	err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil)
   687  	if err != nil {
   688  		return errors.Wrap(err, "elasticcache.Restart")
   689  	}
   690  
   691  	return nil
   692  }
   693  
   694  // https://help.aliyun.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0
   695  func (self *SElasticcache) Delete() error {
   696  	params := make(map[string]string)
   697  	params["InstanceId"] = self.GetId()
   698  
   699  	err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil)
   700  	if err != nil {
   701  		return errors.Wrap(err, "elasticcache.Delete")
   702  	}
   703  
   704  	return nil
   705  }
   706  
   707  // https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw
   708  func (self *SElasticcache) ChangeInstanceSpec(spec string) error {
   709  	params := make(map[string]string)
   710  	params["InstanceId"] = self.GetId()
   711  	params["InstanceClass"] = strings.Split(spec, ":")[0]
   712  	params["AutoPay"] = "true" // 自动付款
   713  
   714  	err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil)
   715  	if err != nil {
   716  		return errors.Wrap(err, "elasticcache.ChangeInstanceSpec")
   717  	}
   718  
   719  	return nil
   720  }
   721  
   722  // https://help.aliyun.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86
   723  func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error {
   724  	params := make(map[string]string)
   725  	params["InstanceId"] = self.GetId()
   726  	params["MaintainStartTime"] = maintainStartTime
   727  	params["MaintainEndTime"] = maintainEndTime
   728  
   729  	err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil)
   730  	if err != nil {
   731  		return errors.Wrap(err, "elasticcache.SetMaintainTime")
   732  	}
   733  
   734  	return nil
   735  }
   736  
   737  // https://help.aliyun.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO
   738  func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) {
   739  	if port < 1024 {
   740  		port = 6379
   741  	}
   742  
   743  	suffix, _ := goutils.RandomAlphabetic(4)
   744  	conn := self.GetId() + strings.ToLower(suffix)
   745  
   746  	params := make(map[string]string)
   747  	params["InstanceId"] = self.GetId()
   748  	params["Port"] = strconv.Itoa(port)
   749  	params["ConnectionStringPrefix"] = conn
   750  
   751  	err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil)
   752  	if err != nil {
   753  		return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection")
   754  	}
   755  
   756  	return conn, nil
   757  }
   758  
   759  // https://help.aliyun.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy
   760  func (self *SElasticcache) ReleasePublicConnection() error {
   761  	publicConn := self.GetPublicDNS()
   762  	if len(publicConn) == 0 {
   763  		log.Debugf("elasticcache.ReleasePublicConnection public connect is empty")
   764  		return nil
   765  	}
   766  
   767  	params := make(map[string]string)
   768  	params["InstanceId"] = self.GetId()
   769  	params["CurrentConnectionString"] = publicConn
   770  
   771  	err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil)
   772  	if err != nil {
   773  		return errors.Wrap(err, "elasticcache.ReleasePublicConnection")
   774  	}
   775  
   776  	return nil
   777  }
   778  
   779  // https://help.aliyun.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址
   780  
   781  // https://help.aliyun.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5
   782  func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) {
   783  	params := make(map[string]string)
   784  	params["InstanceId"] = self.GetId()
   785  	params["AccountName"] = input.AccountName
   786  	params["AccountPassword"] = input.AccountPassword
   787  	if len(input.AccountPrivilege) > 0 {
   788  		params["AccountPrivilege"] = input.AccountPrivilege
   789  	}
   790  
   791  	if len(input.Description) > 0 {
   792  		params["AccountDescription"] = input.Description
   793  	}
   794  
   795  	err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil)
   796  	if err != nil {
   797  		return nil, errors.Wrap(err, "elasticcache.CreateAccount")
   798  	}
   799  
   800  	return self.GetICloudElasticcacheAccountByName(input.AccountName)
   801  }
   802  
   803  func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) {
   804  	acl := &SElasticcacheAcl{}
   805  	acl.cacheDB = self
   806  	acl.SecurityIPGroupName = aclName
   807  	acl.SecurityIPList = securityIps
   808  	return acl, self.region.createAcl(self.GetId(), aclName, securityIps)
   809  }
   810  
   811  // https://help.aliyun.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy
   812  func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error {
   813  	params := make(map[string]string)
   814  	params["InstanceId"] = self.GetId()
   815  	params["Config"] = config.String()
   816  
   817  	err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil)
   818  	if err != nil {
   819  		return errors.Wrap(err, "elasticcache.UpdateInstanceParameters")
   820  	}
   821  
   822  	return nil
   823  }
   824  
   825  // https://help.aliyun.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa
   826  func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) {
   827  	params := make(map[string]string)
   828  	params["InstanceId"] = self.GetId()
   829  
   830  	// 目前没有查询备份ID的接口,因此,备份ID没什么用
   831  	err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil)
   832  	if err != nil {
   833  		return nil, errors.Wrap(err, "elasticcache.CreateBackup")
   834  	}
   835  
   836  	return nil, nil
   837  }
   838  
   839  // https://help.aliyun.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg
   840  func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error {
   841  	params := make(map[string]string)
   842  	params["InstanceId"] = self.GetId()
   843  	params["PreferredBackupPeriod"] = config.PreferredBackupPeriod
   844  	params["PreferredBackupTime"] = config.PreferredBackupTime
   845  
   846  	err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil)
   847  	if err != nil {
   848  		return errors.Wrap(err, "elasticcache.UpdateBackupPolicy")
   849  	}
   850  
   851  	return nil
   852  }
   853  
   854  // https://help.aliyun.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3
   855  func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error {
   856  	params := make(map[string]string)
   857  	params["InstanceId"] = self.GetId()
   858  
   859  	err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil)
   860  	if err != nil {
   861  		return errors.Wrap(err, "elasticcache.FlushInstance")
   862  	}
   863  
   864  	return nil
   865  }
   866  
   867  // https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO
   868  func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error {
   869  	params := make(map[string]string)
   870  	params["InstanceId"] = self.GetId()
   871  	if noPwdAccess {
   872  		params["VpcAuthMode"] = "Close"
   873  	} else {
   874  		params["VpcAuthMode"] = "Open"
   875  	}
   876  
   877  	err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil)
   878  	if err != nil {
   879  		return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode")
   880  	}
   881  
   882  	return nil
   883  }
   884  
   885  func (self *SElasticcache) GetProjectId() string {
   886  	return self.ResourceGroupId
   887  }
   888  
   889  func (self *SElasticcache) GetAuthMode() string {
   890  	attribute, err := self.GetAttribute()
   891  	if err != nil {
   892  		log.Errorf("elasticcache.GetAuthMode %s", err)
   893  	}
   894  	switch attribute.VpcAuthMode {
   895  	case "Open":
   896  		return "on"
   897  	default:
   898  		return "off"
   899  	}
   900  }
   901  
   902  func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) {
   903  	return nil, cloudprovider.ErrNotSupported
   904  }
   905  
   906  func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) {
   907  	segs := strings.Split(accountId, "/")
   908  	if len(segs) < 2 {
   909  		log.Debugf("elasticcache.GetICloudElasticcacheAccount invalid account id %s", accountId)
   910  		return nil, errors.Wrap(cloudprovider.ErrNotFound, "invalid account id")
   911  	}
   912  
   913  	return self.GetICloudElasticcacheAccountByName(segs[1])
   914  }
   915  
   916  func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) {
   917  	acls, err := self.GetICloudElasticcacheAcls()
   918  	if err != nil {
   919  		return nil, err
   920  	}
   921  
   922  	for _, acl := range acls {
   923  		if acl.GetId() == aclId {
   924  			return acl, nil
   925  		}
   926  	}
   927  
   928  	return nil, cloudprovider.ErrNotFound
   929  }
   930  
   931  func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) {
   932  	backups, err := self.GetICloudElasticcacheBackups()
   933  	if err != nil {
   934  		return nil, err
   935  	}
   936  
   937  	for _, backup := range backups {
   938  		if backup.GetId() == backupId {
   939  			return backup, nil
   940  		}
   941  	}
   942  
   943  	return nil, cloudprovider.ErrNotFound
   944  }
   945  
   946  func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error {
   947  	return instance.region.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", instance.GetId(), tags, replace)
   948  }
   949  
   950  func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error {
   951  	return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups")
   952  }
   953  
   954  // https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11174283.6.877.34653436jn6t4C
   955  // https://help.aliyun.com/document_detail/95584.html?spm=a2c4g.11186623.6.907.60e3292bWsVIOE
   956  // https://help.aliyun.com/document_detail/60909.html?spm=a2c4g.11186623.6.910.17664ce0jfir7F
   957  func (self *SElasticcache) Renew(bc billing.SBillingCycle) error {
   958  	month := bc.GetMonths()
   959  	if month <= 0 {
   960  		return errors.Wrap(fmt.Errorf("month should great than 0"), "GetMonths")
   961  	}
   962  
   963  	if (month >= 1 && month <= 9) || month == 12 || month == 24 || month == 36 {
   964  		return errors.Wrap(fmt.Errorf("month %d is invalid, required: 1~9、12、24、36", month), "GetMonths")
   965  	}
   966  
   967  	params := map[string]string{}
   968  	params["InstanceId"] = self.GetId()
   969  	params["Period"] = fmt.Sprintf("%d", month)
   970  	params["AutoPay"] = "true"
   971  	_, err := self.region.kvsRequest("RenewInstance", params)
   972  	if err != nil {
   973  		return errors.Wrap(err, "RenewInstance")
   974  	}
   975  
   976  	return nil
   977  }
   978  
   979  func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error {
   980  	params := map[string]string{}
   981  	params["DBInstanceId"] = self.GetId()
   982  	params["Duration"] = "1"
   983  	params["AutoRenew"] = fmt.Sprintf("%v", bc.AutoRenew)
   984  	_, err := self.region.kvsRequest("ModifyInstanceAutoRenewalAttribute", params)
   985  	if err != nil {
   986  		return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute")
   987  	}
   988  
   989  	return nil
   990  }