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:
wanyaoqi
2024-07-05 13:49:56 +08:00
committed by GitHub
parent b6cc2804e1
commit 35fc11cdd5
9 changed files with 144 additions and 40 deletions
+22 -9
View File
@@ -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)
}
+4 -5
View File
@@ -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))
}
+5
View File
@@ -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 ""
}
+10 -1
View File
@@ -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
}
+82 -2
View File
@@ -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 {
+2 -2
View File
@@ -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
}
+18
View File
@@ -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) {
+1
View File
@@ -86,6 +86,7 @@ type SDiskBackup struct {
type SStorageBackup struct {
BackupId string
BackupLocalPath string
BackupStorageId string
BackupStorageAccessInfo *jsonutils.JSONDict
}