dbinstance.go 19 KB

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