Merge pull request #13631 from rainzm/instancebackup/force_delete

Instancebackup force delete
This commit is contained in:
Zexi Li
2022-03-08 10:40:15 +08:00
committed by GitHub
10 changed files with 111 additions and 18 deletions
+2 -2
View File
@@ -34,7 +34,7 @@ func init() {
dbCmd := shell.NewResourceCmd(&modules.DiskBackups)
dbCmd.List(&compute.DiskBackupListOptions{})
dbCmd.Show(&compute.DiskBackupIdOptions{})
dbCmd.Delete(&compute.DiskBackupIdOptions{})
dbCmd.DeleteWithParam(&compute.DiskBackupDeleteOptions{})
dbCmd.Create(&compute.DiskBackupCreateOptions{})
dbCmd.Perform("recovery", &compute.DiskBackupRecoveryOptions{})
dbCmd.Perform("syncstatus", &compute.DiskBackupSyncstatusOptions{})
@@ -42,7 +42,7 @@ func init() {
ibCmd := shell.NewResourceCmd(&modules.InstanceBackups)
ibCmd.List(&compute.InstanceBackupListOptions{})
ibCmd.Show(&compute.InstanceBackupIdOptions{})
ibCmd.Delete(&compute.InstanceBackupIdOptions{})
ibCmd.DeleteWithParam(&compute.InstanceBackupDeleteOptions{})
ibCmd.Perform("recovery", &compute.InstanceBackupRecoveryOptions{})
ibCmd.Perform("pack", &compute.InstanceBackupPackOptions{})
ibCmd.PerformClass("create-from-package", &compute.InstanceBackupManagerCreateFromPackageOptions{})
+26
View File
@@ -362,6 +362,32 @@ func (cmd ResourceCmd) Delete(args IDeleteOpt) {
cmd.RunWithDesc("delete", fmt.Sprintf("Delete %s", man.GetKeyword()), args, callback)
}
type IDeleteWithParamOpt interface {
IDeleteOpt
QueryParams() (jsonutils.JSONObject, error)
}
func (cmd ResourceCmd) DeleteWithParam(args IDeleteWithParamOpt) {
man := cmd.manager
callback := func(s *mcclient.ClientSession, args IDeleteWithParamOpt) error {
queryParams, err := args.QueryParams()
if err != nil {
return err
}
params, err := args.Params()
if err != nil {
return err
}
ret, err := man.(modulebase.Manager).DeleteWithParam(s, args.GetId(), queryParams, params)
if err != nil {
return err
}
PrintObject(ret)
return nil
}
cmd.RunWithDesc("delete", fmt.Sprintf("Delete %s", man.GetKeyword()), args, callback)
}
type IWithDescOpt interface {
Description() string
}
+4
View File
@@ -44,6 +44,10 @@ const (
BACKUP_NOT_EXIST = "not_exist"
)
const (
BackupStorageOffline = "backup storage offline"
)
type BackupStorageCreateInput struct {
apis.EnabledStatusInfrasResourceBaseCreateInput
+23 -4
View File
@@ -16,6 +16,7 @@ package models
import (
"context"
"database/sql"
"reflect"
"time"
@@ -221,10 +222,23 @@ func (dm *SDiskBackupManager) ValidateCreateData(ctx context.Context, userCred m
if disk.Status != api.DISK_READY {
return input, httperrors.NewInvalidStatusError("disk %s status is not %s", disk.Name, api.DISK_READY)
}
_, err = validators.ValidateModel(userCred, BackupStorageManager, &input.BackupStorageId)
ibs, err := BackupStorageManager.FetchByIdOrName(userCred, input.BackupStorageId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError2(BackupStorageManager.Keyword(), input.BackupStorageId)
}
if errors.Cause(err) == sqlchemy.ErrDuplicateEntry {
return input, httperrors.NewDuplicateResourceError(BackupStorageManager.Keyword(), input.BackupStorageId)
}
return input, httperrors.NewGeneralError(err)
}
if err != nil {
return input, err
}
bs := ibs.(*SBackupStorage)
if bs.Status != api.BACKUPSTORAGE_STATUS_ONLINE {
return input, httperrors.NewForbiddenError("can't backup guest to backup storage with status %s", bs.Status)
}
storage, err := disk.GetStorage()
if err != nil {
return input, errors.Wrapf(err, "unable to get storage of disk %s", disk.GetId())
@@ -356,13 +370,18 @@ func (self *SDiskBackup) RealDelete(ctx context.Context, userCred mcclient.Token
}
func (self *SDiskBackup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartBackupDeleteTask(ctx, userCred, "")
forceDelete := jsonutils.QueryBoolean(query, "force", false)
return self.StartBackupDeleteTask(ctx, userCred, "", forceDelete)
}
func (self *SDiskBackup) StartBackupDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
func (self *SDiskBackup) StartBackupDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, forceDelete bool) error {
self.SetStatus(userCred, api.BACKUP_STATUS_DELETING, "")
log.Infof("start to delete diskbackup %s and set deleting", self.GetId())
task, err := taskman.TaskManager.NewTask(ctx, "DiskBackupDeleteTask", self, userCred, nil, parentTaskId, "", nil)
params := jsonutils.NewDict()
if forceDelete {
params.Set("force_delete", jsonutils.JSONTrue)
}
task, err := taskman.TaskManager.NewTask(ctx, "DiskBackupDeleteTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return err
} else {
+13 -3
View File
@@ -4748,9 +4748,19 @@ func (self *SGuest) PerformInstanceBackup(ctx context.Context, userCred mcclient
if backupStorageId == "" {
return nil, httperrors.NewMissingParameterError("backup_storage_id")
}
_, err = BackupStorageManager.FetchById(backupStorageId)
if err == sql.ErrNoRows {
return nil, httperrors.NewInputParameterError("unkown backup_storage_id %s", backupStorageId)
ibs, err := BackupStorageManager.FetchByIdOrName(userCred, backupStorageId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(BackupStorageManager.Keyword(), backupStorageId)
}
if errors.Cause(err) == sqlchemy.ErrDuplicateEntry {
return nil, httperrors.NewDuplicateResourceError(BackupStorageManager.Keyword(), backupStorageId)
}
return nil, httperrors.NewGeneralError(err)
}
bs := ibs.(*SBackupStorage)
if bs.Status != api.BACKUPSTORAGE_STATUS_ONLINE {
return nil, httperrors.NewForbiddenError("can't backup guest to backup storage with status %s", bs.Status)
}
instanceBackup, err := InstanceBackupManager.CreateInstanceBackup(ctx, userCred, self, name, backupStorageId)
if err != nil {
+8 -5
View File
@@ -376,14 +376,17 @@ func (self *SInstanceBackup) ValidateDeleteCondition(ctx context.Context, info j
func (self *SInstanceBackup) CustomizeDelete(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartInstanceBackupDeleteTask(ctx, userCred, "")
forceDelete := jsonutils.QueryBoolean(query, "force", false)
return self.StartInstanceBackupDeleteTask(ctx, userCred, "", forceDelete)
}
func (self *SInstanceBackup) StartInstanceBackupDeleteTask(
ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupDeleteTask", self, userCred, nil, parentTaskId, "", nil)
ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, forceDelete bool) error {
params := jsonutils.NewDict()
if forceDelete {
params.Set("force_delete", jsonutils.JSONTrue)
}
task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupDeleteTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
log.Errorf("%s", err)
return err
+2 -1
View File
@@ -1056,7 +1056,8 @@ func (self *SKVMRegionDriver) RequestDeleteInstanceBackup(ctx context.Context, i
params := jsonutils.NewDict()
params.Set("del_backup_id", jsonutils.NewString(backups[0].Id))
task.SetStage("OnKvmDiskBackupDelete", params)
err = backups[0].StartBackupDeleteTask(ctx, task.GetUserCred(), task.GetTaskId())
forceDelete := jsonutils.QueryBoolean(task.GetParams(), "force_delete", false)
err = backups[0].StartBackupDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), forceDelete)
if err != nil {
return err
}
+13 -1
View File
@@ -16,8 +16,10 @@ package tasks
import (
"context"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -64,5 +66,15 @@ func (self *DiskBackupDeleteTask) OnDelete(ctx context.Context, backup *models.S
}
func (self *DiskBackupDeleteTask) OnDeleteFailed(ctx context.Context, backup *models.SDiskBackup, data jsonutils.JSONObject) {
self.taskFailed(ctx, backup, data)
log.Infof("params: %s", self.Params)
log.Infof("OnDeleteFailed data: %s", data)
if forceDelete := jsonutils.QueryBoolean(self.Params, "force_delete", false); !forceDelete {
self.taskFailed(ctx, backup, data)
}
reason, _ := data.GetString("__reason__")
if !strings.Contains(reason, api.BackupStorageOffline) {
self.taskFailed(ctx, backup, data)
}
log.Infof("delete backup %s failed, force delete", backup.GetId())
self.taskSuccess(ctx, backup, nil)
}
@@ -37,7 +37,7 @@ import (
const BackupStoragePath = "/opt/cloud/workspace/backupstorage"
var ErrorBackupStorageOffline error = errors.Error("backup storage offline")
var ErrorBackupStorageOffline error = errors.Error(api.BackupStorageOffline)
type SNFSBackupStorage struct {
BackupStorageId string
+19 -1
View File
@@ -43,6 +43,15 @@ func (opts *DiskBackupIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type DiskBackupDeleteOptions struct {
DiskBackupIdOptions
Force bool `help:"force delete"`
}
func (opts *DiskBackupDeleteOptions) QueryParams() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type DiskBackupCreateOptions struct {
options.BaseCreateOptions
DISKID string `help:"disk id" json:"disk_id"`
@@ -121,7 +130,7 @@ func (opts *InstanceBackupListOptions) Params() (jsonutils.JSONObject, error) {
}
type InstanceBackupIdOptions struct {
ID string `help:"instance backup id"`
ID string `help:"instance backup id" json:"-"`
}
func (opts *InstanceBackupIdOptions) GetId() string {
@@ -132,6 +141,15 @@ func (opts *InstanceBackupIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type InstanceBackupDeleteOptions struct {
InstanceBackupIdOptions
Force bool `help:"force delete"`
}
func (opts *InstanceBackupDeleteOptions) QueryParams() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type InstanceBackupRecoveryOptions struct {
DiskBackupIdOptions
Name string `help:"server name" json:"name"`