mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
753 lines
20 KiB
Go
753 lines
20 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package huawei
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
|
|
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
|
|
api "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/multicloud"
|
|
"yunion.io/x/onecloud/pkg/util/billing"
|
|
)
|
|
|
|
type SBackupStrategy struct {
|
|
KeepDays int
|
|
StartTime string
|
|
}
|
|
|
|
type SDatastore struct {
|
|
Type string
|
|
Version string
|
|
}
|
|
|
|
type SHa struct {
|
|
ReplicationMode string
|
|
}
|
|
|
|
type SNonde struct {
|
|
AvailabilityZone string
|
|
Id string
|
|
Name string
|
|
Role string
|
|
Staus string
|
|
}
|
|
|
|
type SVolume struct {
|
|
Size int
|
|
Type string
|
|
}
|
|
|
|
type SRelatedInstance struct {
|
|
Id string
|
|
Type string
|
|
}
|
|
|
|
type SDBInstance struct {
|
|
multicloud.SDBInstanceBase
|
|
region *SRegion
|
|
|
|
flavorCache []SDBInstanceFlavor
|
|
|
|
BackupStrategy SBackupStrategy
|
|
Created string //time.Time
|
|
Datastore SDatastore
|
|
DbUserName string
|
|
DIskEncryptionId string
|
|
FlavorRef string
|
|
Ha SHa
|
|
Id string
|
|
MaintenanceWindow string
|
|
Name string
|
|
Nodes []SNonde
|
|
Port int
|
|
PrivateIps []string
|
|
PublicIps []string
|
|
Region string
|
|
RelatedInstance []SRelatedInstance
|
|
SecurityGroupId string
|
|
Status string
|
|
SubnetId string
|
|
SwitchStrategy string
|
|
TimeZone string
|
|
Type string
|
|
Updated string //time.Time
|
|
Volume SVolume
|
|
VpcId string
|
|
EnterpriseProjectId string
|
|
}
|
|
|
|
func (region *SRegion) GetDBInstances() ([]SDBInstance, error) {
|
|
params := map[string]string{}
|
|
dbinstances := []SDBInstance{}
|
|
err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances)
|
|
return dbinstances, err
|
|
}
|
|
|
|
func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) {
|
|
if len(instanceId) == 0 {
|
|
return nil, cloudprovider.ErrNotFound
|
|
}
|
|
instance := SDBInstance{region: region}
|
|
err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance)
|
|
return &instance, err
|
|
}
|
|
|
|
func (rds *SDBInstance) GetName() string {
|
|
return rds.Name
|
|
}
|
|
|
|
func (rds *SDBInstance) GetId() string {
|
|
return rds.Id
|
|
}
|
|
|
|
func (rds *SDBInstance) GetGlobalId() string {
|
|
return rds.GetId()
|
|
}
|
|
|
|
// 值为“BUILD”,表示实例正在创建。
|
|
// 值为“ACTIVE”,表示实例正常。
|
|
// 值为“FAILED”,表示实例异常。
|
|
// 值为“FROZEN”,表示实例冻结。
|
|
// 值为“MODIFYING”,表示实例正在扩容。
|
|
// 值为“REBOOTING”,表示实例正在重启。
|
|
// 值为“RESTORING”,表示实例正在恢复。
|
|
// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。
|
|
// 值为“SWITCHOVER”,表示实例正在主备切换。
|
|
// 值为“MIGRATING”,表示实例正在迁移。
|
|
// 值为“BACKING UP”,表示实例正在进行备份。
|
|
// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。
|
|
// 值为“STORAGE FULL”,表示实例磁盘空间满。
|
|
|
|
func (rds *SDBInstance) GetStatus() string {
|
|
switch rds.Status {
|
|
case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT":
|
|
return api.DBINSTANCE_DEPLOYING
|
|
case "ACTIVE":
|
|
return api.DBINSTANCE_RUNNING
|
|
case "FAILED", "FROZEN", "STORAGE FULL":
|
|
return api.DBINSTANCE_UNKNOWN
|
|
case "REBOOTING":
|
|
return api.DBINSTANCE_REBOOTING
|
|
case "RESTORING":
|
|
return api.DBINSTANCE_RESTORING
|
|
case "MIGRATING":
|
|
return api.DBINSTANCE_MIGRATING
|
|
case "BACKING UP":
|
|
return api.DBINSTANCE_BACKING_UP
|
|
}
|
|
return rds.Status
|
|
}
|
|
|
|
func (rds *SDBInstance) GetBillingType() string {
|
|
_, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id))
|
|
if err != nil {
|
|
return billing_api.BILLING_TYPE_POSTPAID
|
|
}
|
|
return billing_api.BILLING_TYPE_PREPAID
|
|
}
|
|
|
|
func (rds *SDBInstance) GetSecurityGroupId() string {
|
|
return rds.SecurityGroupId
|
|
}
|
|
|
|
func (rds *SDBInstance) fetchFlavor() error {
|
|
if len(rds.flavorCache) > 0 {
|
|
return nil
|
|
}
|
|
flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rds.flavorCache = flavors
|
|
return nil
|
|
}
|
|
|
|
func (rds *SDBInstance) GetExpiredAt() time.Time {
|
|
order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id))
|
|
if err != nil {
|
|
return time.Time{}
|
|
}
|
|
return order.ExpireTime
|
|
}
|
|
|
|
func (rds *SDBInstance) GetStorageType() string {
|
|
return rds.Volume.Type
|
|
}
|
|
|
|
func (rds *SDBInstance) GetCreatedAt() time.Time {
|
|
t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created)
|
|
if err != nil {
|
|
return time.Time{}
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (rds *SDBInstance) GetEngine() string {
|
|
return rds.Datastore.Type
|
|
}
|
|
|
|
func (rds *SDBInstance) GetEngineVersion() string {
|
|
return rds.Datastore.Version
|
|
}
|
|
|
|
func (rds *SDBInstance) GetInstanceType() string {
|
|
return rds.FlavorRef
|
|
}
|
|
|
|
func (rds *SDBInstance) GetCategory() string {
|
|
switch rds.Type {
|
|
case "Single":
|
|
return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE
|
|
case "Ha":
|
|
return api.HUAWEI_DBINSTANCE_CATEGORY_HA
|
|
case "Replica":
|
|
return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA
|
|
}
|
|
return rds.Type
|
|
}
|
|
|
|
func (rds *SDBInstance) GetVcpuCount() int {
|
|
err := rds.fetchFlavor()
|
|
if err != nil {
|
|
log.Errorf("failed to fetch flavors: %v", err)
|
|
return 0
|
|
}
|
|
for _, flavor := range rds.flavorCache {
|
|
if flavor.SpecCode == rds.FlavorRef {
|
|
return flavor.Vcpus
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (rds *SDBInstance) GetVmemSizeMB() int {
|
|
err := rds.fetchFlavor()
|
|
if err != nil {
|
|
log.Errorf("failed to fetch flavors: %v", err)
|
|
return 0
|
|
}
|
|
for _, flavor := range rds.flavorCache {
|
|
if flavor.SpecCode == rds.FlavorRef {
|
|
return flavor.Ram * 1024
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (rds *SDBInstance) GetDiskSizeGB() int {
|
|
return rds.Volume.Size
|
|
}
|
|
|
|
func (rds *SDBInstance) GetPort() int {
|
|
return rds.Port
|
|
}
|
|
|
|
func (rds *SDBInstance) GetMaintainTime() string {
|
|
return rds.MaintenanceWindow
|
|
}
|
|
|
|
func (rds *SDBInstance) GetIVpcId() string {
|
|
return rds.VpcId
|
|
}
|
|
|
|
func (rds *SDBInstance) GetProjectId() string {
|
|
return rds.EnterpriseProjectId
|
|
}
|
|
|
|
func (rds *SDBInstance) Refresh() error {
|
|
instance, err := rds.region.GetDBInstance(rds.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return jsonutils.Update(rds, instance)
|
|
}
|
|
|
|
func (rds *SDBInstance) GetZone1Id() string {
|
|
return rds.GetZoneIdByRole("master")
|
|
}
|
|
|
|
func (rds *SDBInstance) GetZoneIdByRole(role string) string {
|
|
for _, node := range rds.Nodes {
|
|
if node.Role == role {
|
|
zone, err := rds.region.getZoneById(node.AvailabilityZone)
|
|
if err != nil {
|
|
log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err)
|
|
return ""
|
|
}
|
|
return zone.GetGlobalId()
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (rds *SDBInstance) GetZone2Id() string {
|
|
return rds.GetZoneIdByRole("slave")
|
|
}
|
|
|
|
func (rds *SDBInstance) GetZone3Id() string {
|
|
return ""
|
|
}
|
|
|
|
type SRdsNetwork struct {
|
|
SubnetId string
|
|
IP string
|
|
}
|
|
|
|
func (rds *SDBInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) {
|
|
for _, ip := range rds.PrivateIps {
|
|
inetwork := &cloudprovider.SDBInstanceNetwork{
|
|
IP: ip,
|
|
NetworkId: rds.SubnetId,
|
|
}
|
|
return inetwork, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("failed to found network for huawei rds %s", rds.Name)
|
|
}
|
|
|
|
func (rds *SDBInstance) GetInternalConnectionStr() string {
|
|
for _, ip := range rds.PrivateIps {
|
|
return ip
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (rds *SDBInstance) GetConnectionStr() string {
|
|
for _, ip := range rds.PublicIps {
|
|
return ip
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) {
|
|
dbinstance, err := region.GetDBInstance(instanceId)
|
|
if err != nil {
|
|
log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err)
|
|
}
|
|
return dbinstance, err
|
|
}
|
|
|
|
func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) {
|
|
instances, err := region.GetDBInstances()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "region.GetDBInstances()")
|
|
}
|
|
idbinstances := []cloudprovider.ICloudDBInstance{}
|
|
for i := 0; i < len(instances); i++ {
|
|
instances[i].region = region
|
|
idbinstances = append(idbinstances, &instances[i])
|
|
}
|
|
return idbinstances, nil
|
|
}
|
|
|
|
func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) {
|
|
parameters, err := rds.region.GetDBInstanceParameters(rds.Id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iparameters := []cloudprovider.ICloudDBInstanceParameter{}
|
|
for i := 0; i < len(parameters); i++ {
|
|
iparameters = append(iparameters, ¶meters[i])
|
|
}
|
|
return iparameters, nil
|
|
}
|
|
|
|
func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) {
|
|
databases, err := rds.region.GetDBInstanceDatabases(rds.Id)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)")
|
|
}
|
|
|
|
idatabase := []cloudprovider.ICloudDBInstanceDatabase{}
|
|
for i := 0; i < len(databases); i++ {
|
|
databases[i].instance = rds
|
|
idatabase = append(idatabase, &databases[i])
|
|
}
|
|
return idatabase, nil
|
|
}
|
|
|
|
func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) {
|
|
accounts, err := rds.region.GetDBInstanceAccounts(rds.Id)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)")
|
|
}
|
|
|
|
user := "root"
|
|
if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER {
|
|
user = "rduser"
|
|
}
|
|
|
|
accounts = append(accounts, SDBInstanceAccount{
|
|
Name: user,
|
|
instance: rds,
|
|
})
|
|
|
|
iaccounts := []cloudprovider.ICloudDBInstanceAccount{}
|
|
for i := 0; i < len(accounts); i++ {
|
|
accounts[i].instance = rds
|
|
iaccounts = append(iaccounts, &accounts[i])
|
|
}
|
|
return iaccounts, nil
|
|
}
|
|
|
|
func (rds *SDBInstance) Delete() error {
|
|
return rds.region.DeleteDBInstance(rds.Id)
|
|
}
|
|
|
|
func (region *SRegion) DeleteDBInstance(instanceId string) error {
|
|
_, err := region.ecsClient.DBInstance.Delete(instanceId, nil)
|
|
return err
|
|
}
|
|
|
|
func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
|
|
zoneIds := []string{}
|
|
zones, err := region.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, zone := range zones {
|
|
zoneIds = append(zoneIds, zone.GetId())
|
|
}
|
|
|
|
params := map[string]interface{}{
|
|
"region": region.ID,
|
|
"name": desc.Name,
|
|
"datastore": map[string]string{
|
|
"type": desc.Engine,
|
|
"version": desc.EngineVersion,
|
|
},
|
|
"password": desc.Password,
|
|
"volume": map[string]interface{}{
|
|
"type": desc.StorageType,
|
|
"size": desc.DiskSizeGB,
|
|
},
|
|
"vpc_id": desc.VpcId,
|
|
"subnet_id": desc.NetworkId,
|
|
"security_group_id": desc.SecgroupId,
|
|
}
|
|
|
|
if len(desc.ProjectId) > 0 {
|
|
params["enterprise_project_id"] = desc.ProjectId
|
|
}
|
|
|
|
if len(desc.MasterInstanceId) > 0 {
|
|
params["replica_of_id"] = desc.MasterInstanceId
|
|
}
|
|
|
|
switch desc.Category {
|
|
case api.HUAWEI_DBINSTANCE_CATEGORY_HA:
|
|
switch desc.Engine {
|
|
case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL:
|
|
params["ha"] = map[string]string{
|
|
"mode": "Ha",
|
|
"replication_mode": "async",
|
|
}
|
|
case api.DBINSTANCE_TYPE_SQLSERVER:
|
|
params["ha"] = map[string]string{
|
|
"mode": "Ha",
|
|
"replication_mode": "sync",
|
|
}
|
|
}
|
|
if len(desc.ZoneIds) == 0 {
|
|
for _, masterZoneId := range zoneIds {
|
|
for _, slaveZoneId := range zoneIds {
|
|
desc.ZoneIds = append(desc.ZoneIds, fmt.Sprintf("%s,%s", masterZoneId, slaveZoneId))
|
|
}
|
|
}
|
|
}
|
|
case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE:
|
|
if len(desc.ZoneIds) == 0 {
|
|
desc.ZoneIds = zoneIds
|
|
}
|
|
case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA:
|
|
}
|
|
|
|
if desc.BillingCycle != nil {
|
|
periodType := "month"
|
|
periodNum := desc.BillingCycle.GetMonths()
|
|
if desc.BillingCycle.GetYears() > 0 {
|
|
periodType = "year"
|
|
periodNum = desc.BillingCycle.GetYears()
|
|
}
|
|
params["charge_info"] = map[string]interface{}{
|
|
"charge_mode": "prePaid",
|
|
"period_type": periodType,
|
|
"period_num": periodNum,
|
|
"is_auto_renew": false,
|
|
}
|
|
}
|
|
var resp jsonutils.JSONObject = nil
|
|
|
|
if len(desc.InstanceType) > 0 {
|
|
params["flavor_ref"] = desc.InstanceType
|
|
for _, zoneId := range desc.ZoneIds {
|
|
params["availability_zone"] = zoneId
|
|
resp, err = region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
|
|
if err == nil {
|
|
break
|
|
}
|
|
}
|
|
if err != nil {
|
|
log.Debugf("params: %s", jsonutils.Marshal(params).PrettyString())
|
|
return nil, errors.Wrap(err, "DBInstance.Create")
|
|
}
|
|
} else {
|
|
for _, spec := range desc.InstanceTypes {
|
|
params["flavor_ref"] = spec.InstanceType
|
|
for _, zoneId := range spec.ZoneIds {
|
|
params["availability_zone"] = zoneId
|
|
resp, err = region.ecsClient.DBInstance.Create(jsonutils.Marshal(params))
|
|
if err == nil {
|
|
break
|
|
}
|
|
}
|
|
if err == nil {
|
|
break
|
|
}
|
|
}
|
|
if err != nil {
|
|
log.Debugf("params: %s", jsonutils.Marshal(params).PrettyString())
|
|
return nil, errors.Wrap(err, "region.ecsClient.DBInstance.Create")
|
|
}
|
|
if resp == nil {
|
|
return nil, fmt.Errorf("dbinstance type %dC%dMB not avaiable", desc.VcpuCount, desc.VmemSizeMb)
|
|
}
|
|
}
|
|
|
|
instance := &SDBInstance{region: region}
|
|
err = resp.Unmarshal(instance, "instance")
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`)
|
|
}
|
|
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
|
err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) {
|
|
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
status, _ := job.GetString("status")
|
|
process, _ := job.GetString("process")
|
|
log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process)
|
|
if status == "Completed" {
|
|
return true, nil
|
|
}
|
|
if status == "Failed" {
|
|
return false, fmt.Errorf("create failed")
|
|
}
|
|
return false, nil
|
|
})
|
|
}
|
|
return instance, err
|
|
}
|
|
|
|
func (rds *SDBInstance) Reboot() error {
|
|
return rds.region.RebootDBInstance(rds.Id)
|
|
}
|
|
|
|
func (rds *SDBInstance) OpenPublicConnection() error {
|
|
return fmt.Errorf("Huawei current not support this operation")
|
|
//return rds.region.PublicConnectionAction(rds.Id, "openRC")
|
|
}
|
|
|
|
func (rds *SDBInstance) ClosePublicConnection() error {
|
|
return fmt.Errorf("Huawei current not support this operation")
|
|
//return rds.region.PublicConnectionAction(rds.Id, "closeRC")
|
|
}
|
|
|
|
func (region *SRegion) PublicConnectionAction(instanceId string, action string) error {
|
|
resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "")
|
|
if err != nil {
|
|
return errors.Wrapf(err, "rds.%s", action)
|
|
}
|
|
|
|
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
|
err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool {
|
|
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
|
if err != nil {
|
|
log.Errorf("failed to get job %s info error: %v", jobId, err)
|
|
return false
|
|
}
|
|
status, _ := job.GetString("status")
|
|
process, _ := job.GetString("process")
|
|
if status == "Completed" {
|
|
return true
|
|
}
|
|
log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process)
|
|
return false
|
|
})
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (region *SRegion) RebootDBInstance(instanceId string) error {
|
|
params := jsonutils.Marshal(map[string]interface{}{
|
|
"restart": map[string]string{},
|
|
})
|
|
resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 {
|
|
err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool {
|
|
job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId})
|
|
if err != nil {
|
|
log.Errorf("failed to get job %s info error: %v", jobId, err)
|
|
return false
|
|
}
|
|
status, _ := job.GetString("status")
|
|
process, _ := job.GetString("process")
|
|
if status == "Completed" {
|
|
return true
|
|
}
|
|
log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process)
|
|
return false
|
|
})
|
|
}
|
|
return err
|
|
}
|
|
|
|
type SDBInstanceFlavor struct {
|
|
Vcpus int
|
|
Ram int //单位GB
|
|
SpecCode string
|
|
InstanceMode string //实例模型
|
|
}
|
|
|
|
func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) {
|
|
flavors := []SDBInstanceFlavor{}
|
|
resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return flavors, jsonutils.Update(&flavors, resp.Data)
|
|
}
|
|
|
|
func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error {
|
|
return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password)
|
|
}
|
|
|
|
func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error {
|
|
params := map[string]string{
|
|
"name": account,
|
|
"password": password,
|
|
}
|
|
_, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "")
|
|
return err
|
|
}
|
|
|
|
func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error {
|
|
return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet)
|
|
}
|
|
|
|
func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error {
|
|
params := map[string]string{
|
|
"name": database,
|
|
"character_set": characterSet,
|
|
}
|
|
_, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "")
|
|
return err
|
|
}
|
|
|
|
func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error {
|
|
if rds.GetInstanceType() == desc.InstanceType {
|
|
desc.InstanceType = ""
|
|
}
|
|
|
|
if rds.GetDiskSizeGB() >= desc.DiskSizeGB {
|
|
desc.DiskSizeGB = 0
|
|
}
|
|
|
|
return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB)
|
|
}
|
|
|
|
func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error {
|
|
instance, err := region.GetIDBInstanceById(instanceId)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId)
|
|
}
|
|
|
|
if len(instanceType) > 0 {
|
|
params := map[string]map[string]string{
|
|
"resize_flavor": map[string]string{
|
|
"spec_code": instanceType,
|
|
},
|
|
}
|
|
_, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params))
|
|
if err != nil {
|
|
return errors.Wrap(err, "resize_flavor")
|
|
}
|
|
cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30)
|
|
}
|
|
if diskSizeGb > 0 {
|
|
params := map[string]map[string]int{
|
|
"enlarge_volume": map[string]int{
|
|
"size": diskSizeGb,
|
|
},
|
|
}
|
|
_, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params))
|
|
if err != nil {
|
|
return errors.Wrap(err, "enlarge_volume")
|
|
}
|
|
cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error {
|
|
if len(conf.OriginDBInstanceExternalId) == 0 {
|
|
conf.OriginDBInstanceExternalId = rds.Id
|
|
}
|
|
return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases)
|
|
}
|
|
|
|
func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error {
|
|
source := map[string]interface{}{
|
|
"type": "backup",
|
|
"backup_id": backupId,
|
|
}
|
|
if len(origin) > 0 {
|
|
source["instance_id"] = origin
|
|
}
|
|
if len(databases) > 0 {
|
|
source["database_name"] = databases
|
|
}
|
|
params := map[string]interface{}{
|
|
"source": source,
|
|
"target": map[string]string{
|
|
"instance_id": target,
|
|
},
|
|
}
|
|
_, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params))
|
|
if err != nil {
|
|
return errors.Wrap(err, "dbinstance.recovery")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error {
|
|
return rds.region.RenewInstance(rds.Id, bc)
|
|
}
|