yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/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 huawei 16 17 import ( 18 "context" 19 "fmt" 20 "time" 21 22 "github.com/pkg/errors" 23 24 "yunion.io/x/jsonutils" 25 "yunion.io/x/log" 26 27 billing_api "yunion.io/x/cloudmux/pkg/apis/billing" 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 ) 33 34 type SBackupStrategy struct { 35 KeepDays int 36 StartTime string 37 } 38 39 type SDatastore struct { 40 Type string 41 Version string 42 } 43 44 type SHa struct { 45 ReplicationMode string 46 } 47 48 type SNonde struct { 49 AvailabilityZone string 50 Id string 51 Name string 52 Role string 53 Staus string 54 } 55 56 type SVolume struct { 57 Size int 58 Type string 59 } 60 61 type SRelatedInstance struct { 62 Id string 63 Type string 64 } 65 66 type SDBInstance struct { 67 multicloud.SDBInstanceBase 68 HuaweiTags 69 region *SRegion 70 71 flavorCache []SDBInstanceFlavor 72 BackupStrategy SBackupStrategy 73 Created string //time.Time 74 Datastore SDatastore 75 DbUserName string 76 DIskEncryptionId string 77 FlavorRef string 78 Ha SHa 79 Id string 80 MaintenanceWindow string 81 MaxIops int 82 Name string 83 Nodes []SNonde 84 Port int 85 PrivateIps []string 86 PublicIps []string 87 Region string 88 RelatedInstance []SRelatedInstance 89 SecurityGroupId string 90 Status string 91 SubnetId string 92 SwitchStrategy string 93 TimeZone string 94 Type string 95 Updated string //time.Time 96 Volume SVolume 97 VpcId string 98 EnterpriseProjectId string 99 } 100 101 func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { 102 params := map[string]string{} 103 dbinstances := []SDBInstance{} 104 err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) 105 return dbinstances, err 106 } 107 108 func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { 109 if len(instanceId) == 0 { 110 return nil, cloudprovider.ErrNotFound 111 } 112 instance := SDBInstance{region: region} 113 err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) 114 return &instance, err 115 } 116 117 func (rds *SDBInstance) GetName() string { 118 return rds.Name 119 } 120 121 func (rds *SDBInstance) GetId() string { 122 return rds.Id 123 } 124 125 func (rds *SDBInstance) GetGlobalId() string { 126 return rds.GetId() 127 } 128 129 // 值为“BUILD”,表示实例正在创建。 130 // 值为“ACTIVE”,表示实例正常。 131 // 值为“FAILED”,表示实例异常。 132 // 值为“FROZEN”,表示实例冻结。 133 // 值为“MODIFYING”,表示实例正在扩容。 134 // 值为“REBOOTING”,表示实例正在重启。 135 // 值为“RESTORING”,表示实例正在恢复。 136 // 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 137 // 值为“SWITCHOVER”,表示实例正在主备切换。 138 // 值为“MIGRATING”,表示实例正在迁移。 139 // 值为“BACKING UP”,表示实例正在进行备份。 140 // 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 141 // 值为“STORAGE FULL”,表示实例磁盘空间满。 142 143 func (rds *SDBInstance) GetStatus() string { 144 switch rds.Status { 145 case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": 146 return api.DBINSTANCE_DEPLOYING 147 case "ACTIVE": 148 return api.DBINSTANCE_RUNNING 149 case "FAILED", "FROZEN", "STORAGE FULL": 150 return api.DBINSTANCE_UNKNOWN 151 case "REBOOTING": 152 return api.DBINSTANCE_REBOOTING 153 case "RESTORING": 154 return api.DBINSTANCE_RESTORING 155 case "MIGRATING": 156 return api.DBINSTANCE_MIGRATING 157 case "BACKING UP": 158 return api.DBINSTANCE_BACKING_UP 159 } 160 return rds.Status 161 } 162 163 func (rds *SDBInstance) GetBillingType() string { 164 _, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) 165 if err != nil { 166 return billing_api.BILLING_TYPE_POSTPAID 167 } 168 return billing_api.BILLING_TYPE_PREPAID 169 } 170 171 func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { 172 return []string{rds.SecurityGroupId}, nil 173 } 174 175 func (rds *SDBInstance) fetchFlavor() error { 176 if len(rds.flavorCache) > 0 { 177 return nil 178 } 179 flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) 180 if err != nil { 181 return err 182 } 183 rds.flavorCache = flavors 184 return nil 185 } 186 187 func (rds *SDBInstance) GetExpiredAt() time.Time { 188 order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) 189 if err != nil { 190 return time.Time{} 191 } 192 return order.ExpireTime 193 } 194 195 func (rds *SDBInstance) GetStorageType() string { 196 return rds.Volume.Type 197 } 198 199 func (rds *SDBInstance) GetCreatedAt() time.Time { 200 t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) 201 if err != nil { 202 return time.Time{} 203 } 204 return t 205 } 206 207 func (rds *SDBInstance) GetEngine() string { 208 return rds.Datastore.Type 209 } 210 211 func (rds *SDBInstance) GetEngineVersion() string { 212 return rds.Datastore.Version 213 } 214 215 func (rds *SDBInstance) GetInstanceType() string { 216 return rds.FlavorRef 217 } 218 219 func (rds *SDBInstance) GetCategory() string { 220 switch rds.Type { 221 case "Single": 222 return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE 223 case "Ha": 224 return api.HUAWEI_DBINSTANCE_CATEGORY_HA 225 case "Replica": 226 return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA 227 } 228 return rds.Type 229 } 230 231 func (rds *SDBInstance) GetVcpuCount() int { 232 err := rds.fetchFlavor() 233 if err != nil { 234 log.Errorf("failed to fetch flavors: %v", err) 235 return 0 236 } 237 for _, flavor := range rds.flavorCache { 238 if flavor.SpecCode == rds.FlavorRef { 239 return flavor.Vcpus 240 } 241 } 242 return 0 243 } 244 245 func (rds *SDBInstance) GetVmemSizeMB() int { 246 err := rds.fetchFlavor() 247 if err != nil { 248 log.Errorf("failed to fetch flavors: %v", err) 249 return 0 250 } 251 for _, flavor := range rds.flavorCache { 252 if flavor.SpecCode == rds.FlavorRef { 253 return flavor.Ram * 1024 254 } 255 } 256 return 0 257 } 258 259 func (rds *SDBInstance) GetDiskSizeGB() int { 260 return rds.Volume.Size 261 } 262 263 func (rds *SDBInstance) GetPort() int { 264 return rds.Port 265 } 266 267 func (rds *SDBInstance) GetMaintainTime() string { 268 return rds.MaintenanceWindow 269 } 270 271 func (rds *SDBInstance) GetIVpcId() string { 272 return rds.VpcId 273 } 274 275 func (rds *SDBInstance) GetProjectId() string { 276 return rds.EnterpriseProjectId 277 } 278 279 func (rds *SDBInstance) Refresh() error { 280 instance, err := rds.region.GetDBInstance(rds.Id) 281 if err != nil { 282 return err 283 } 284 return jsonutils.Update(rds, instance) 285 } 286 287 func (rds *SDBInstance) GetZone1Id() string { 288 return rds.GetZoneIdByRole("master") 289 } 290 291 func (rds *SDBInstance) GetZoneIdByRole(role string) string { 292 for _, node := range rds.Nodes { 293 if node.Role == role { 294 zone, err := rds.region.getZoneById(node.AvailabilityZone) 295 if err != nil { 296 log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) 297 return "" 298 } 299 return zone.GetGlobalId() 300 } 301 } 302 return "" 303 } 304 305 func (rds *SDBInstance) GetZone2Id() string { 306 return rds.GetZoneIdByRole("slave") 307 } 308 309 func (rds *SDBInstance) GetZone3Id() string { 310 return "" 311 } 312 313 func (rds *SDBInstance) GetIops() int { 314 return rds.MaxIops 315 } 316 317 type SRdsNetwork struct { 318 SubnetId string 319 IP string 320 } 321 322 func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { 323 ret := []cloudprovider.SDBInstanceNetwork{} 324 for _, ip := range rds.PrivateIps { 325 network := cloudprovider.SDBInstanceNetwork{ 326 IP: ip, 327 NetworkId: rds.SubnetId, 328 } 329 ret = append(ret, network) 330 } 331 return ret, nil 332 } 333 334 func (rds *SDBInstance) GetInternalConnectionStr() string { 335 for _, ip := range rds.PrivateIps { 336 return ip 337 } 338 return "" 339 } 340 341 func (rds *SDBInstance) GetConnectionStr() string { 342 for _, ip := range rds.PublicIps { 343 return ip 344 } 345 return "" 346 } 347 348 func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { 349 dbinstance, err := region.GetDBInstance(instanceId) 350 if err != nil { 351 log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) 352 } 353 return dbinstance, err 354 } 355 356 func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { 357 instances, err := region.GetDBInstances() 358 if err != nil { 359 return nil, errors.Wrapf(err, "region.GetDBInstances()") 360 } 361 idbinstances := []cloudprovider.ICloudDBInstance{} 362 for i := 0; i < len(instances); i++ { 363 instances[i].region = region 364 idbinstances = append(idbinstances, &instances[i]) 365 } 366 return idbinstances, nil 367 } 368 369 func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { 370 parameters, err := rds.region.GetDBInstanceParameters(rds.Id) 371 if err != nil { 372 return nil, err 373 } 374 iparameters := []cloudprovider.ICloudDBInstanceParameter{} 375 for i := 0; i < len(parameters); i++ { 376 iparameters = append(iparameters, ¶meters[i]) 377 } 378 return iparameters, nil 379 } 380 381 func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { 382 databases, err := rds.region.GetDBInstanceDatabases(rds.Id) 383 if err != nil { 384 return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") 385 } 386 387 idatabase := []cloudprovider.ICloudDBInstanceDatabase{} 388 for i := 0; i < len(databases); i++ { 389 databases[i].instance = rds 390 idatabase = append(idatabase, &databases[i]) 391 } 392 return idatabase, nil 393 } 394 395 func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { 396 accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) 397 if err != nil { 398 return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") 399 } 400 401 user := "root" 402 if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { 403 user = "rduser" 404 } 405 406 accounts = append(accounts, SDBInstanceAccount{ 407 Name: user, 408 instance: rds, 409 }) 410 411 iaccounts := []cloudprovider.ICloudDBInstanceAccount{} 412 for i := 0; i < len(accounts); i++ { 413 accounts[i].instance = rds 414 iaccounts = append(iaccounts, &accounts[i]) 415 } 416 return iaccounts, nil 417 } 418 419 func (rds *SDBInstance) Delete() error { 420 return rds.region.DeleteDBInstance(rds.Id) 421 } 422 423 func (region *SRegion) DeleteDBInstance(instanceId string) error { 424 _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) 425 return err 426 } 427 428 func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { 429 zoneIds := []string{} 430 zones, err := region.GetIZones() 431 if err != nil { 432 return nil, err 433 } 434 for _, zone := range zones { 435 zoneIds = append(zoneIds, zone.GetId()) 436 } 437 438 if len(desc.SecgroupIds) == 0 { 439 return nil, fmt.Errorf("Missing secgroupId") 440 } 441 442 params := map[string]interface{}{ 443 "region": region.ID, 444 "name": desc.Name, 445 "datastore": map[string]string{ 446 "type": desc.Engine, 447 "version": desc.EngineVersion, 448 }, 449 "password": desc.Password, 450 "volume": map[string]interface{}{ 451 "type": desc.StorageType, 452 "size": desc.DiskSizeGB, 453 }, 454 "vpc_id": desc.VpcId, 455 "subnet_id": desc.NetworkId, 456 "security_group_id": desc.SecgroupIds[0], 457 } 458 459 if len(desc.ProjectId) > 0 { 460 params["enterprise_project_id"] = desc.ProjectId 461 } 462 463 if len(desc.MasterInstanceId) > 0 { 464 params["replica_of_id"] = desc.MasterInstanceId 465 delete(params, "security_group_id") 466 } 467 468 if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { 469 params["restore_point"] = map[string]interface{}{ 470 "backup_id": desc.BackupId, 471 "instance_id": desc.RdsId, 472 "type": "backup", 473 } 474 } 475 476 switch desc.Category { 477 case api.HUAWEI_DBINSTANCE_CATEGORY_HA: 478 switch desc.Engine { 479 case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: 480 params["ha"] = map[string]string{ 481 "mode": "Ha", 482 "replication_mode": "async", 483 } 484 case api.DBINSTANCE_TYPE_SQLSERVER: 485 params["ha"] = map[string]string{ 486 "mode": "Ha", 487 "replication_mode": "sync", 488 } 489 } 490 case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: 491 case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: 492 } 493 494 if desc.BillingCycle != nil { 495 periodType := "month" 496 periodNum := desc.BillingCycle.GetMonths() 497 if desc.BillingCycle.GetYears() > 0 { 498 periodType = "year" 499 periodNum = desc.BillingCycle.GetYears() 500 } 501 params["charge_info"] = map[string]interface{}{ 502 "charge_mode": "prePaid", 503 "period_type": periodType, 504 "period_num": periodNum, 505 "is_auto_renew": false, 506 } 507 } 508 params["flavor_ref"] = desc.InstanceType 509 params["availability_zone"] = desc.ZoneId 510 resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) 511 if err != nil { 512 return nil, errors.Wrapf(err, "Create") 513 } 514 515 instance := &SDBInstance{region: region} 516 err = resp.Unmarshal(instance, "instance") 517 if err != nil { 518 return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) 519 } 520 if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { 521 err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { 522 job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) 523 if err != nil { 524 return false, nil 525 } 526 status, _ := job.GetString("status") 527 process, _ := job.GetString("process") 528 log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) 529 if status == "Completed" { 530 return true, nil 531 } 532 if status == "Failed" { 533 return false, fmt.Errorf("create failed") 534 } 535 return false, nil 536 }) 537 } 538 return instance, err 539 } 540 541 func (rds *SDBInstance) Reboot() error { 542 return rds.region.RebootDBInstance(rds.Id) 543 } 544 545 func (rds *SDBInstance) OpenPublicConnection() error { 546 return fmt.Errorf("Huawei current not support this operation") 547 //return rds.region.PublicConnectionAction(rds.Id, "openRC") 548 } 549 550 func (rds *SDBInstance) ClosePublicConnection() error { 551 return fmt.Errorf("Huawei current not support this operation") 552 //return rds.region.PublicConnectionAction(rds.Id, "closeRC") 553 } 554 555 func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { 556 resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") 557 if err != nil { 558 return errors.Wrapf(err, "rds.%s", action) 559 } 560 561 if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { 562 err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { 563 job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) 564 if err != nil { 565 log.Errorf("failed to get job %s info error: %v", jobId, err) 566 return false 567 } 568 status, _ := job.GetString("status") 569 process, _ := job.GetString("process") 570 if status == "Completed" { 571 return true 572 } 573 log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) 574 return false 575 }) 576 } 577 578 return nil 579 580 } 581 582 func (region *SRegion) RebootDBInstance(instanceId string) error { 583 params := jsonutils.Marshal(map[string]interface{}{ 584 "restart": map[string]string{}, 585 }) 586 resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") 587 if err != nil { 588 return err 589 } 590 if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { 591 err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { 592 job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) 593 if err != nil { 594 log.Errorf("failed to get job %s info error: %v", jobId, err) 595 return false 596 } 597 status, _ := job.GetString("status") 598 process, _ := job.GetString("process") 599 if status == "Completed" { 600 return true 601 } 602 log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) 603 return false 604 }) 605 } 606 return err 607 } 608 609 type SDBInstanceFlavor struct { 610 Vcpus int 611 Ram int //单位GB 612 SpecCode string 613 InstanceMode string //实例模型 614 } 615 616 func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { 617 flavors := []SDBInstanceFlavor{} 618 resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") 619 if err != nil { 620 return nil, err 621 } 622 return flavors, jsonutils.Update(&flavors, resp.Data) 623 } 624 625 func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { 626 return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) 627 } 628 629 func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { 630 params := map[string]string{ 631 "name": account, 632 "password": password, 633 } 634 _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") 635 return err 636 } 637 638 func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { 639 return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) 640 } 641 642 func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { 643 params := map[string]string{ 644 "name": database, 645 "character_set": characterSet, 646 } 647 _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") 648 return err 649 } 650 651 func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { 652 return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) 653 } 654 655 func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { 656 instance, err := region.GetIDBInstanceById(instanceId) 657 if err != nil { 658 return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) 659 } 660 661 if len(instanceType) > 0 { 662 params := map[string]map[string]string{ 663 "resize_flavor": map[string]string{ 664 "spec_code": instanceType, 665 }, 666 } 667 _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) 668 if err != nil { 669 return errors.Wrap(err, "resize_flavor") 670 } 671 cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) 672 } 673 if diskSizeGb > 0 { 674 params := map[string]map[string]int{ 675 "enlarge_volume": map[string]int{ 676 "size": diskSizeGb, 677 }, 678 } 679 _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) 680 if err != nil { 681 return errors.Wrap(err, "enlarge_volume") 682 } 683 cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) 684 } 685 return nil 686 } 687 688 func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { 689 existedTags, err := self.GetTags() 690 if err != nil { 691 return errors.Wrap(err, "self.GetTags()") 692 } 693 deleteTagsKey := []string{} 694 for k := range existedTags { 695 if replace { 696 deleteTagsKey = append(deleteTagsKey, k) 697 } else { 698 if _, ok := tags[k]; ok { 699 deleteTagsKey = append(deleteTagsKey, k) 700 } 701 } 702 } 703 if len(deleteTagsKey) > 0 { 704 err := self.region.DeleteRdsTags(self.GetId(), deleteTagsKey) 705 if err != nil { 706 return errors.Wrapf(err, "DeleteRdsTags") 707 } 708 } 709 if len(tags) > 0 { 710 err := self.region.CreateRdsTags(self.GetId(), tags) 711 if err != nil { 712 return errors.Wrapf(err, "CreateRdsTags") 713 } 714 } 715 return nil 716 } 717 718 func (self *SRegion) DeleteRdsTags(instanceId string, tagsKey []string) error { 719 params := map[string]interface{}{ 720 "action": "delete", 721 } 722 tagsObj := []map[string]string{} 723 for _, k := range tagsKey { 724 tagsObj = append(tagsObj, map[string]string{"key": k}) 725 } 726 params["tags"] = tagsObj 727 728 _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") 729 return err 730 } 731 732 func (self *SRegion) CreateRdsTags(instanceId string, tags map[string]string) error { 733 params := map[string]interface{}{ 734 "action": "create", 735 } 736 737 tagsObj := []map[string]string{} 738 for k, v := range tags { 739 tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) 740 } 741 params["tags"] = tagsObj 742 743 _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") 744 return err 745 } 746 747 func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { 748 if len(conf.OriginDBInstanceExternalId) == 0 { 749 conf.OriginDBInstanceExternalId = rds.Id 750 } 751 return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) 752 } 753 754 func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { 755 source := map[string]interface{}{ 756 "type": "backup", 757 "backup_id": backupId, 758 } 759 if len(origin) > 0 { 760 source["instance_id"] = origin 761 } 762 if len(databases) > 0 { 763 source["database_name"] = databases 764 } 765 params := map[string]interface{}{ 766 "source": source, 767 "target": map[string]string{ 768 "instance_id": target, 769 }, 770 } 771 _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) 772 if err != nil { 773 return errors.Wrap(err, "dbinstance.recovery") 774 } 775 return nil 776 } 777 778 func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { 779 return rds.region.RenewInstance(rds.Id, bc) 780 }