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 }