feat: rds recovery new instance from backup supported

This commit is contained in:
Qu Xuan
2020-11-19 10:16:43 +08:00
parent b9565f288a
commit b6917c5604
15 changed files with 396 additions and 38 deletions

View File

@@ -142,6 +142,9 @@ type DBInstanceCreateInput struct {
// required: true
DiskSizeGB int `json:"disk_size_gb"`
// 指定连接端口
Port int `json:"port"`
// rds初始化密码
// 阿里云不需要此参数
// 华为云会默认创建一个用户,若不传此参数, 则为随机密码
@@ -163,6 +166,9 @@ type DBInstanceCreateInput struct {
// swagger:ignore
Provider string
// 从备份中创建新实例
DBInstancebackupId string `json:"dbinstancebackup_id"`
}
type SDBInstanceChangeConfigInput struct {

View File

@@ -30,6 +30,7 @@ import (
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
@@ -821,3 +822,15 @@ func NewIPv4AddrValidator(key string) *ValidatorIPv4Addr {
v.SetParent(v)
return v
}
var ValidateModel = func(userCred mcclient.TokenCredential, manager db.IStandaloneModelManager, id *string) (db.IModel, error) {
model, err := manager.FetchByIdOrName(userCred, *id)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(manager.Keyword(), *id)
}
return nil, httperrors.NewGeneralError(err)
}
*id = model.GetId()
return model, nil
}

View File

@@ -16,6 +16,14 @@ package cloudprovider
import "yunion.io/x/onecloud/pkg/util/billing"
type TBackupMethod string
const (
BackupMethodLogical = TBackupMethod("Logical")
BackupMethodPhysical = TBackupMethod("Physical")
BackupMethodUnknown = TBackupMethod("")
)
type SDBInstanceNetwork struct {
IP string
NetworkId string
@@ -55,6 +63,9 @@ type SManagedDBInstanceCreateConfig struct {
ProjectId string
BillingCycle *billing.SBillingCycle
// 仅从备份恢复到新实例用到
RdsId string
}
type SManagedDBInstanceChangeConfig struct {

View File

@@ -816,6 +816,9 @@ type ICloudDBInstanceBackup interface {
GetBackupSizeMb() int
GetDBNames() string
GetBackupMode() string
GetBackupMethod() TBackupMethod
CreateICloudDBInstance(opts *SManagedDBInstanceCreateConfig) (ICloudDBInstance, error)
Delete() error
}

View File

@@ -85,9 +85,8 @@ type SDBInstanceBackup struct {
// example: 32
BackupSizeMb int `nullable:"false" list:"user" json:"backup_size_mb"`
// RDS实例Id
// example: 239b9663-6d06-4ef4-8cfc-320a7fb6660d
// DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"`
// 备份方式 Logical|Physical
BackupMethod string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"backup_method"`
}
func (manager *SDBInstanceBackupManager) GetContextManagers() [][]db.IModelManager {
@@ -369,6 +368,46 @@ func (backup *SDBInstanceBackup) GetIRegion() (cloudprovider.ICloudRegion, error
}
func (backup *SDBInstanceBackup) GetIDBInstanceBackup() (cloudprovider.ICloudDBInstanceBackup, error) {
if len(backup.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
}
if len(backup.DBInstanceId) > 0 {
rds, err := backup.GetDBInstance()
if err != nil {
return nil, errors.Wrapf(err, "GetDBInstance")
}
iRds, err := rds.GetIDBInstance()
if err != nil {
return nil, errors.Wrapf(err, "GetIDBInstance")
}
err = cloudprovider.Wait(time.Second*3, time.Second*15, func() (bool, error) {
backups, err := iRds.GetIDBInstanceBackups()
if err != nil {
return false, errors.Wrapf(err, "GetIDBInstanceBackups")
}
for i := range backups {
if backups[i].GetGlobalId() == backup.ExternalId {
return true, nil
}
}
log.Warningf("failed to found backup %s", backup.ExternalId)
return false, nil
})
if err != nil {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "timeout for search backup %s", backup.ExternalId)
}
backups, err := iRds.GetIDBInstanceBackups()
if err != nil {
return nil, errors.Wrapf(err, "GetIDBInstanceBackups")
}
for i := range backups {
if backups[i].GetGlobalId() == backup.ExternalId {
return backups[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "search backup %s", backup.ExternalId)
}
iRegion, err := backup.GetIRegion()
if err != nil {
return nil, errors.Wrap(err, "backup.GetIRegion")
@@ -439,6 +478,7 @@ func (self *SDBInstanceBackup) SyncWithCloudDBInstanceBackup(
self.Engine = extBackup.GetEngine()
self.EngineVersion = extBackup.GetEngineVersion()
self.DBNames = extBackup.GetDBNames()
self.BackupMethod = string(extBackup.GetBackupMethod())
if dbinstanceId := extBackup.GetDBInstanceId(); len(dbinstanceId) > 0 {
//有可能云上删除了实例,未删除备份
@@ -497,6 +537,7 @@ func (manager *SDBInstanceBackupManager) newFromCloudDBInstanceBackup(
backup.BackupSizeMb = extBackup.GetBackupSizeMb()
backup.DBNames = extBackup.GetDBNames()
backup.BackupMode = extBackup.GetBackupMode()
backup.BackupMethod = string(extBackup.GetBackupMethod())
backup.ExternalId = extBackup.GetGlobalId()
if dbinstanceId := extBackup.GetDBInstanceId(); len(dbinstanceId) > 0 {
@@ -591,3 +632,67 @@ func (manager *SDBInstanceBackupManager) ListItemExportKeys(ctx context.Context,
func (self *SDBInstanceBackup) GetChangeOwnerCandidateDomainIds() []string {
return self.SManagedResourceBase.GetChangeOwnerCandidateDomainIds()
}
func (self *SDBInstanceBackup) fillRdsConfig(output *api.DBInstanceCreateInput) error {
if self.Status != api.DBINSTANCE_BACKUP_READY {
return fmt.Errorf("backup %s status is %s require %s", self.Name, self.Status, api.DBINSTANCE_BACKUP_READY)
}
if len(self.DBInstanceId) == 0 {
if len(self.Engine) == 0 {
return fmt.Errorf("backup engine %s is unknown", self.Name)
}
output.Engine = self.Engine
if len(self.EngineVersion) == 0 {
return fmt.Errorf("backup engine version %s is unknown", self.Name)
}
output.EngineVersion = self.EngineVersion
return nil
}
rds, err := self.GetDBInstance()
if err != nil {
return errors.Wrapf(err, "backup.GetDBInstance")
}
if len(output.NetworkId) == 0 {
network, _ := rds.GetDBNetwork()
if network != nil {
output.NetworkId = network.NetworkId
}
}
if output.VcpuCount == 0 {
output.VcpuCount = rds.VcpuCount
}
if output.VmemSizeMb == 0 {
output.VmemSizeMb = rds.VmemSizeMb
}
if output.DiskSizeGB == 0 {
output.DiskSizeGB = rds.DiskSizeGB
}
if output.Port == 0 {
output.Port = rds.Port
}
if len(output.Category) == 0 {
output.Category = rds.Category
}
if len(output.StorageType) == 0 {
output.StorageType = rds.StorageType
}
output.Engine = rds.Engine
output.EngineVersion = rds.EngineVersion
if len(output.InstanceType) == 0 {
output.InstanceType = rds.InstanceType
}
if len(output.VpcId) == 0 {
output.VpcId = rds.VpcId
}
if len(output.Zone1) == 0 {
output.Zone1 = rds.Zone1
}
if len(output.Zone2) == 0 {
output.Zone2 = rds.Zone2
}
if len(output.Zone3) == 0 {
output.Zone3 = rds.Zone3
}
return nil
}

View File

@@ -18,6 +18,7 @@ import (
"context"
"database/sql"
"fmt"
"net"
"strings"
"time"
@@ -135,6 +136,9 @@ type SDBInstance struct {
Zone2 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
// 可用区3
Zone3 string `width:"36" charset:"ascii" nullable:"false" create:"optional" list:"user"`
// 从备份创建新实例
DBInstancebackupId string `width:"36" name:"dbinstancebackup_id" charset:"ascii" nullable:"false" create:"optional"`
}
func (manager *SDBInstanceManager) GetContextManagers() [][]db.IModelManager {
@@ -274,8 +278,18 @@ func (man *SDBInstanceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field
}
func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (*jsonutils.JSONDict, error) {
if len(input.DBInstancebackupId) > 0 {
_backup, err := validators.ValidateModel(userCred, DBInstanceBackupManager, &input.DBInstancebackupId)
if err != nil {
return nil, err
}
backup := _backup.(*SDBInstanceBackup)
err = backup.fillRdsConfig(&input)
if err != nil {
return nil, err
}
}
data := input.JSON(input)
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
addressV := validators.NewIPv4AddrValidator("address")
secgroupV := validators.NewModelIdOrNameValidator("secgroup", "secgroup", ownerId)
masterV := validators.NewModelIdOrNameValidator("master_instance", "dbinstance", ownerId)
@@ -283,7 +297,6 @@ func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred
zone2V := validators.NewModelIdOrNameValidator("zone2", "zone", ownerId)
zone3V := validators.NewModelIdOrNameValidator("zone3", "zone", ownerId)
keyV := map[string]validators.IValidator{
"network": networkV,
"address": addressV.Optional(true),
"master": masterV.ModelIdKey("master_instance_id").Optional(true),
"secgroup": secgroupV.Optional(true),
@@ -318,10 +331,36 @@ func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred
}
}
network := networkV.Model.(*SNetwork)
input.NetworkExternalId = network.ExternalId
var vpc *SVpc
var network *SNetwork
if len(input.NetworkId) > 0 {
_network, err := validators.ValidateModel(userCred, NetworkManager, &input.NetworkId)
if err != nil {
return nil, err
}
network = _network.(*SNetwork)
input.NetworkExternalId = network.ExternalId
if len(input.Address) > 0 {
ip := net.ParseIP(input.Address).To4()
if ip == nil {
return nil, httperrors.NewInputParameterError("invalid address: %s", input.Address)
}
addr, _ := netutils.NewIPV4Addr(input.Address)
if !network.IsAddressInRange(addr) {
return nil, httperrors.NewInputParameterError("Ip %s not in network %s(%s) range", input.Address, network.Name, network.Id)
}
}
vpc = network.GetVpc()
} else if len(input.VpcId) > 0 {
_vpc, err := validators.ValidateModel(userCred, VpcManager, &input.VpcId)
if err != nil {
return nil, err
}
vpc = _vpc.(*SVpc)
} else {
return nil, httperrors.NewMissingParameterError("vpc_id")
}
vpc := network.GetVpc()
input.VpcId = vpc.Id
input.ManagerId = vpc.ManagerId
cloudprovider := vpc.GetCloudprovider()

View File

@@ -154,6 +154,7 @@ type IDBInstanceDriver interface {
ValidateResetDBInstancePassword(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, account string) error
RequestCreateDBInstance(ctx context.Context, userCred mcclient.TokenCredential, dbinstance *SDBInstance, task taskman.ITask) error
RequestCreateDBInstanceFromBackup(ctx context.Context, userCred mcclient.TokenCredential, dbinstance *SDBInstance, task taskman.ITask) error
RequestCreateDBInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, backup *SDBInstanceBackup, task taskman.ITask) error
RequestChangeDBInstanceConfig(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, task taskman.ITask) error

View File

@@ -1000,25 +1000,26 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
return input, httperrors.NewInputParameterError("slave dbinstance not support prepaid billing type")
}
wire := network.GetWire()
if wire == nil {
return input, httperrors.NewGeneralError(fmt.Errorf("failed to found wire for network %s(%s)", network.Name, network.Id))
}
zone := wire.GetZone()
if zone == nil {
return input, httperrors.NewGeneralError(fmt.Errorf("failed to found zone for wire %s(%s)", wire.Name, wire.Id))
}
match := false
for _, sku := range skus {
if utils.IsInStringArray(zone.Id, []string{sku.Zone1, sku.Zone2, sku.Zone3}) {
match = true
break
if network != nil {
wire := network.GetWire()
if wire == nil {
return input, httperrors.NewGeneralError(fmt.Errorf("failed to found wire for network %s(%s)", network.Name, network.Id))
}
zone := wire.GetZone()
if zone == nil {
return input, httperrors.NewGeneralError(fmt.Errorf("failed to found zone for wire %s(%s)", wire.Name, wire.Id))
}
}
if !match {
return input, httperrors.NewInputParameterError("failed to match any skus in the network %s(%s) zone %s(%s)", network.Name, network.Id, zone.Name, zone.Id)
match := false
for _, sku := range skus {
if utils.IsInStringArray(zone.Id, []string{sku.Zone1, sku.Zone2, sku.Zone3}) {
match = true
break
}
}
if !match {
return input, httperrors.NewInputParameterError("failed to match any skus in the network %s(%s) zone %s(%s)", network.Name, network.Id, zone.Name, zone.Id)
}
}
var master *models.SDBInstance

View File

@@ -285,6 +285,10 @@ func (self *SBaseRegionDriver) RequestCreateDBInstance(ctx context.Context, user
return fmt.Errorf("Not Implement RequestCreateDBInstance")
}
func (self *SBaseRegionDriver) RequestCreateDBInstanceFromBackup(ctx context.Context, userCred mcclient.TokenCredential, dbinstance *models.SDBInstance, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestCreateDBInstanceFromBackup")
}
func (self *SBaseRegionDriver) RequestCreateDBInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, dbinstance *models.SDBInstance, backup *models.SDBInstanceBackup, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestCreateDBInstanceBackup")
}

View File

@@ -1738,6 +1738,73 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstanceFromBackup(ctx context.Context, userCred mcclient.TokenCredential, rds *models.SDBInstance, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
_backup, err := models.DBInstanceBackupManager.FetchById(rds.DBInstancebackupId)
if err != nil {
return nil, errors.Wrapf(err, "DBInstanceBackupManager.FetchById(%s)", rds.DBInstancebackupId)
}
backup := _backup.(*models.SDBInstanceBackup)
iBackup, err := backup.GetIDBInstanceBackup()
if err != nil {
return nil, errors.Wrapf(err, "backup.GetIDBInstanceBackup")
}
vpc, err := rds.GetVpc()
if err != nil {
return nil, errors.Wrap(err, "rds.GetVpc()")
}
desc := cloudprovider.SManagedDBInstanceCreateConfig{
Name: rds.Name,
Description: rds.Description,
StorageType: rds.StorageType,
DiskSizeGB: rds.DiskSizeGB,
VcpuCount: rds.VcpuCount,
VmemSizeMb: rds.VmemSizeMb,
VpcId: vpc.ExternalId,
Engine: rds.Engine,
EngineVersion: rds.EngineVersion,
Category: rds.Category,
Port: rds.Port,
}
if len(backup.DBInstanceId) > 0 {
parentRds, err := backup.GetDBInstance()
if err != nil {
return nil, errors.Wrapf(err, "backup.GetDBInstance")
}
desc.RdsId = parentRds.ExternalId
}
log.Debugf("create from backup params: %s", jsonutils.Marshal(desc).String())
if rds.BillingType == billing_api.BILLING_TYPE_PREPAID {
bc, err := billing.ParseBillingCycle(rds.BillingCycle)
if err != nil {
log.Errorf("failed to parse billing cycle %s: %v", rds.BillingCycle, err)
} else if bc.IsValid() {
desc.BillingCycle = &bc
desc.BillingCycle.AutoRenew = rds.AutoRenew
}
}
iRds, err := iBackup.CreateICloudDBInstance(&desc)
if err != nil {
return nil, errors.Wrapf(err, "iBackup.CreateICloudDBInstance")
}
err = db.SetExternalId(rds, userCred, iRds.GetGlobalId())
if err != nil {
return nil, errors.Wrapf(err, "db.SetExternalId")
}
err = cloudprovider.WaitStatus(iRds, api.DBINSTANCE_RUNNING, time.Second*5, time.Hour*1)
if err != nil {
return nil, errors.Wrapf(err, "cloudprovider.WaitStatus runing")
}
return nil, nil
})
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error {
task.ScheduleRun(nil)
return nil
@@ -2347,14 +2414,9 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstanceBackup(ct
return nil, errors.Wrapf(err, "iRegion.GetIDBInstanceBackupById(%s)", backupId)
}
_, err = db.Update(backup, func() error {
backup.StartTime = iBackup.GetStartTime()
backup.EndTime = iBackup.GetEndTime()
backup.BackupSizeMb = iBackup.GetBackupSizeMb()
return nil
})
err = backup.SyncWithCloudDBInstanceBackup(ctx, userCred, iBackup, instance.GetCloudprovider())
if err != nil {
return nil, errors.Wrap(err, "db.Update")
log.Warningf("sync backup info error: %v", err)
}
instance.SetStatus(userCred, api.DBINSTANCE_RUNNING, "")

View File

@@ -48,12 +48,17 @@ func (self *DBInstanceCreateTask) OnInit(ctx context.Context, obj db.IStandalone
self.CreateDBInstance(ctx, dbinstance)
}
func (self *DBInstanceCreateTask) CreateDBInstance(ctx context.Context, dbinstance *models.SDBInstance) {
region := dbinstance.GetRegion()
func (self *DBInstanceCreateTask) CreateDBInstance(ctx context.Context, rds *models.SDBInstance) {
region := rds.GetRegion()
self.SetStage("OnCreateDBInstanceComplete", nil)
err := region.GetDriver().RequestCreateDBInstance(ctx, self.UserCred, dbinstance, self)
var err error
if len(rds.DBInstancebackupId) > 0 {
err = region.GetDriver().RequestCreateDBInstanceFromBackup(ctx, self.UserCred, rds, self)
} else {
err = region.GetDriver().RequestCreateDBInstance(ctx, self.UserCred, rds, self)
}
if err != nil {
self.taskFailed(ctx, dbinstance, err)
self.taskFailed(ctx, rds, err)
return
}
}

View File

@@ -0,0 +1,66 @@
// 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 options
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
)
type DBInstanceCreateOptions struct {
NAME string `help:"DBInstance Name"`
InstanceType string `help:"InstanceType for DBInstance"`
VcpuCount int `help:"Core of cpu for DBInstance"`
VmemSizeMb int `help:"Memory size of DBInstance"`
Port int `help:"Port of DBInstance"`
Category string `help:"Category of DBInstance"`
Network string `help:"Network of DBInstance"`
Address string `help:"Address of DBInstance"`
Engine string `help:"Engine of DBInstance"`
EngineVersion string `help:"EngineVersion of DBInstance Engine"`
StorageType string `help:"StorageTyep of DBInstance"`
Secgroup string `help:"Secgroup name or Id for DBInstance"`
Zone string `help:"ZoneId or name for DBInstance"`
DiskSizeGB int `help:"Storage size for DBInstance"`
Duration string `help:"Duration for DBInstance"`
AllowDelete *bool `help:"not lock dbinstance" `
Tags []string `help:"Tags info,prefix with 'user:', eg: user:project=default" json:"-"`
DBInstancebackupId string `help:"create dbinstance from backup" json:"dbinstancebackup_id"`
}
func (opts *DBInstanceCreateOptions) Params() (*jsonutils.JSONDict, error) {
params, err := StructToParams(opts)
if err != nil {
return nil, err
}
Tagparams := jsonutils.NewDict()
for _, tag := range opts.Tags {
info := strings.Split(tag, "=")
if len(info) == 2 {
if len(info[0]) == 0 {
return nil, fmt.Errorf("invalidate tag info %s", tag)
}
Tagparams.Add(jsonutils.NewString(info[1]), info[0])
} else if len(info) == 1 {
Tagparams.Add(jsonutils.NewString(info[0]), info[0])
} else {
return nil, fmt.Errorf("invalidate tag info %s", tag)
}
}
params.Add(Tagparams, "__meta__")
return params, nil
}

View File

@@ -19,8 +19,7 @@ import (
"strings"
"time"
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
@@ -325,3 +324,33 @@ func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) (strin
}
return "", fmt.Errorf("failed to found backup job %s backupid", jobId)
}
func (self *SDBInstanceBackup) GetBackupMethod() cloudprovider.TBackupMethod {
return cloudprovider.TBackupMethod(self.BackupMethod)
}
func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
rdsId, err := self.region.CreateDBInstanceByBackup(self.BackupId, opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateDBInstanceByBackup")
}
return self.region.GetDBInstanceDetail(rdsId)
}
func (self *SRegion) CreateDBInstanceByBackup(backupId string, opts *cloudprovider.SManagedDBInstanceCreateConfig) (string, error) {
params := map[string]string{
"DBInstanceId": opts.RdsId,
"DBInstanceStorageType": opts.StorageType,
"PayType": "Postpaid",
"BackupId": backupId,
}
resp, err := self.rdsRequest("CloneDBInstance", params)
if err != nil {
return "", errors.Wrapf(err, "rdsRequest")
}
rdsId, err := resp.GetString("DBInstanceId")
if err != nil {
return "", fmt.Errorf("missing DBInstanceId after CloneDBInstance")
}
return rdsId, nil
}

View File

@@ -17,7 +17,10 @@ package multicloud
import (
"fmt"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SDBInstanceBackupBase struct {
@@ -35,3 +38,11 @@ func (backup *SDBInstanceBackupBase) Delete() error {
func (backup *SDBInstanceBackupBase) GetProjectId() string {
return ""
}
func (backup *SDBInstanceBackupBase) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) {
return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateICloudDBInstance")
}
func (backup *SDBInstanceBackupBase) GetBackupMethod() cloudprovider.TBackupMethod {
return cloudprovider.BackupMethodUnknown
}

View File

@@ -23,6 +23,7 @@ import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/multicloud"
)
type OperationError struct {
@@ -32,6 +33,7 @@ type OperationError struct {
}
type SDBInstanceBackup struct {
multicloud.SDBInstanceBackupBase
rds *SDBInstance
Kind string