fix(region,host): slvm default deactivate on hosts (#20314)

This commit is contained in:
wanyaoqi
2024-05-30 15:03:26 +08:00
committed by GitHub
parent 7729869968
commit ec826cbfa3
30 changed files with 572 additions and 190 deletions

View File

@@ -64,7 +64,10 @@ const (
DISK_EXIST = "exist"
)
const DISK_META_EXISTING_PATH = "disk_existing_path"
const (
DISK_META_EXISTING_PATH = "disk_existing_path"
DISK_META_LAST_ATTACHED_HOST = "__disk_last_attached_host"
)
const (
DISK_DRIVER_VIRTIO = "virtio"

View File

@@ -163,7 +163,7 @@ var (
STORAGE_NFS, STORAGE_GPFS, STORAGE_VSAN, STORAGE_CIFS, STORAGE_CLVM, STORAGE_SLVM}
SHARED_FILE_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS}
FIEL_STORAGE = []string{STORAGE_LOCAL, STORAGE_NFS, STORAGE_GPFS}
FIEL_STORAGE = []string{STORAGE_LOCAL, STORAGE_NFS, STORAGE_GPFS, STORAGE_LVM, STORAGE_CLVM, STORAGE_SLVM}
// 目前来说只支持这些
SHARED_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS, STORAGE_RBD, STORAGE_CLVM, STORAGE_SLVM}

View File

