mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(region,host): lvm snapshot reset and backup (#20718)
- fix lvm disk reset request hosts wrong, should reset on guest hosts - add lvm disk snapshot failed handle - support lvm disk backup - lvm disk snapshot add encrypt support
This commit is contained in:
@@ -102,16 +102,29 @@ func (self *DiskResetTask) OnStartGuest(ctx context.Context, disk *models.SDisk,
|
||||
|
||||
func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
disk := obj.(*models.SDisk)
|
||||
storage, err := disk.GetStorage()
|
||||
if err != nil {
|
||||
self.TaskFailed(ctx, disk, errors.Wrapf(err, "disk.GetStorage"))
|
||||
return
|
||||
}
|
||||
host, err := storage.GetMasterHost()
|
||||
if err != nil {
|
||||
self.TaskFailed(ctx, disk, errors.Wrapf(err, "storage.GetMasterHost"))
|
||||
return
|
||||
guest := disk.GetGuest()
|
||||
|
||||
var host *models.SHost
|
||||
if guest == nil {
|
||||
storage, err := disk.GetStorage()
|
||||
if err != nil {
|
||||
self.TaskFailed(ctx, disk, errors.Wrapf(err, "disk.GetStorage"))
|
||||
return
|
||||
}
|
||||
host, err = storage.GetMasterHost()
|
||||
if err != nil {
|
||||
self.TaskFailed(ctx, disk, errors.Wrapf(err, "storage.GetMasterHost"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
host, err = guest.GetHost()
|
||||
if err != nil {
|
||||
self.TaskFailed(ctx, disk, errors.Wrapf(err, "guest.GetHost"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
self.RequestResetDisk(ctx, disk, host)
|
||||
}
|
||||
|
||||
|
||||
@@ -2016,12 +2016,11 @@ func (s *SGuestDiskSnapshotTask) onReloadBlkdevSucc(res string) {
|
||||
}
|
||||
|
||||
func (s *SGuestDiskSnapshotTask) onSnapshotBlkdevFail(reason string) {
|
||||
snapshotDir := s.disk.GetSnapshotDir()
|
||||
snapshotPath := path.Join(snapshotDir, s.snapshotId)
|
||||
output, err := procutils.NewCommand("mv", "-f", snapshotPath, s.disk.GetPath()).Output()
|
||||
if err != nil {
|
||||
log.Errorf("mv %s to %s failed: %s, %s", snapshotPath, s.disk.GetPath(), err, output)
|
||||
// rollback snapshot to disk file
|
||||
if err := s.disk.RollbackDiskOnSnapshotFail(s.snapshotId); err != nil {
|
||||
log.Errorf("failed do rollback %s", err)
|
||||
}
|
||||
|
||||
hostutils.TaskFailed(s.ctx, fmt.Sprintf("Reload blkdev error: %s", reason))
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ type IDisk interface {
|
||||
DoDeleteSnapshot(snapshotId string) error
|
||||
GetSnapshotLocation() string
|
||||
GetSnapshotPath(snapshotId string) string
|
||||
RollbackDiskOnSnapshotFail(snapshotId string) error
|
||||
|
||||
GetStorage() IStorage
|
||||
|
||||
@@ -246,6 +247,10 @@ func (d *SBaseDisk) DoDeleteSnapshot(snapshotId string) error {
|
||||
return fmt.Errorf("Not implement disk.DoDeleteSnapshot")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) RollbackDiskOnSnapshotFail(snapshotId string) error {
|
||||
return errors.Errorf("Not implement disk.DoDeleteSnapshot")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) GetBackupDir() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -418,7 +418,6 @@ func (d *SLocalDisk) DiskBackup(ctx context.Context, params interface{}) (jsonut
|
||||
|
||||
snapshotDir := d.GetSnapshotDir()
|
||||
snapshotPath := path.Join(snapshotDir, diskBackup.SnapshotId)
|
||||
|
||||
size, err := doBackupDisk(ctx, snapshotPath, diskBackup)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doBackupDisk")
|
||||
@@ -676,6 +675,16 @@ func (d *SLocalDisk) DoDeleteSnapshot(snapshotId string) error {
|
||||
return d.Storage.DeleteDiskfile(snapshotPath, false)
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) RollbackDiskOnSnapshotFail(snapshotId string) error {
|
||||
snapshotDir := d.GetSnapshotDir()
|
||||
snapshotPath := path.Join(snapshotDir, snapshotId)
|
||||
output, err := procutils.NewCommand("mv", "-f", snapshotPath, d.GetPath()).Output()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "rollback disk on snapshot fail: %s", output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) IsFile() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -31,12 +31,14 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/storageutils"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
identity_modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/fuseutils"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
@@ -407,8 +409,72 @@ func (d *SLVMDisk) PrepareSaveToGlance(ctx context.Context, params interface{})
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) GetBackupName(backupId string) string {
|
||||
return "backup_" + backupId
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) GetBackupPath(backupId string) string {
|
||||
return path.Join("/dev", d.Storage.GetPath(), d.GetBackupName(backupId))
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) DiskBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return nil, errors.ErrNotImplemented
|
||||
diskBackup := params.(*SDiskBackup)
|
||||
|
||||
encKey := ""
|
||||
if len(diskBackup.EncryptKeyId) > 0 {
|
||||
session := auth.GetSession(ctx, diskBackup.UserCred, consts.GetRegion())
|
||||
secKey, err := identity_modules.Credentials.GetEncryptKey(session, diskBackup.EncryptKeyId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetEncryptKey")
|
||||
}
|
||||
encKey = secKey.Key
|
||||
}
|
||||
|
||||
snapshotPath := d.GetSnapshotPath(diskBackup.SnapshotId)
|
||||
snapshotImg, err := qemuimg.NewQemuImage(snapshotPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "lvm disk backup snapshotPath NewQemuImage")
|
||||
}
|
||||
|
||||
// create backup lv
|
||||
lvSizeMb := lvmutils.GetQcow2LvSize(snapshotImg.SizeBytes / 1024 / 1024)
|
||||
err = lvmutils.LvCreate(d.Storage.GetPath(), d.GetBackupName(diskBackup.BackupId), lvSizeMb*1024*1024)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "lvcreate backup")
|
||||
}
|
||||
|
||||
backupPath := d.GetBackupPath(diskBackup.BackupId)
|
||||
srcInfo := qemuimg.SImageInfo{
|
||||
Path: snapshotPath,
|
||||
Format: snapshotImg.Format,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: encKey,
|
||||
}
|
||||
destInfo := qemuimg.SImageInfo{
|
||||
Path: backupPath,
|
||||
Format: qemuimgfmt.QCOW2,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: encKey,
|
||||
}
|
||||
if err = qemuimg.Convert(srcInfo, destInfo, true, nil); err != nil {
|
||||
if errRm := lvmutils.LvRemove(backupPath); errRm != nil {
|
||||
log.Errorf("failed delete backup lv %s", errRm)
|
||||
}
|
||||
return nil, errors.Wrap(err, "failed convert snapshot to backup")
|
||||
}
|
||||
|
||||
_, err = d.Storage.StorageBackup(ctx, &SStorageBackup{
|
||||
BackupId: diskBackup.BackupId,
|
||||
BackupLocalPath: backupPath,
|
||||
BackupStorageId: diskBackup.BackupStorageId,
|
||||
BackupStorageAccessInfo: diskBackup.BackupStorageAccessInfo,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to SStorageBackup")
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
data.Set("size_mb", jsonutils.NewInt(snapshotImg.SizeBytes/1024/1024))
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) CreateSnapshot(snapshotId string, encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg) error {
|
||||
@@ -441,7 +507,7 @@ func (d *SLVMDisk) CreateSnapshot(snapshotId string, encryptKey string, encForma
|
||||
}
|
||||
|
||||
snapPath := d.GetSnapshotPath(snapshotId)
|
||||
err = img.CreateQcow2(0, false, snapPath, "", "", "")
|
||||
err = img.CreateQcow2(0, false, snapPath, encryptKey, encFormat, encAlg)
|
||||
if err != nil {
|
||||
if e := lvmutils.LvRemove(d.GetPath()); e != nil {
|
||||
log.Errorf("failed remove lv %s: %s", d.GetPath(), e)
|
||||
@@ -543,6 +609,20 @@ func (d *SLVMDisk) DoDeleteSnapshot(snapshotId string) error {
|
||||
return lvmutils.LvRemove(snapshotPath)
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) RollbackDiskOnSnapshotFail(snapshotId string) error {
|
||||
diskPath := d.GetPath()
|
||||
if fileutils2.Exists(diskPath) {
|
||||
if err := lvmutils.LvRemove(diskPath); err != nil {
|
||||
return errors.Wrap(err, "rollback disk on snapshot fail delete disk")
|
||||
}
|
||||
}
|
||||
snapshotName := d.GetSnapshotName(snapshotId)
|
||||
if err := lvmutils.LvRename(d.Storage.GetPath(), snapshotName, d.Id); err != nil {
|
||||
return errors.Wrapf(err, "RollbackDiskOnSnapshotFail rename %s to %s failed: %s", snapshotName, d.Id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) PrepareMigrate(liveMigrate bool) ([]string, string, bool, error) {
|
||||
disk, err := qemuimg.NewQemuImage(d.GetPath())
|
||||
if err != nil {
|
||||
|
||||
@@ -414,27 +414,6 @@ func diskSnapshot(ctx context.Context, userCred mcclient.TokenCredential, storag
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func diskStorageBackup(ctx context.Context, storage storageman.IStorage, diskId string, disk storageman.IDisk, body jsonutils.JSONObject) (interface{}, error) {
|
||||
backupId, err := body.GetString("backup_id")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewMissingParameterError("backup_id")
|
||||
}
|
||||
backupStorageId, err := body.GetString("backup_storage_id")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewMissingParameterError("backup_storage_id")
|
||||
}
|
||||
backupStorageAccessInfo, err := body.Get("backup_storage_access_info")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewMissingParameterError("backup_storage_access_info")
|
||||
}
|
||||
hostutils.DelayTask(ctx, storage.StorageBackup, &storageman.SStorageBackup{
|
||||
BackupId: backupId,
|
||||
BackupStorageId: backupStorageId,
|
||||
BackupStorageAccessInfo: backupStorageAccessInfo.(*jsonutils.JSONDict),
|
||||
})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func diskStorageBackupRecovery(ctx context.Context, storage storageman.IStorage, diskId string, disk storageman.IDisk, body jsonutils.JSONObject) (interface{}, error) {
|
||||
backupId, err := body.GetString("backup_id")
|
||||
if err != nil {
|
||||
|
||||
@@ -106,7 +106,7 @@ type IStorage interface {
|
||||
IsSnapshotExist(diskId, snapshotId string) (bool, error)
|
||||
|
||||
GetBackupDir() string
|
||||
StorageBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
|
||||
StorageBackup(ctx context.Context, params *SStorageBackup) (jsonutils.JSONObject, error)
|
||||
StorageBackupRecovery(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
|
||||
|
||||
GetFreeSizeMb() int
|
||||
@@ -198,7 +198,7 @@ func (s *SBaseStorage) SetStoragecacheId(storagecacheId string) {
|
||||
s.StoragecacheId = storagecacheId
|
||||
}
|
||||
|
||||
func (s *SBaseStorage) StorageBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
|
||||
func (s *SBaseStorage) StorageBackup(ctx context.Context, params *SStorageBackup) (jsonutils.JSONObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/backupstorage"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/remotefile"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -529,6 +530,23 @@ func (s *SLVMStorage) Detach() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SLVMStorage) StorageBackup(ctx context.Context, params *SStorageBackup) (jsonutils.JSONObject, error) {
|
||||
backupStorage, err := backupstorage.GetBackupStorage(params.BackupStorageId, params.BackupStorageAccessInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backupPath := params.BackupLocalPath
|
||||
err = backupStorage.SaveBackupFrom(ctx, backupPath, params.BackupId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// remove local backup
|
||||
if err = lvmutils.LvRemove(backupPath); err != nil {
|
||||
return nil, errors.Wrap(err, "On backuped lvremove")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *SLVMStorage) CloneDiskFromStorage(
|
||||
ctx context.Context, srcStorage IStorage, srcDisk IDisk, targetDiskId string, fullCopy bool,
|
||||
) (*hostapi.ServerCloneDiskFromStorageResponse, error) {
|
||||
|
||||
@@ -86,6 +86,7 @@ type SDiskBackup struct {
|
||||
|
||||
type SStorageBackup struct {
|
||||
BackupId string
|
||||
BackupLocalPath string
|
||||
BackupStorageId string
|
||||
BackupStorageAccessInfo *jsonutils.JSONDict
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user