mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
fix(region,host): slvm default deactivate on hosts (#20314)
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
Reference in New Issue
Block a user