@@ -59,7 +59,11 @@ func (self *SBaseHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb i
return fmt.Errorf("Not Implement ValidateDiskSize")
}
func (self *SBaseHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error {
func (self *SBaseHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask, snapshotIds []string) error {
return fmt.Errorf("Not Implement")
}
func (self *SBaseHostDriver) RequestDeleteSnapshotWithoutGuest(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, params *jsonutils.JSONDict, task taskman.ITask) error {
return fmt.Errorf("Not Implement")
}

View File

@@ -410,10 +410,11 @@ func (self *SKVMHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, ho
return err
}
func (self *SKVMHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error {
func (self *SKVMHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask, snapshotIds []string) error {
url := fmt.Sprintf("/storages/%s/delete-snapshots", snapshot.StorageId)
body := jsonutils.NewDict()
body.Set("disk_id", jsonutils.NewString(snapshot.DiskId))
body.Set("snapshot_ids", jsonutils.NewStringArray(snapshotIds))
header := task.GetTaskRequestHeader()
@@ -421,6 +422,14 @@ func (self *SKVMHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Contex
return err
}
func (self *SKVMHostDriver) RequestDeleteSnapshotWithoutGuest(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, params *jsonutils.JSONDict, task taskman.ITask) error {
url := fmt.Sprintf("/storages/%s/delete-snapshot", snapshot.StorageId)
header := task.GetTaskRequestHeader()
_, err := host.Request(ctx, task.GetUserCred(), "POST", url, header, params)
return err
}
func (self *SKVMHostDriver) ValidateResetDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, snapshot *models.SSnapshot, guests []models.SGuest, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if len(guests) > 1 {
return nil, httperrors.NewBadRequestError("Disk attach muti guests")

View File

@@ -2190,6 +2190,21 @@ func (self *SDisk) RealDelete(ctx context.Context, userCred mcclient.TokenCreden
return self.SVirtualResourceBase.Delete(ctx, userCred)
}
func (self *SDisk) RecordLastAttachedHost(ctx context.Context, userCred mcclient.TokenCredential, hostId string) error {
storage, err := self.GetStorage()
if err != nil {
return err
}
if storage.StorageType != api.STORAGE_SLVM {
return nil
}
return self.SetMetadata(ctx, api.DISK_META_LAST_ATTACHED_HOST, hostId, userCred)
}
func (self *SDisk) GetLastAttachedHost(ctx context.Context, userCred mcclient.TokenCredential) string {
return self.GetMetadata(ctx, api.DISK_META_LAST_ATTACHED_HOST, userCred)
}
// 同步磁盘状态
func (self *SDisk) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DiskSyncstatusInput) (jsonutils.JSONObject, error) {
var openTask = true

View File

@@ -49,7 +49,8 @@ type IHostDriver interface {
// resize disk
RequestResizeDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
RequestDeleteSnapshotsWithStorage(ctx context.Context, host *SHost, snapshot *SSnapshot, task taskman.ITask) error
RequestDeleteSnapshotsWithStorage(ctx context.Context, host *SHost, snapshot *SSnapshot, task taskman.ITask, snapshotIds []string) error
RequestDeleteSnapshotWithoutGuest(ctx context.Context, host *SHost, snapshot *SSnapshot, params *jsonutils.JSONDict, task taskman.ITask) error
RequestResetDisk(ctx context.Context, host *SHost, disk *SDisk, params *jsonutils.JSONDict, task taskman.ITask) error
RequestCleanUpDiskSnapshots(ctx context.Context, host *SHost, disk *SDisk, params *jsonutils.JSONDict, task taskman.ITask) error
PrepareConvert(host *SHost, image, raid string, data jsonutils.JSONObject) (*api.ServerCreateInput, error)

View File

@@ -730,16 +730,20 @@ func (self *SSnapshotManager) PerformDeleteDiskSnapshots(ctx context.Context, us
if snapshots == nil || len(snapshots) == 0 {
return nil, httperrors.NewNotFoundError("Disk %s dose not have snapshot", diskId)
}
snapshotIds := []string{}
for i := 0; i < len(snapshots); i++ {
if snapshots[i].FakeDeleted == false {
return nil, httperrors.NewBadRequestError("Can not delete disk snapshots, have manual snapshot")
}
snapshotIds = append(snapshotIds, snapshots[i].Id)
}
err = snapshots[0].StartSnapshotsDeleteTask(ctx, userCred, "")
err = snapshots[0].StartSnapshotsDeleteTask(ctx, userCred, "", snapshotIds)
return nil, err
}
func (self *SSnapshot) StartSnapshotsDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
func (self *SSnapshot) StartSnapshotsDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, snapshotIds []string) error {
data := jsonutils.NewDict()
data.Set("snapshot_ids", jsonutils.NewStringArray(snapshotIds))
task, err := taskman.TaskManager.NewTask(ctx, "BatchSnapshotsDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
log.Errorln(err)

View File

@@ -96,6 +96,36 @@ func (self *SBaseStorageDriver) RequestDeleteSnapshot(ctx context.Context, snaps
return err
}
}
if guest == nil {
storage := snapshot.GetStorage()
host, err := storage.GetMasterHost()
if err != nil {
return err
}
convertSnapshot, err := models.SnapshotManager.GetConvertSnapshot(snapshot)
if err != nil && err != sql.ErrNoRows {
return errors.Wrap(err, "get convert snapshot")
}
params := jsonutils.NewDict()
params.Set("delete_snapshot", jsonutils.NewString(snapshot.Id))
params.Set("disk_id", jsonutils.NewString(snapshot.DiskId))
disk, err := models.DiskManager.FetchById(snapshot.DiskId)
if err != nil && err != sql.ErrNoRows {
return errors.Wrap(err, "get disk by snapshot")
}
if !snapshot.OutOfChain {
if convertSnapshot != nil {
params.Set("convert_snapshot", jsonutils.NewString(convertSnapshot.Id))
} else if disk != nil {
params.Set("block_stream", jsonutils.JSONTrue)
} else {
params.Set("auto_deleted", jsonutils.JSONTrue)
}
} else {
params.Set("auto_deleted", jsonutils.JSONTrue)
}
return host.GetHostDriver().RequestDeleteSnapshotWithoutGuest(ctx, host, snapshot, params, task)
}
if jsonutils.QueryBoolean(task.GetParams(), "reload_disk", false) && snapshot.OutOfChain {
guest.SetStatus(task.GetUserCred(), api.VM_SNAPSHOT, "Start Reload Snapshot")

View File

@@ -118,10 +118,16 @@ func (self *DiskDeleteTask) startDeleteDisk(ctx context.Context, disk *models.SD
purgeParams := jsonutils.QueryBoolean(self.Params, "purge", false)
host, err := storage.GetMasterHost()
if err != nil && errors.Cause(err) != sql.ErrNoRows && !purgeParams {
self.OnGuestDiskDeleteCompleteFailed(ctx, disk, jsonutils.NewString("storage.GetMasterHost"))
return
var host *models.SHost
if hostId := disk.GetLastAttachedHost(ctx, self.UserCred); hostId != "" {
host = models.HostManager.FetchHostById(hostId)
}
if host == nil {
host, err = storage.GetMasterHost()
if err != nil && errors.Cause(err) != sql.ErrNoRows && !purgeParams {
self.OnGuestDiskDeleteCompleteFailed(ctx, disk, jsonutils.NewString("storage.GetMasterHost"))
return
}
}
isPurge := false

View File

@@ -60,6 +60,12 @@ func (self *GuestDetachDiskTask) OnInit(ctx context.Context, obj db.IStandaloneM
return
}
err = disk.RecordLastAttachedHost(ctx, self.UserCred, host.Id)
if err != nil {
self.OnTaskFail(ctx, guest, nil, jsonutils.NewString(err.Error()))
return
}
if !host.GetEnabled() {
self.OnDetachDiskCompleteFailed(ctx, guest, jsonutils.Marshal(map[string]string{"error": fmt.Sprintf("host %s(%s) is disabled", host.Name, host.Id)}))
return

View File

@@ -172,8 +172,16 @@ func (self *BatchSnapshotsDeleteTask) StartStorageDeleteSnapshot(ctx context.Con
self.SetStageFailed(ctx, jsonutils.NewString(errors.Wrapf(err, "snapshot.GetHost").Error()))
return
}
snapshotIds := []string{}
err = self.Params.Unmarshal(&snapshotIds, "snapshot_ids")
if err != nil {
self.SetStageFailed(ctx, jsonutils.NewString(errors.Wrapf(err, "unmarshal snapshot ids").Error()))
return
}
self.SetStage("OnStorageDeleteSnapshot", nil)
err = host.GetHostDriver().RequestDeleteSnapshotsWithStorage(ctx, host, snapshot, self)
err = host.GetHostDriver().RequestDeleteSnapshotsWithStorage(ctx, host, snapshot, self, snapshotIds)
if err != nil {
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}

View File

@@ -62,8 +62,6 @@ func (self *StorageCacheImageTask) OnRelinquishLeastUsedCachedImageComplete(ctx
db.OpsLog.LogEvent(storageCache, db.ACT_CACHING_IMAGE, imageId, self.UserCred)
self.SetStage("OnImageCacheComplete", nil)
var host *models.SHost
var err error
serverId, _ := self.Params.GetString("server_id")
@@ -75,7 +73,8 @@ func (self *StorageCacheImageTask) OnRelinquishLeastUsedCachedImageComplete(ctx
return
}
server := guest.(*models.SGuest)
server.SetStatus(self.GetUserCred(), api.VM_IMAGE_CACHING, "")
self.Params.Set("guest_oldstatus", jsonutils.NewString(server.Status))
server.SetStatus(self.GetUserCred(), api.VM_IMAGE_CACHING, "start cache image")
host, _ = server.GetHost()
} else {
host, err = storageCache.GetMasterHost()
@@ -86,6 +85,7 @@ func (self *StorageCacheImageTask) OnRelinquishLeastUsedCachedImageComplete(ctx
}
}
self.SetStage("OnImageCacheComplete", nil)
err = host.GetHostDriver().CheckAndSetCacheImage(ctx, host, storageCache, self)
if err != nil {
errData := taskman.Error2TaskData(err)
@@ -133,6 +133,20 @@ func (self *StorageCacheImageTask) OnCacheSucc(ctx context.Context, cache *model
scimg.SetExternalId(extImgId)
}
models.CachedimageManager.ImageAddRefCount(imageId)
serverId, _ := self.Params.GetString("server_id")
if len(serverId) > 0 {
guest, err := models.GuestManager.FetchById(serverId)
if err != nil {
errData := taskman.Error2TaskData(err)
self.OnImageCacheCompleteFailed(ctx, cache, errData)
return
}
server := guest.(*models.SGuest)
serverOldStatus, _ := self.Params.GetString("guest_oldstatus")
server.SetStatus(self.GetUserCred(), serverOldStatus, "on cache image success")
}
db.OpsLog.LogEvent(cache, db.ACT_CACHED_IMAGE, imageId, self.UserCred)
self.SetStageComplete(ctx, data)
}

View File

@@ -115,7 +115,7 @@ func getSnapshotPath(diskId, snapshotId string) string {
}
}
for _, vg := range HostImageOptions.LVMVolumeGroups {
diskPath := path.Join("/dev", vg, "snap_"+diskId+snapshotId)
diskPath := path.Join("/dev", vg, "snap_"+snapshotId)
if _, err := os.Stat(diskPath); !os.IsNotExist(err) {
return diskPath
}

View File

@@ -1142,7 +1142,7 @@ func (m *SGuestManager) DeleteSnapshot(ctx context.Context, params interface{})
} else {
res := jsonutils.NewDict()
res.Set("deleted", jsonutils.JSONTrue)
return res, delParams.Disk.DeleteSnapshot(delParams.DeleteSnapshot, "")
return res, delParams.Disk.DeleteSnapshot(delParams.DeleteSnapshot, "", false)
}
}

View File

@@ -29,6 +29,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
hostapi "yunion.io/x/onecloud/pkg/apis/host"
"yunion.io/x/onecloud/pkg/appctx"
"yunion.io/x/onecloud/pkg/hostman/guestman/qemu"
@@ -1240,6 +1241,7 @@ type SGuestStreamDisksTask struct {
c chan struct{}
streamDevs []string
lvmBacking []string
}
func NewGuestStreamDisksTask(ctx context.Context, guest *SKVMGuestInstance, callback func(), disksIdx []int) *SGuestStreamDisksTask {
@@ -1274,6 +1276,7 @@ func (s *SGuestStreamDisksTask) checkBlockDrives() {
func (s *SGuestStreamDisksTask) onBlockDrivesSucc(blocks []monitor.QemuBlock) {
s.streamDevs = []string{}
s.lvmBacking = []string{}
for _, block := range blocks {
if len(block.Inserted.File) > 0 && len(block.Inserted.BackingFile) > 0 {
var stream = false
@@ -1286,10 +1289,17 @@ func (s *SGuestStreamDisksTask) onBlockDrivesSucc(blocks []monitor.QemuBlock) {
if !stream {
continue
}
s.streamDevs = append(s.streamDevs, block.Device)
disk, err := storageman.GetManager().GetDiskByPath(block.Inserted.File)
if err == nil && disk.GetType() == api.STORAGE_SLVM {
s.lvmBacking = append(s.lvmBacking, block.Inserted.BackingFile)
} else {
log.Errorf("failed get disk by path %s: %s", block.Inserted.File, err)
}
}
}
log.Infof("Stream devices %s: %v", s.GetName(), s.streamDevs)
log.Infof("Stream devices %s: %v , backingfiles %v", s.GetName(), s.streamDevs, s.lvmBacking)
if len(s.streamDevs) == 0 {
s.taskComplete()
} else {
@@ -1334,7 +1344,14 @@ func (s *SGuestStreamDisksTask) checkStreamJobs(jobs int) {
}
}
func (s *SGuestStreamDisksTask) deactivateLvmBackingFile() {
for _, lvPath := range s.lvmBacking {
storageman.TryDeactivateBackingLvs(lvPath)
}
}
func (s *SGuestStreamDisksTask) taskComplete() {
s.deactivateLvmBackingFile()
hostutils.UpdateServerProgress(context.Background(), s.Id, 100.0, 0.0)
s.SyncStatus("Guest Disks Block Stream Complete")

View File

@@ -2211,7 +2211,7 @@ func (s *SKVMGuestInstance) ExecDeleteSnapshotTask(
func (s *SKVMGuestInstance) deleteStaticSnapshotFile(
ctx context.Context, disk storageman.IDisk, deleteSnapshot, convertSnapshot string, blockStream bool,
) (jsonutils.JSONObject, error) {
if err := disk.DeleteSnapshot(deleteSnapshot, convertSnapshot); err != nil {
if err := disk.DeleteSnapshot(deleteSnapshot, convertSnapshot, blockStream); err != nil {
log.Errorln(err)
return nil, err
}

View File

@@ -60,14 +60,14 @@ type IDisk interface {
RebuildSlaveDisk(diskUri string) error
CreateFromUrl(ctx context.Context, url string, size int64, callback func(progress, progressMbps float64, totalSizeMb int64)) error
CreateFromTemplate(context.Context, string, string, int64, *apis.SEncryptInfo) (jsonutils.JSONObject, error)
CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) error
CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error)
CreateFromRbdSnapshot(ctx context.Context, snapshotId, srcDiskId, srcPool string) error
CreateFromImageFuse(ctx context.Context, url string, size int64, encryptInfo *apis.SEncryptInfo) error
CreateRaw(ctx context.Context, sizeMb int, diskFromat string, fsFormat string,
encryptInfo *apis.SEncryptInfo, diskId string, back string) (jsonutils.JSONObject, error)
PostCreateFromImageFuse()
CreateSnapshot(snapshotId string, encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg) error
DeleteSnapshot(snapshotId, convertSnapshot string) error
DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error
DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *jsonutils.JSONDict,
deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error)
ConvertSnapshot(convertSnapshotId string) error
@@ -118,8 +118,8 @@ func (d *SBaseDisk) CreateFromTemplate(context.Context, string, string, int64, *
return nil, errors.Errorf("Not implemented")
}
func (d *SBaseDisk) CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) error {
return errors.Errorf("Not implemented")
func (d *SBaseDisk) CreateFromSnapshotLocation(ctx context.Context, location string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error) {
return nil, errors.Errorf("Not implemented")
}
func (d *SBaseDisk) CreateFromImageFuse(ctx context.Context, url string, size int64, encryptInfo *apis.SEncryptInfo) error {

View File

@@ -515,46 +515,9 @@ func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string) error {
return nil
}
func (d *SLocalDisk) DeleteSnapshot(snapshotId, convertSnapshot string) error {
func (d *SLocalDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
snapshotDir := d.GetSnapshotDir()
snapshotPath := path.Join(snapshotDir, snapshotId)
if len(convertSnapshot) > 0 {
if !fileutils2.Exists(snapshotDir) {
err := procutils.NewCommand("mkdir", "-p", snapshotDir).Run()
if err != nil {
log.Errorln(err)
return err
}
}
convertSnapshotPath := path.Join(snapshotDir, convertSnapshot)
output := convertSnapshotPath + ".tmp"
if fileutils2.Exists(output) {
procutils.NewCommand("rm", "-f", output).Run()
}
img, err := qemuimg.NewQemuImage(convertSnapshotPath)
if err != nil {
return errors.Wrap(err, "NewQemuImage")
}
if err = img.Convert2Qcow2To(output, false, "", "", ""); err != nil {
log.Errorf("convert image %s to %s: %s", img.Path, output, err)
procutils.NewCommand("rm", "-f", output).Run()
return err
}
if err = procutils.NewCommand("rm", "-f", convertSnapshotPath).Run(); err != nil {
log.Errorf("rm convert snapshot file %s: %s", convertSnapshotPath, err)
return err
}
if err = procutils.NewCommand("mv", "-f", output, convertSnapshotPath).Run(); err != nil {
log.Errorf("mv snapshot file %s to %s: %s", output, convertSnapshotPath, err)
return err
}
}
err := procutils.NewCommand("rm", "-f", snapshotPath).Run()
if err != nil {
log.Errorf("rm snapshot file: %s", err)
return errors.Wrap(err, "rm snapshot file")
}
return nil
return DeleteLocalSnapshot(snapshotDir, snapshotId, d.getPath(), convertSnapshot, blockStream)
}
func (d *SLocalDisk) PrepareSaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {

View File

@@ -74,7 +74,7 @@ func (d *SLVMDisk) GetPath() string {
// The LVM logical volume name is limited to 64 characters.
func (d *SLVMDisk) GetSnapshotName(snapshotId string) string {
return "snap_" + d.Id + "_" + snapshotId
return "snap_" + snapshotId
}
func (d *SLVMDisk) GetSnapshotPath(snapshotId string) string {
@@ -408,20 +408,31 @@ func (d *SLVMDisk) CreateSnapshot(snapshotId string, encryptKey string, encForma
return err
}
if err := lvmutils.LvCreate(d.Storage.GetPath(), d.Id, lvSize); err != nil {
if e := lvmutils.LvRename(d.Storage.GetPath(), snapName, d.Id); e != nil {
log.Errorf("failed rename lv %s to %s: %s", snapName, d.GetPath(), e)
}
return errors.Wrap(err, "snapshot LvCreate")
}
img, err := qemuimg.NewQemuImage(d.GetPath())
if err != nil {
lvmutils.LvRemove(d.GetPath())
lvmutils.LvRename(d.Storage.GetPath(), snapName, d.Id)
if e := lvmutils.LvRemove(d.GetPath()); e != nil {
log.Errorf("failed remove lv %s: %s", d.GetPath(), e)
}
if e := lvmutils.LvRename(d.Storage.GetPath(), snapName, d.Id); e != nil {
log.Errorf("failed rename lv %s to %s: %s", snapName, d.GetPath(), e)
}
return errors.Wrapf(err, "failed qemuimg.NewQemuImage(%s))", d.GetPath())
}
snapPath := d.GetSnapshotPath(snapshotId)
err = img.CreateQcow2(0, false, snapPath, "", "", "")
if err != nil {
lvmutils.LvRemove(d.GetPath())
lvmutils.LvRename(d.Storage.GetPath(), snapName, d.Id)
if e := lvmutils.LvRemove(d.GetPath()); e != nil {
log.Errorf("failed remove lv %s: %s", d.GetPath(), e)
}
if e := lvmutils.LvRename(d.Storage.GetPath(), snapName, d.Id); e != nil {
log.Errorf("failed rename lv %s to %s: %s", snapName, d.GetPath(), e)
}
return errors.Wrapf(err, "CreateQcow2(%s)", snapPath)
}
return nil
@@ -475,8 +486,12 @@ func (d *SLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (j
return nil, nil
}
func (d *SLVMDisk) DeleteSnapshot(snapshotId, convertSnapshot string) error {
if len(convertSnapshot) > 0 {
func (d *SLVMDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
if blockStream {
if err := ConvertLVMDisk(d.Storage.GetPath(), d.Id); err != nil {
return err
}
} else if len(convertSnapshot) > 0 {
if err := d.ConvertSnapshot(convertSnapshot); err != nil {
return err
}
@@ -503,59 +518,8 @@ func (d *SLVMDisk) DeleteAllSnapshot(skipRecycle bool) error {
}
func (d *SLVMDisk) ConvertSnapshot(convertSnapshot string) error {
convertSnapshotPath := d.GetSnapshotPath(convertSnapshot)
qemuImg, err := qemuimg.NewQemuImage(convertSnapshotPath)
if err != nil {
log.Errorln(err)
return err
}
lvSize, err := lvmutils.GetLvSize(convertSnapshotPath)
if err != nil {
return err
}
tmpVolume := d.Id + "-convert.tmp"
tmpVolumePath := path.Join("/dev", d.Storage.GetPath(), tmpVolume)
// create /dev/vg/snapshot-convert.tmp
if err := lvmutils.LvCreate(d.Storage.GetPath(), d.Id, lvSize); err != nil {
return errors.Wrap(err, "delete snapshot LvCreate")
}
srcInfo := qemuimg.SImageInfo{
Path: convertSnapshotPath,
Format: qemuImg.Format,
IoLevel: qemuimg.IONiceNone,
Password: "",
}
destInfo := qemuimg.SImageInfo{
Path: tmpVolumePath,
Format: qemuimg.QCOW2,
IoLevel: qemuimg.IONiceNone,
Password: "",
}
// convert /dev/vg/snapshot to /dev/vg/snapshot-convert.tmp
if err = qemuimg.Convert(srcInfo, destInfo, false, nil); err != nil {
lvmutils.LvRemove(tmpVolumePath)
return errors.Wrap(err, "failed convert tmp disk")
}
tmpVolume2 := d.Id + "-convert.tmp2"
tmpVolume2Path := path.Join("/dev", d.Storage.GetPath(), tmpVolume2)
// rename /dev/vg/snapshot to /dev/vg/snapshot-convert.tmp2
err = lvmutils.LvRename(d.Storage.GetPath(), convertSnapshot, tmpVolume2)
if err != nil {
return errors.Wrap(err, "failed rename disk to tmp")
}
// rename /dev/vg/snapshot-convert.tmp to /dev/vg/snapshot
err = lvmutils.LvRename(d.Storage.GetPath(), tmpVolume, convertSnapshot)
if err != nil {
return errors.Wrap(err, "failed rename tmp to disk")
}
// delete /dev/vg/snapshot-convert.tmp2
err = lvmutils.LvRemove(tmpVolume2Path)
if err != nil {
return errors.Wrap(err, "failed remove tmp disk")
}
return nil
convertSnapshotName := d.GetSnapshotName(convertSnapshot)
return ConvertLVMDisk(d.Storage.GetPath(), convertSnapshotName)
}
func (d *SLVMDisk) DoDeleteSnapshot(snapshotId string) error {

View File

@@ -48,16 +48,16 @@ func (d *SNasDisk) CreateFromImageFuse(ctx context.Context, url string, size int
return fmt.Errorf("Not implemented")
}
func (d *SNasDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocation string, size int64, encryptInfo *apis.SEncryptInfo) error {
func (d *SNasDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocation string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error) {
snapshotPath := path.Join(d.Storage.GetPath(), snapshotLocation)
newImg, err := qemuimg.NewQemuImage(d.GetPath())
if err != nil {
return errors.Wrap(err, "new image from snapshot")
return nil, errors.Wrap(err, "new image from snapshot")
}
if newImg.IsValid() {
if err := newImg.Delete(); err != nil {
log.Errorln(err)
return err
return nil, err
}
}
if encryptInfo != nil {
@@ -66,7 +66,7 @@ func (d *SNasDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocat
err = newImg.CreateQcow2(0, false, snapshotPath, "", "", "")
}
if err != nil {
return errors.Wrap(err, "create image from snapshot")
return nil, errors.Wrap(err, "create image from snapshot")
}
retSize, _ := d.GetDiskDesc().Int("disk_size")
log.Infof("REQSIZE: %d, RETSIZE: %d", size, retSize)
@@ -77,9 +77,9 @@ func (d *SNasDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocat
params.Set("encrypt_info", jsonutils.Marshal(encryptInfo))
}
_, err = d.Resize(ctx, params)
return err
return nil, err
}
return nil
return d.GetDiskDesc(), nil
}
func (d *SNasDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {

View File

@@ -263,7 +263,7 @@ func (d *SRBDDisk) ConvertSnapshot(convertSnapshotId string) error {
return nil
}
func (d *SRBDDisk) DeleteSnapshot(snapshotId, convertSnapshot string) error {
func (d *SRBDDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
storage := d.Storage.(*SRbdStorage)
pool, _ := storage.StorageConf.GetString("pool")
return storage.deleteSnapshot(pool, d.Id, snapshotId)
@@ -282,7 +282,7 @@ func (d *SRBDDisk) DiskDeleteSnapshot(ctx context.Context, params interface{}) (
if !ok {
return nil, hostutils.ParamsError
}
err := d.DeleteSnapshot(snapshotId, "")
err := d.DeleteSnapshot(snapshotId, "", false)
if err != nil {
return nil, err
} else {

View File

@@ -56,29 +56,27 @@ func (d *SSLVMDisk) Probe() error {
}
var lvPath = d.GetPath()
activated, err := lvmutils.LvIsActivated(lvPath)
if err != nil {
return errors.Wrap(err, "check lv is activated")
}
if !activated {
if err := lvmutils.LVActive(lvPath, d.Storage.Lvmlockd(), false); err != nil {
return errors.Wrap(err, "lv active")
}
if err := lvmutils.LVActive(lvPath, d.Storage.Lvmlockd(), false); err != nil {
return errors.Wrap(err, "lv active")
}
qemuImg, err := qemuimg.NewQemuImage(d.GetPath())
if err != nil {
log.Errorln(err)
return err
}
if qemuImg.BackFilePath != "" {
originActivated, err := lvmutils.LvIsActivated(qemuImg.BackFilePath)
diskPath := d.GetPath()
for diskPath != "" {
qemuImg, err := qemuimg.NewQemuImage(diskPath)
if err != nil {
return errors.Wrap(err, "check lv is activated")
log.Errorln(err)
return err
}
if !originActivated {
if err = lvmutils.LVActive(qemuImg.BackFilePath, d.Storage.Lvmlockd(), false); err != nil {
return errors.Wrap(err, "lv active origin")
diskPath = qemuImg.BackFilePath
if qemuImg.BackFilePath != "" {
originActivated, err := lvmutils.LvIsActivated(qemuImg.BackFilePath)
if err != nil {
return errors.Wrap(err, "check lv is activated")
}
if !originActivated {
if err = lvmutils.LVActive(qemuImg.BackFilePath, d.Storage.Lvmlockd(), false); err != nil {
return errors.Wrap(err, "lv active origin")
}
}
}
}
@@ -93,13 +91,23 @@ func (d *SSLVMDisk) CreateRaw(
ctx context.Context, sizeMb int, diskFormat string, fsFormat string,
encryptInfo *apis.SEncryptInfo, diskId string, back string,
) (jsonutils.JSONObject, error) {
if fileutils2.Exists(d.GetPath()) {
err := lvmutils.LVDeactivate(d.GetPath())
if err != nil {
return nil, errors.Wrap(err, "LVDeactivate")
}
if err := lvmutils.LvRemove(d.GetLvPath()); err != nil {
return nil, errors.Wrap(err, "CreateRaw lvremove")
}
}
ret, err := d.SLVMDisk.CreateRaw(ctx, sizeMb, diskFormat, fsFormat, encryptInfo, diskId, back)
if err != nil {
return ret, err
}
err = lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
err = lvmutils.LVDeactivate(d.GetPath())
if err != nil {
return ret, errors.Wrap(err, "lvactive shared")
return ret, errors.Wrap(err, "LVDeactivate")
}
return ret, nil
}
@@ -107,13 +115,23 @@ func (d *SSLVMDisk) CreateRaw(
func (d *SSLVMDisk) CreateFromTemplate(
ctx context.Context, imageId, format string, sizeMb int64, encryptInfo *apis.SEncryptInfo,
) (jsonutils.JSONObject, error) {
if fileutils2.Exists(d.GetPath()) {
err := lvmutils.LVDeactivate(d.GetPath())
if err != nil {
return nil, errors.Wrap(err, "LVDeactivate")
}
if err := lvmutils.LvRemove(d.GetLvPath()); err != nil {
return nil, errors.Wrap(err, "CreateRaw lvremove")
}
}
ret, err := d.SLVMDisk.CreateFromTemplate(ctx, imageId, format, sizeMb, encryptInfo)
if err != nil {
return ret, err
}
err = lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
err = lvmutils.LVDeactivate(d.GetPath())
if err != nil {
return ret, errors.Wrap(err, "lvactive shared")
return ret, errors.Wrap(err, "LVDeactivate")
}
return ret, nil
}
@@ -122,7 +140,7 @@ func (d *SSLVMDisk) PreResize(ctx context.Context, sizeMb int64) error {
if ok, err := lvmutils.LvIsActivated(d.GetPath()); err != nil {
return err
} else if ok && d.Storage.Lvmlockd() {
err = lvmutils.LVActive(d.GetPath(), false, true)
err = lvmutils.LVActive(d.GetPath(), false, d.Storage.Lvmlockd())
if err != nil {
return errors.Wrap(err, "lvactive shared")
}
@@ -142,7 +160,7 @@ func (d *SSLVMDisk) Resize(ctx context.Context, params interface{}) (jsonutils.J
if ok, err := lvmutils.LvIsActivated(d.GetPath()); err != nil {
return nil, err
} else if ok && d.Storage.Lvmlockd() {
err = lvmutils.LVActive(d.GetPath(), false, true)
err = lvmutils.LVActive(d.GetPath(), false, d.Storage.Lvmlockd())
if err != nil {
return nil, errors.Wrap(err, "lvactive shared")
}
@@ -158,6 +176,23 @@ func (d *SSLVMDisk) Resize(ctx context.Context, params interface{}) (jsonutils.J
return ret, nil
}
func TryDeactivateBackingLvs(backingFile string) {
if backingFile == "" {
return
}
qemuImg, err := qemuimg.NewQemuImage(backingFile)
if err != nil {
log.Errorf("tryDeactivateBackingLvs NewQemuImage %s", err)
return
}
err = lvmutils.LVDeactivate(backingFile)
if err != nil {
log.Errorf("tryDeactivateBackingLvs LVDeactivate %s", err)
return
}
TryDeactivateBackingLvs(qemuImg.BackFilePath)
}
func (d *SSLVMDisk) Delete(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
var lvPath = d.GetPath()
activated, err := lvmutils.LvIsActivated(lvPath)
@@ -169,38 +204,56 @@ func (d *SSLVMDisk) Delete(ctx context.Context, params interface{}) (jsonutils.J
return nil, errors.Wrap(err, "lv active")
}
}
qemuImg, err := qemuimg.NewQemuImage(lvPath)
if err != nil {
return nil, errors.Wrap(err, "NewQemuImage")
}
TryDeactivateBackingLvs(qemuImg.BackFilePath)
return d.SLVMDisk.Delete(ctx, params)
}
func (d *SSLVMDisk) CreateSnapshot(snapshotId string, encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg) error {
err := lvmutils.LVActive(d.GetPath(), false, true)
err := lvmutils.LVActive(d.GetPath(), false, d.Storage.Lvmlockd())
if err != nil {
return errors.Wrap(err, "lvactive exclusive")
}
err = d.SLVMDisk.CreateSnapshot(snapshotId, encryptKey, encFormat, encAlg)
if err != nil {
err := lvmutils.LVActive(d.GetPath(), true, false)
if err != nil {
log.Errorf("failed lvactive share %s", err)
e3 := lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
if e3 != nil {
log.Errorf("failed lvactive share %s", e3)
}
return err
}
// active disk share mode
err = lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
if err != nil {
return errors.Wrap(err, "lvactive snapshot share")
}
// active snapshot active mode
snapPath := d.GetSnapshotPath(snapshotId)
err = lvmutils.LVActive(snapPath, false, true)
err = lvmutils.LVActive(snapPath, d.Storage.Lvmlockd(), false)
if err != nil {
return errors.Wrap(err, "lvactive snapshot share")
}
return nil
}
func (d *SSLVMDisk) PostCreateFromImageFuse() {
log.Infof("slvm post create from fuse do nothing")
}
func (d *SSLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
err := lvmutils.LVActive(d.GetPath(), false, true)
err := lvmutils.LVActive(d.GetPath(), false, d.Storage.Lvmlockd())
if err != nil {
return nil, errors.Wrap(err, "lvactive exclusive")
}
ret, err := d.SLVMDisk.ResetFromSnapshot(ctx, params)
if err != nil {
err := lvmutils.LVActive(d.GetPath(), true, false)
err := lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
if err != nil {
log.Errorf("failed lvactive share %s", err)
}
@@ -208,3 +261,22 @@ func (d *SSLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (
}
return ret, nil
}
func (d *SSLVMDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocation string, size int64, encryptInfo *apis.SEncryptInfo) (jsonutils.JSONObject, error) {
ret, err := d.SLVMDisk.CreateRaw(ctx, int(size), "", "", encryptInfo, d.Id, snapshotLocation)
if err != nil {
return nil, err
}
qemuImg, err := qemuimg.NewQemuImage(d.GetPath())
if err != nil {
return nil, errors.Wrap(err, "NewQemuImage")
}
TryDeactivateBackingLvs(qemuImg.BackFilePath)
err = lvmutils.LVDeactivate(d.GetPath())
if err != nil {
return nil, errors.Wrap(err, "LVDeactivate")
}
return ret, nil
}

View File

@@ -98,6 +98,7 @@ type IStorage interface {
GetSnapshotDir() string
GetSnapshotPathByIds(diskId, snapshotId string) string
DeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
DeleteSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
IsSnapshotExist(diskId, snapshotId string) (bool, error)
@@ -118,7 +119,7 @@ type IStorage interface {
// *SDiskCreateByDiskinfo
CreateDiskByDiskinfo(context.Context, interface{}) (jsonutils.JSONObject, error)
SaveToGlance(context.Context, interface{}) (jsonutils.JSONObject, error)
CreateDiskFromSnapshot(context.Context, IDisk, *SDiskCreateByDiskinfo) error
CreateDiskFromSnapshot(context.Context, IDisk, *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error)
CreateDiskFromExistingPath(context.Context, IDisk, *SDiskCreateByDiskinfo) error
CreateDiskFromBackup(context.Context, IDisk, *SDiskCreateByDiskinfo) error
@@ -398,12 +399,7 @@ func (s *SBaseStorage) CreateDiskFromSnpashot(ctx context.Context, disk IDisk, i
return nil, httperrors.NewMissingParameterError("snapshot_url")
}
err := storage.CreateDiskFromSnapshot(ctx, disk, input)
if err != nil {
return nil, errors.Wrapf(err, "CreateDiskFromSnapshot")
}
return disk.GetDiskDesc(), nil
return storage.CreateDiskFromSnapshot(ctx, disk, input)
}
func (s *SBaseStorage) createDiskFromExistingPath(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {

View File

@@ -543,11 +543,11 @@ func (s *SLocalStorage) CreateSnapshotFormUrl(
}
func (s *SLocalStorage) DeleteSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
diskId, ok := params.(string)
input, ok := params.(SStorageDeleteSnapshots)
if !ok {
return nil, hostutils.ParamsError
}
snapshotDir := path.Join(s.GetSnapshotDir(), diskId+options.HostOptions.SnapshotDirSuffix)
snapshotDir := path.Join(s.GetSnapshotDir(), input.DiskId+options.HostOptions.SnapshotDirSuffix)
output, err := procutils.NewCommand("rm", "-rf", snapshotDir).Output()
if err != nil {
return nil, fmt.Errorf("Delete snapshot dir failed: %s", output)
@@ -555,6 +555,82 @@ func (s *SLocalStorage) DeleteSnapshots(ctx context.Context, params interface{})
return nil, nil
}
func (s *SLocalStorage) DeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
input, ok := params.(SStorageDeleteSnapshot)
if !ok {
return nil, hostutils.ParamsError
}
snapshotDir := path.Join(s.GetSnapshotDir(), input.DiskId+options.HostOptions.SnapshotDirSuffix)
diskPath := path.Join(s.GetPath(), input.DiskId)
return nil, DeleteLocalSnapshot(snapshotDir, input.SnapshotId, diskPath, input.ConvertSnapshot, input.BlockStream)
}
func DeleteLocalSnapshot(snapshotDir, snapshotId, diskPath, convertSnapshot string, blockStream bool) error {
//snapshotDir := d.GetSnapshotDir()
snapshotPath := path.Join(snapshotDir, snapshotId)
if blockStream {
//diskPath := d.getPath()
output := diskPath + ".tmp"
if fileutils2.Exists(output) {
procutils.NewCommand("rm", "-f", output).Run()
}
img, err := qemuimg.NewQemuImage(diskPath)
if err != nil {
return errors.Wrap(err, "NewQemuImage")
}
if err = img.Convert2Qcow2To(output, false, "", "", ""); err != nil {
log.Errorf("convert image %s to %s: %s", img.Path, output, err)
procutils.NewCommand("rm", "-f", output).Run()
return err
}
if err = procutils.NewCommand("rm", "-f", diskPath).Run(); err != nil {
log.Errorf("rm convert disk file %s: %s", diskPath, err)
return err
}
if err = procutils.NewCommand("mv", "-f", output, diskPath).Run(); err != nil {
log.Errorf("mv disk file %s to %s: %s", output, diskPath, err)
return err
}
} else if len(convertSnapshot) > 0 {
if !fileutils2.Exists(snapshotDir) {
err := procutils.NewCommand("mkdir", "-p", snapshotDir).Run()
if err != nil {
log.Errorln(err)
return err
}
}
convertSnapshotPath := path.Join(snapshotDir, convertSnapshot)
output := convertSnapshotPath + ".tmp"
if fileutils2.Exists(output) {
procutils.NewCommand("rm", "-f", output).Run()
}
img, err := qemuimg.NewQemuImage(convertSnapshotPath)
if err != nil {
return errors.Wrap(err, "NewQemuImage")
}
if err = img.Convert2Qcow2To(output, false, "", "", ""); err != nil {
log.Errorf("convert image %s to %s: %s", img.Path, output, err)
procutils.NewCommand("rm", "-f", output).Run()
return err
}
if err = procutils.NewCommand("rm", "-f", convertSnapshotPath).Run(); err != nil {
log.Errorf("rm convert snapshot file %s: %s", convertSnapshotPath, err)
return err
}
if err = procutils.NewCommand("mv", "-f", output, convertSnapshotPath).Run(); err != nil {
log.Errorf("mv snapshot file %s to %s: %s", output, convertSnapshotPath, err)
return err
}
}
err := procutils.NewCommand("rm", "-f", snapshotPath).Run()
if err != nil {
log.Errorf("rm snapshot file: %s", err)
return errors.Wrap(err, "rm snapshot file")
}
return nil
}
func (s *SLocalStorage) DestinationPrepareMigrate(
ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string,
disksBackingFile, diskSnapsChain, outChainSnaps jsonutils.JSONObject,
@@ -696,9 +772,7 @@ func doRebaseDisk(diskPath, newBasePath string, encInfo *apis.SEncryptInfo) erro
return nil
}
func (s *SLocalStorage) CreateDiskFromSnapshot(
ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo,
) error {
func (s *SLocalStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
info := input.DiskInfo
if info.Protocol == "fuse" {
var encryptInfo *apis.SEncryptInfo
@@ -707,11 +781,11 @@ func (s *SLocalStorage) CreateDiskFromSnapshot(
}
err := disk.CreateFromImageFuse(ctx, info.SnapshotUrl, int64(info.DiskSizeMb), encryptInfo)
if err != nil {
return errors.Wrapf(err, "CreateFromImageFuse")
return nil, errors.Wrapf(err, "CreateFromImageFuse")
}
return nil
return disk.GetDiskDesc(), nil
}
return httperrors.NewUnsupportOperationError("Unsupport protocol %s for Local storage", info.Protocol)
return nil, httperrors.NewUnsupportOperationError("Unsupport protocol %s for Local storage", info.Protocol)
}
func (s *SLocalStorage) CreateDiskFromExistingPath(

View File

@@ -186,7 +186,33 @@ func (s *SLVMStorage) GetSnapshotPathByIds(diskId, snapshotId string) string {
}
func (s *SLVMStorage) DeleteSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
return nil, errors.Errorf("unsupported operation")
input := params.(SStorageDeleteSnapshots)
for i := range input.SnapshotIds {
lvPath := path.Join("/dev", s.GetPath(), "snap_"+input.SnapshotIds[i])
if err := lvmutils.LvRemove(lvPath); err != nil {
return nil, err
}
}
return nil, nil
}
func (s *SLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
input, ok := params.(SStorageDeleteSnapshot)
if !ok {
return nil, hostutils.ParamsError
}
if input.BlockStream {
if err := ConvertLVMDisk(s.GetPath(), input.DiskId); err != nil {
return nil, err
}
} else if len(input.ConvertSnapshot) > 0 {
convertSnapshotName := "snap_" + input.ConvertSnapshot
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName); err != nil {
return nil, err
}
}
snapId := path.Join("/dev", s.GetPath(), input.SnapshotId)
return nil, lvmutils.LvRemove(snapId)
}
func (s *SLVMStorage) IsSnapshotExist(diskId, snapshotId string) (bool, error) {
@@ -426,7 +452,7 @@ func (s *SLVMStorage) DestinationPrepareMigrate(
return nil
}
func (s *SLVMStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) error {
func (s *SLVMStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
info := input.DiskInfo
if info.Protocol == "fuse" {
var encryptInfo *apis.SEncryptInfo
@@ -435,11 +461,11 @@ func (s *SLVMStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, in
}
err := disk.CreateFromImageFuse(ctx, info.SnapshotUrl, int64(info.DiskSizeMb), encryptInfo)
if err != nil {
return errors.Wrapf(err, "CreateFromImageFuse")
return nil, errors.Wrapf(err, "CreateFromImageFuse")
}
return nil
return disk.GetDiskDesc(), nil
}
return httperrors.NewUnsupportOperationError("Unsupport protocol %s for lvm storage", info.Protocol)
return nil, httperrors.NewUnsupportOperationError("Unsupport protocol %s for lvm storage", info.Protocol)
}
func (s *SLVMStorage) CreateDiskFromExistingPath(context.Context, IDisk, *SDiskCreateByDiskinfo) error {
@@ -526,3 +552,58 @@ func (s *SLVMStorage) CloneDiskFromStorage(
TargetFormat: qemuimg.QCOW2.String(),
}, nil
}
func ConvertLVMDisk(vgName, lvName string) error {
diskPath := path.Join("/dev", vgName, lvName)
qemuImg, err := qemuimg.NewQemuImage(diskPath)
if err != nil {
log.Errorln(err)
return err
}
lvSize, err := lvmutils.GetLvSize(diskPath)
if err != nil {
return err
}
tmpVolume := lvName + "-convert.tmp"
tmpVolumePath := path.Join("/dev", vgName, tmpVolume)
// create /dev/vg/disk-convert.tmp
if err := lvmutils.LvCreate(vgName, tmpVolume, lvSize); err != nil {
return errors.Wrap(err, "delete snapshot LvCreate")
}
srcInfo := qemuimg.SImageInfo{
Path: diskPath,
Format: qemuImg.Format,
IoLevel: qemuimg.IONiceNone,
Password: "",
}
destInfo := qemuimg.SImageInfo{
Path: tmpVolumePath,
Format: qemuimg.QCOW2,
IoLevel: qemuimg.IONiceNone,
Password: "",
}
// convert /dev/vg/disk to /dev/vg/disk-convert.tmp
if err = qemuimg.Convert(srcInfo, destInfo, false, nil); err != nil {
lvmutils.LvRemove(tmpVolumePath)
return errors.Wrap(err, "failed convert tmp disk")
}
tmpVolume2 := lvName + "-convert.tmp2"
tmpVolume2Path := path.Join("/dev", vgName, tmpVolume2)
// rename /dev/vg/disk to /dev/vg/disk-convert.tmp2
err = lvmutils.LvRename(vgName, diskPath, tmpVolume2)
if err != nil {
return errors.Wrap(err, "failed rename disk to tmp")
}
// rename /dev/vg/disk-convert.tmp to /dev/vg/disk
err = lvmutils.LvRename(vgName, tmpVolume, diskPath)
if err != nil {
return errors.Wrap(err, "failed rename tmp to disk")
}
// delete /dev/vg/disk-convert.tmp2
err = lvmutils.LvRemove(tmpVolume2Path)
if err != nil {
return errors.Wrap(err, "failed remove tmp disk")
}
return nil
}

View File

@@ -94,11 +94,12 @@ func (s *SNasStorage) SyncStorageInfo() (jsonutils.JSONObject, error) {
return res, err
}
func (s *SNasStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) error {
func (s *SNasStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
info := input.DiskInfo
var encryptInfo *apis.SEncryptInfo
if info.Encryption {
encryptInfo = &info.EncryptInfo
}
return disk.CreateFromSnapshotLocation(ctx, input.DiskInfo.SnapshotUrl, int64(input.DiskInfo.DiskSizeMb), encryptInfo)
}

View File

@@ -576,9 +576,17 @@ func (s *SRbdStorage) DeleteSnapshots(ctx context.Context, params interface{}) (
return nil, fmt.Errorf("Not support delete snapshots")
}
func (s *SRbdStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) error {
func (s *SRbdStorage) DeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
return nil, fmt.Errorf("Not support delete snapshot")
}
func (s *SRbdStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
info := input.DiskInfo
return disk.CreateFromRbdSnapshot(ctx, info.SnapshotUrl, info.SrcDiskId, info.SrcPool)
err := disk.CreateFromRbdSnapshot(ctx, info.SnapshotUrl, info.SrcDiskId, info.SrcPool)
if err != nil {
return nil, err
}
return disk.GetDiskDesc(), nil
}
func (s *SRbdStorage) GetBackupDir() string {

View File

@@ -15,11 +15,15 @@
package storageman
import (
"context"
"path"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
)
@@ -88,18 +92,58 @@ func (s *SSLVMStorage) GetDiskById(diskId string) (IDisk, error) {
}
var disk = NewSLVMDisk(s, diskId)
if disk.Probe() == nil {
err := disk.Probe()
if err == nil {
s.Disks = append(s.Disks, disk)
return disk, nil
} else {
log.Errorf("failed probe slvm disk %s: %s", diskId, err)
}
return nil, errors.ErrNotFound
}
func (s *SSLVMStorage) Accessible() error {
if err := lvmutils.VgActive(s.Path, true); err != nil {
log.Warningf("vgactive got %s", err)
func (s *SSLVMStorage) CreateDiskFromSnapshot(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
snapshotLocation := disk.GetSnapshotPath(input.DiskInfo.SnapshotId)
return disk.CreateFromSnapshotLocation(ctx, snapshotLocation, int64(input.DiskInfo.DiskSizeMb), &input.DiskInfo.EncryptInfo)
}
func (s *SSLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
input, ok := params.(SStorageDeleteSnapshot)
if !ok {
return nil, hostutils.ParamsError
}
if input.BlockStream {
diskLvPath := path.Join("/dev", s.GetPath(), input.DiskId)
err := lvmutils.LVActive(diskLvPath, false, s.Lvmlockd())
if err != nil {
return nil, errors.Wrap(err, "lvactive exclusive")
}
err = ConvertLVMDisk(s.GetPath(), input.DiskId)
if err != nil {
return nil, err
}
} else if len(input.ConvertSnapshot) > 0 {
convertSnapshotName := "snap_" + input.ConvertSnapshot
convertSnapshotPath := path.Join("/dev", s.GetPath(), convertSnapshotName)
err := lvmutils.LVActive(convertSnapshotPath, false, s.Lvmlockd())
if err != nil {
return nil, errors.Wrap(err, "lvactive exclusive")
}
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName); err != nil {
return nil, err
}
}
snapId := path.Join("/dev", s.GetPath(), input.SnapshotId)
return nil, lvmutils.LvRemove(snapId)
}
func (s *SSLVMStorage) Accessible() error {
if err := lvmutils.VgDisplay(s.Path); err != nil {
return err
}

View File

@@ -56,6 +56,9 @@ func AddStorageHandler(prefix string, app *appsrv.Application) {
app.AddHandler("POST",
fmt.Sprintf("%s/%s/<storageId>/delete-snapshots", prefix, keyWords),
auth.Authenticate(storageDeleteSnapshots))
app.AddHandler("POST",
fmt.Sprintf("%s/%s/<storageId>/delete-snapshot", prefix, keyWords),
auth.Authenticate(storageDeleteSnapshot))
app.AddHandler("GET",
fmt.Sprintf("%s/%s/is-mount-point", prefix, keyWords),
auth.Authenticate(storageVerifyMountPoint))
@@ -441,6 +444,41 @@ func deleteBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject
return nil, nil
}
func storageDeleteSnapshot(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
var storageId = params["<storageId>"]
storage := storageman.GetManager().GetStorage(storageId)
if storage == nil {
hostutils.Response(ctx, w, httperrors.NewNotFoundError("Stroage Not found"))
return
}
diskId, err := body.GetString("disk_id")
if err != nil {
hostutils.Response(ctx, w, httperrors.NewImageNotFoundError("disk_id"))
return
}
// blockStream indicate snapshot<-disk
blockStream := jsonutils.QueryBoolean(body, "block_stream", false)
autoDeleted := jsonutils.QueryBoolean(body, "auto_deleted", false)
input := &storageman.SStorageDeleteSnapshot{
DiskId: diskId,
BlockStream: blockStream,
}
if !blockStream && !autoDeleted {
convertSnapshot, err := body.GetString("convert_snapshot")
if err != nil {
hostutils.Response(ctx, w, httperrors.NewMissingParameterError("convert_snapshot"))
return
}
input.ConvertSnapshot = convertSnapshot
}
hostutils.DelayTask(ctx, storage.DeleteSnapshot, input)
hostutils.ResponseOk(ctx, w)
}
func storageDeleteSnapshots(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
var storageId = params["<storageId>"]
@@ -454,6 +492,18 @@ func storageDeleteSnapshots(ctx context.Context, w http.ResponseWriter, r *http.
hostutils.Response(ctx, w, httperrors.NewImageNotFoundError("disk_id"))
return
}
hostutils.DelayTask(ctx, storage.DeleteSnapshots, diskId)
snapshotIds := []string{}
err = body.Unmarshal(&snapshotIds, "snapshot_ids")
if err != nil {
hostutils.Response(ctx, w, httperrors.NewMissingParameterError("snapshot_ids"))
return
}
input := &storageman.SStorageDeleteSnapshots{
DiskId: diskId,
SnapshotIds: snapshotIds,
}
hostutils.DelayTask(ctx, storage.DeleteSnapshots, input)
hostutils.ResponseOk(ctx, w)
}

View File

@@ -46,6 +46,18 @@ type SDiskCleanupSnapshots struct {
DeleteSnapshots []jsonutils.JSONObject
}
type SStorageDeleteSnapshots struct {
DiskId string
SnapshotIds []string
}
type SStorageDeleteSnapshot struct {
DiskId string
SnapshotId string
ConvertSnapshot string
BlockStream bool
}
type SDiskBakcup struct {
SnapshotId string `json:"snapshot_id"`
BackupId string `json:"backup_id"`