yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/google/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 google
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    24  	"yunion.io/x/jsonutils"
    25  	"yunion.io/x/log"
    26  	"yunion.io/x/pkg/errors"
    27  	"yunion.io/x/pkg/utils"
    28  
    29  	billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
    30  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    31  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    32  	"yunion.io/x/cloudmux/pkg/multicloud"
    33  	"yunion.io/x/onecloud/pkg/util/billing"
    34  )
    35  
    36  var (
    37  	EngineVersions = map[string]GoogleSQLVersion{
    38  		"MYSQL_5_5":                 GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.5"},
    39  		"MYSQL_5_6":                 GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.6"},
    40  		"MYSQL_5_7":                 GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.7"},
    41  		"POSTGRES_9_6":              GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "9.6"},
    42  		"POSTGRES_10":               GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "10"},
    43  		"POSTGRES_11":               GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "11"},
    44  		"POSTGRES_12":               GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "12"},
    45  		"SQLSERVER_2017_STANDARD":   GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Standard"},
    46  		"SQLSERVER_2017_ENTERPRISE": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Enterprise"},
    47  		"SQLSERVER_2017_EXPRESS":    GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Express"},
    48  		"SQLSERVER_2017_WEB":        GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Web"},
    49  	}
    50  	InstanceTypes = map[string]GoogleSQLType{
    51  		"db-f1-micro": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 614},
    52  		"db-g1-small": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1740},
    53  		"D0":          GoogleSQLType{VcpuCount: 1, VmemSizeMb: 512},
    54  		"D1":          GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1024},
    55  		"D2":          GoogleSQLType{VcpuCount: 1, VmemSizeMb: 2048},
    56  		"D4":          GoogleSQLType{VcpuCount: 1, VmemSizeMb: 5120},
    57  		"D8":          GoogleSQLType{VcpuCount: 2, VmemSizeMb: 10240},
    58  		"D16":         GoogleSQLType{VcpuCount: 4, VmemSizeMb: 10240},
    59  		"D32":         GoogleSQLType{VcpuCount: 8, VmemSizeMb: 10240},
    60  	}
    61  )
    62  
    63  type GoogleSQLType struct {
    64  	VcpuCount  int
    65  	VmemSizeMb int
    66  }
    67  
    68  type GoogleSQLVersion struct {
    69  	Engine  string
    70  	Version string
    71  }
    72  
    73  type SDBInstanceLocationPreference struct {
    74  	Zone string
    75  	Kind string
    76  }
    77  
    78  type SDBInstanceMaintenanceWindow struct {
    79  	Kind string
    80  	Hour int
    81  	Day  int
    82  }
    83  
    84  type SDBInstanceBackupConfiguration struct {
    85  	StartTime        string
    86  	Kind             string
    87  	Enabled          bool
    88  	BinaryLogEnabled bool
    89  }
    90  
    91  type SAuthorizedNetwork struct {
    92  	Value string
    93  	Kind  string
    94  	Name  string
    95  }
    96  
    97  type SDBInstanceSettingIpConfiguration struct {
    98  	PrivateNetwork     string
    99  	AuthorizedNetworks []SAuthorizedNetwork
   100  	Ipv4Enabled        bool
   101  }
   102  
   103  type SDBInstanceSetting struct {
   104  	AuthorizedGaeApplications []string
   105  	Tier                      string
   106  	Kind                      string
   107  	AvailabilityType          string
   108  	PricingPlan               string
   109  	ReplicationType           string
   110  	ActivationPolicy          string
   111  	IpConfiguration           SDBInstanceSettingIpConfiguration
   112  	LocationPreference        SDBInstanceLocationPreference
   113  	DataDiskType              string
   114  	MaintenanceWindow         SDBInstanceMaintenanceWindow
   115  	BackupConfiguration       SDBInstanceBackupConfiguration
   116  	SettingsVersion           string
   117  	StorageAutoResizeLimit    string
   118  	StorageAutoResize         bool
   119  	DataDiskSizeGb            int
   120  	DatabaseFlags             []SDBInstanceParameter
   121  	UserLabels                map[string]string
   122  }
   123  
   124  type SDBInstanceIpAddress struct {
   125  	Type      string
   126  	IpAddress string
   127  }
   128  
   129  type SDBInstanceCaCert struct {
   130  	Kind             string
   131  	CertSerialNumber string
   132  	Cert             string
   133  	CommonName       string
   134  	Sha1Fingerprint  string
   135  	Instance         string
   136  	CreateTime       time.Time
   137  	ExpirationTime   time.Time
   138  }
   139  
   140  type SDBInstance struct {
   141  	multicloud.SDBInstanceBase
   142  	region *SRegion
   143  
   144  	Kind                       string
   145  	State                      string
   146  	DatabaseVersion            string
   147  	Settings                   SDBInstanceSetting
   148  	Etag                       string
   149  	MasterInstanceName         string
   150  	IpAddresses                []SDBInstanceIpAddress
   151  	ServerCaCert               SDBInstanceCaCert
   152  	InstanceType               string
   153  	Project                    string
   154  	ServiceAccountEmailAddress string
   155  	BackendType                string
   156  	SelfLink                   string
   157  	ConnectionName             string
   158  	Name                       string
   159  	Region                     string
   160  	GceZone                    string
   161  }
   162  
   163  func (region *SRegion) GetDBInstances(maxResults int, pageToken string) ([]SDBInstance, error) {
   164  	instances := []SDBInstance{}
   165  	params := map[string]string{"filter": "region=" + region.Name}
   166  	err := region.RdsList("instances", params, maxResults, pageToken, &instances)
   167  	if err != nil {
   168  		return nil, errors.Wrap(err, "RdsList")
   169  	}
   170  	return instances, nil
   171  }
   172  
   173  func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) {
   174  	instance := SDBInstance{region: region}
   175  	err := region.rdsGet(instanceId, &instance)
   176  	if err != nil {
   177  		return nil, errors.Wrap(err, "RdsGet")
   178  	}
   179  	return &instance, nil
   180  }
   181  
   182  func (rds *SDBInstance) GetName() string {
   183  	return rds.Name
   184  }
   185  
   186  func (rds *SDBInstance) GetId() string {
   187  	return rds.SelfLink
   188  }
   189  
   190  func (rds *SDBInstance) GetGlobalId() string {
   191  	return strings.TrimPrefix(rds.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION))
   192  }
   193  
   194  func (rds *SDBInstance) GetProjectId() string {
   195  	return rds.region.GetProjectId()
   196  }
   197  
   198  func (rds *SDBInstance) IsEmulated() bool {
   199  	return false
   200  }
   201  
   202  func (rds *SDBInstance) GetStatus() string {
   203  	switch rds.State {
   204  	case "RUNNABLE":
   205  		return api.DBINSTANCE_RUNNING
   206  	case "PENDING_CREATE":
   207  		return api.DBINSTANCE_DEPLOYING
   208  	case "MAINTENANCE":
   209  		return api.DBINSTANCE_MAINTENANCE
   210  	case "FAILED":
   211  		return api.DBINSTANCE_CREATE_FAILED
   212  	case "UNKNOWN_STATE", "SUSPENDED":
   213  		return api.DBINSTANCE_UNKNOWN
   214  	}
   215  	return rds.State
   216  }
   217  
   218  func (rds *SDBInstance) GetBillingType() string {
   219  	return billing_api.BILLING_TYPE_POSTPAID
   220  }
   221  
   222  func (rds *SDBInstance) GetCreatedAt() time.Time {
   223  	return rds.ServerCaCert.CreateTime
   224  }
   225  
   226  func (rds *SDBInstance) GetExpiredAt() time.Time {
   227  	return time.Time{}
   228  }
   229  
   230  func (rds *SDBInstance) GetMasterInstanceId() string {
   231  	if len(rds.MasterInstanceName) > 0 {
   232  		if master := strings.Split(rds.MasterInstanceName, ":"); len(master) == 2 {
   233  			return fmt.Sprintf("projects/%s/instances/%s", master[0], master[1])
   234  		}
   235  	}
   236  	return ""
   237  }
   238  
   239  func (rds *SDBInstance) GetSecurityGroupId() string {
   240  	return ""
   241  }
   242  
   243  func (rds *SDBInstance) Refresh() error {
   244  	instance, err := rds.region.GetDBInstance(rds.SelfLink)
   245  	if err != nil {
   246  		return errors.Wrapf(err, "GetDBInstance(%s)", rds.SelfLink)
   247  	}
   248  	return jsonutils.Update(rds, instance)
   249  }
   250  
   251  func (rds *SDBInstance) GetPort() int {
   252  	switch rds.GetEngine() {
   253  	case api.DBINSTANCE_TYPE_MYSQL:
   254  		return 3306
   255  	case api.DBINSTANCE_TYPE_POSTGRESQL:
   256  		return 5432
   257  	case api.DBINSTANCE_TYPE_SQLSERVER:
   258  		return 1433
   259  	default:
   260  		return 0
   261  	}
   262  }
   263  
   264  func (rds *SDBInstance) GetEngine() string {
   265  	if e, ok := EngineVersions[rds.DatabaseVersion]; ok {
   266  		return e.Engine
   267  	}
   268  	return rds.DatabaseVersion
   269  }
   270  
   271  func (rds *SDBInstance) GetEngineVersion() string {
   272  	if e, ok := EngineVersions[rds.DatabaseVersion]; ok {
   273  		return e.Version
   274  	}
   275  	return rds.DatabaseVersion
   276  }
   277  
   278  func (rds *SDBInstance) GetInstanceType() string {
   279  	return rds.Settings.Tier
   280  }
   281  
   282  func (rds *SDBInstance) GetVcpuCount() int {
   283  	if t, ok := InstanceTypes[rds.Settings.Tier]; ok {
   284  		return t.VcpuCount
   285  	}
   286  	numStr := ""
   287  	if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") {
   288  		numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-standard-")
   289  	} else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") {
   290  		numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-highmem-")
   291  	} else {
   292  		numStr = strings.TrimPrefix(rds.Settings.Tier, "db-custom-")
   293  		numStr = strings.Split(numStr, "-")[0]
   294  	}
   295  	cpu, _ := strconv.ParseInt(numStr, 10, 32)
   296  	return int(cpu)
   297  }
   298  
   299  func (rds *SDBInstance) GetVmemSizeMB() int {
   300  	if t, ok := InstanceTypes[rds.Settings.Tier]; ok {
   301  		return t.VmemSizeMb
   302  	}
   303  	if strings.HasPrefix(rds.Settings.Tier, "db-custom-") {
   304  		info := strings.Split(rds.Settings.Tier, "-")
   305  		numStr := info[len(info)-1]
   306  		mem, _ := strconv.ParseInt(numStr, 10, 32)
   307  		return int(mem)
   308  	} else if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") {
   309  		return rds.GetVcpuCount() * 3840
   310  	} else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") {
   311  		return rds.GetVcpuCount() * 3840 * 2
   312  	}
   313  	return 0
   314  }
   315  
   316  func (rds *SDBInstance) GetDiskSizeGB() int {
   317  	return rds.Settings.DataDiskSizeGb
   318  }
   319  
   320  func (rds *SDBInstance) GetCategory() string {
   321  	switch rds.Settings.AvailabilityType {
   322  	case "REGIONAL":
   323  		return api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL
   324  	default:
   325  		return api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL
   326  	}
   327  }
   328  
   329  func (rds *SDBInstance) GetStorageType() string {
   330  	return rds.Settings.DataDiskType
   331  }
   332  
   333  func (rds *SDBInstance) GetMaintainTime() string {
   334  	startTime := (rds.Settings.MaintenanceWindow.Hour + 8) % 24
   335  	startDay := (rds.Settings.MaintenanceWindow.Day + 1) % 7
   336  	return fmt.Sprintf("%s %02d:00 - %02d:00", time.Weekday(startDay).String(), startTime, startTime+1)
   337  }
   338  
   339  func (rds *SDBInstance) GetConnectionStr() string {
   340  	for _, ip := range rds.IpAddresses {
   341  		if ip.Type == "PRIMARY" {
   342  			return ip.IpAddress
   343  		}
   344  	}
   345  	return ""
   346  }
   347  
   348  func (rds *SDBInstance) GetInternalConnectionStr() string {
   349  	ret := []string{rds.ConnectionName}
   350  	for _, ip := range rds.IpAddresses {
   351  		if ip.Type == "PRIVATE" {
   352  			ret = append(ret, ip.IpAddress)
   353  		}
   354  	}
   355  	return strings.Join(ret, ",")
   356  }
   357  
   358  func (rds *SDBInstance) GetZone1Id() string {
   359  	zones, err := rds.region.GetIZones()
   360  	if err != nil {
   361  		log.Errorf("failed to found rds %s zone %s", rds.Name, rds.GceZone)
   362  		return ""
   363  	}
   364  	for _, zone := range zones {
   365  		if zone.GetId() == rds.GceZone {
   366  			return zone.GetGlobalId()
   367  		}
   368  	}
   369  	return ""
   370  }
   371  
   372  func (rds *SDBInstance) GetZone2Id() string {
   373  	return ""
   374  }
   375  
   376  func (rds *SDBInstance) GetZone3Id() string {
   377  	return ""
   378  }
   379  
   380  func (rds *SDBInstance) GetIVpcId() string {
   381  	return ""
   382  }
   383  
   384  func (rds *SDBInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) {
   385  	return nil, nil
   386  }
   387  
   388  func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) {
   389  	ret := []cloudprovider.ICloudDBInstanceParameter{}
   390  	for i := range rds.Settings.DatabaseFlags {
   391  		rds.Settings.DatabaseFlags[i].rds = rds
   392  		ret = append(ret, &rds.Settings.DatabaseFlags[i])
   393  	}
   394  	return ret, nil
   395  }
   396  
   397  func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) {
   398  	databases, err := rds.region.GetDBInstanceDatabases(rds.Name)
   399  	if err != nil {
   400  		return nil, errors.Wrap(err, "GetDBInstanceDatabases")
   401  	}
   402  	ret := []cloudprovider.ICloudDBInstanceDatabase{}
   403  	for i := range databases {
   404  		databases[i].rds = rds
   405  		ret = append(ret, &databases[i])
   406  	}
   407  	return ret, nil
   408  }
   409  
   410  func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) {
   411  	accounts, err := rds.region.GetDBInstanceAccounts(rds.Name)
   412  	if err != nil {
   413  		return nil, errors.Wrap(err, "GetDBInstanceAccounts")
   414  	}
   415  	ret := []cloudprovider.ICloudDBInstanceAccount{}
   416  	for i := range accounts {
   417  		accounts[i].rds = rds
   418  		ret = append(ret, &accounts[i])
   419  	}
   420  	return ret, nil
   421  }
   422  
   423  func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) {
   424  	backups, err := rds.region.GetDBInstanceBackups(rds.Name)
   425  	if err != nil {
   426  		return nil, errors.Wrap(err, "GetDBInstanceBackups")
   427  	}
   428  	ret := []cloudprovider.ICloudDBInstanceBackup{}
   429  	for i := range backups {
   430  		backups[i].rds = rds
   431  		ret = append(ret, &backups[i])
   432  	}
   433  	return ret, nil
   434  }
   435  
   436  func (region *SRegion) ChangeDBInstanceConfig(instanceId string, diskSizeGb int, instanceType string) error {
   437  	rds, err := region.GetDBInstance(instanceId)
   438  	if err != nil {
   439  		return errors.Wrapf(err, "GetDBInstance(%s)", instanceId)
   440  	}
   441  	body := map[string]interface{}{}
   442  	settings := map[string]interface{}{}
   443  	if len(instanceType) > 0 && instanceType != rds.GetInstanceType() {
   444  		settings["tier"] = instanceType
   445  	}
   446  	if diskSizeGb > 0 && diskSizeGb != rds.GetDiskSizeGB() {
   447  		settings["dataDiskSizeGb"] = diskSizeGb
   448  	}
   449  	if len(settings) == 0 {
   450  		return nil
   451  	}
   452  	body["settings"] = settings
   453  	return region.rdsPatch(rds.SelfLink, jsonutils.Marshal(body))
   454  }
   455  
   456  func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error {
   457  	return rds.region.ChangeDBInstanceConfig(rds.SelfLink, config.DiskSizeGB, config.InstanceType)
   458  }
   459  
   460  func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error {
   461  	return cloudprovider.ErrNotSupported
   462  }
   463  
   464  func (region *SRegion) DBInstancePublicConnectionOperation(instanceId string, open bool) error {
   465  	ipConfiguration := map[string]interface{}{
   466  		"ipv4Enabled": open,
   467  	}
   468  	if open {
   469  		ipConfiguration["authorizedNetworks"] = []map[string]string{
   470  			map[string]string{
   471  				"name":  "White list",
   472  				"value": "0.0.0.0/0",
   473  			},
   474  		}
   475  	}
   476  	body := map[string]interface{}{
   477  		"settings": map[string]interface{}{
   478  			"ipConfiguration": ipConfiguration,
   479  		},
   480  	}
   481  	return region.rdsPatch(instanceId, jsonutils.Marshal(body))
   482  }
   483  
   484  func (rds *SDBInstance) OpenPublicConnection() error {
   485  	return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, true)
   486  }
   487  
   488  func (rds *SDBInstance) ClosePublicConnection() error {
   489  	return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, false)
   490  }
   491  
   492  func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error {
   493  	return rds.region.CreateDatabase(rds.SelfLink, conf.Name, conf.CharacterSet)
   494  }
   495  
   496  func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error {
   497  	return rds.region.CreateDBInstanceAccount(rds.SelfLink, conf.Name, conf.Password, "%")
   498  }
   499  
   500  func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) {
   501  	err := rds.region.CreateDBInstanceBackup(rds.SelfLink, conf.Name, conf.Description)
   502  	if err != nil {
   503  		return "", errors.Wrap(err, "CreateIBackup")
   504  	}
   505  	return "", nil
   506  }
   507  
   508  func (region *SRegion) RecoverFromBackup(instanceName, dest string, backupId string) error {
   509  	backup, err := region.GetDBInstanceBackup(backupId)
   510  	if err != nil {
   511  		return errors.Wrap(err, "GetDBInstanceBackup")
   512  	}
   513  	body := map[string]interface{}{
   514  		"restoreBackupContext": map[string]string{
   515  			"backupRunId": backup.Id,
   516  			"instanceId":  instanceName,
   517  			"project":     region.client.projectId,
   518  		},
   519  	}
   520  	return region.rdsDo(dest, "restoreBackup", nil, jsonutils.Marshal(body))
   521  }
   522  
   523  func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error {
   524  	instanceName := rds.Name
   525  	if len(conf.OriginDBInstanceExternalId) > 0 {
   526  		instance, err := rds.region.GetDBInstance(conf.OriginDBInstanceExternalId)
   527  		if err != nil {
   528  			return errors.Wrapf(err, "GetInstance(%s)", conf.OriginDBInstanceExternalId)
   529  		}
   530  		instanceName = instance.Name
   531  	}
   532  	return rds.region.RecoverFromBackup(instanceName, rds.SelfLink, conf.BackupId)
   533  }
   534  
   535  func (rds *SDBInstance) Reboot() error {
   536  	return rds.region.rdsDo(rds.SelfLink, "restart", nil, nil)
   537  }
   538  
   539  func (rds *SDBInstance) Delete() error {
   540  	return rds.region.DeleteDBInstance(rds.SelfLink)
   541  }
   542  
   543  func (region *SRegion) DeleteDBInstance(id string) error {
   544  	return region.rdsDelete(id)
   545  }
   546  
   547  func (region *SRegion) CreateRds(name, engine, databaseVersion, category, instanceType, storageType string, diskSizeGb int, vpcId, zoneId, password string) (*SDBInstance, error) {
   548  	settings := map[string]interface{}{
   549  		"tier":              instanceType,
   550  		"storageAutoResize": true,
   551  		"dataDiskType":      storageType,
   552  		"dataDiskSizeGb":    diskSizeGb,
   553  	}
   554  	if utils.IsInStringArray(category, []string{api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL, api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL}) {
   555  		settings["availabilityType"] = strings.ToUpper(category)
   556  		backupConfiguration := map[string]interface{}{
   557  			"enabled":   true,
   558  			"startTime": "19:00",
   559  		}
   560  		if engine == api.DBINSTANCE_TYPE_MYSQL {
   561  			backupConfiguration["binaryLogEnabled"] = true
   562  		}
   563  		settings["backupConfiguration"] = backupConfiguration
   564  	}
   565  	ipConfiguration := map[string]interface{}{
   566  		"ipv4Enabled": true,
   567  	}
   568  	ipConfiguration["authorizedNetworks"] = []map[string]string{
   569  		map[string]string{
   570  			"name":  "White list",
   571  			"value": "0.0.0.0/0",
   572  		},
   573  	}
   574  	settings["ipConfiguration"] = ipConfiguration
   575  	body := map[string]interface{}{
   576  		"databaseVersion": databaseVersion,
   577  		"name":            name,
   578  		"region":          region.Name,
   579  		"settings":        settings,
   580  		"backendType":     "SECOND_GEN",
   581  		"instanceType":    "CLOUD_SQL_INSTANCE",
   582  	}
   583  	if len(zoneId) > 0 {
   584  		settings["locationPreference"] = map[string]string{
   585  			"zone": zoneId,
   586  		}
   587  	}
   588  	if len(password) > 0 {
   589  		body["rootPassword"] = password
   590  	}
   591  	rds := SDBInstance{region: region}
   592  	err := region.rdsInsert("instances", jsonutils.Marshal(body), &rds)
   593  	if err != nil {
   594  		if e, ok := errors.Cause(err).(*gError); ok && e.ErrorInfo.Code == 409 { //The instance or operation is not in an appropriate state to handle the request
   595  			return nil, fmt.Errorf("the name %s is unavailable because it was used recently", name)
   596  		}
   597  		return nil, errors.Wrap(err, "rdsInsert")
   598  	}
   599  	return &rds, nil
   600  }
   601  
   602  func (region *SRegion) CreateDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (*SDBInstance, error) {
   603  	desc.EngineVersion = strings.ToUpper(desc.EngineVersion)
   604  	desc.EngineVersion = strings.Replace(desc.EngineVersion, ".", "_", -1)
   605  	desc.EngineVersion = strings.Replace(desc.EngineVersion, " ", "_", -1)
   606  	if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL {
   607  		desc.Engine = "POSTGRES"
   608  	}
   609  	databaseVersion := fmt.Sprintf("%s_%s", strings.ToUpper(desc.Engine), desc.EngineVersion)
   610  	if _, ok := EngineVersions[databaseVersion]; !ok {
   611  		return nil, fmt.Errorf("Unsupport %s version %s", desc.Engine, desc.EngineVersion)
   612  	}
   613  	rds, err := region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, desc.ZoneId, desc.Password)
   614  	if err != nil {
   615  		return nil, errors.Wrapf(err, "CreateRds")
   616  	}
   617  	return rds, nil
   618  }
   619  
   620  func (self *SDBInstance) GetTags() (map[string]string, error) {
   621  	return self.Settings.UserLabels, nil
   622  }
   623  
   624  func (self *SDBInstance) GetSysTags() map[string]string {
   625  	return nil
   626  }
   627  
   628  func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error {
   629  	params := map[string]interface{}{
   630  		"settings": map[string]interface{}{
   631  			"userLabels": tags,
   632  		},
   633  	}
   634  	err := self.region.rdsPatch(self.GetId(), jsonutils.Marshal(params))
   635  	return errors.Wrapf(err, "rdsPatch")
   636  }