mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
Automated cherry pick of #21313: Automated cherry pick of #21312: Automated cherry pick of #20996: fix(region,host): lvm snapshot delete and create from backup (#21315)
* fix(region,host): lvm snapshot delete and create from backup * fix(host): slvm delete snapshot and save images * fix(host): add option boot vga pci addr * fix(host): slvm active exclusive mode on convert snapshot
This commit is contained in:
@@ -113,6 +113,15 @@ func (self *SBaseStorageDriver) RequestDeleteSnapshot(ctx context.Context, snaps
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return errors.Wrap(err, "get disk by snapshot")
|
||||
}
|
||||
sDisk, _ := disk.(*models.SDisk)
|
||||
if sDisk.IsEncrypted() {
|
||||
if encryptInfo, err := sDisk.GetEncryptInfo(ctx, task.GetUserCred()); err != nil {
|
||||
return errors.Wrap(err, "faild get encryptInfo")
|
||||
} else {
|
||||
params.Set("encrypt_info", jsonutils.Marshal(encryptInfo))
|
||||
}
|
||||
}
|
||||
|
||||
if !snapshot.OutOfChain {
|
||||
if convertSnapshot != nil {
|
||||
params.Set("convert_snapshot", jsonutils.NewString(convertSnapshot.Id))
|
||||
@@ -152,6 +161,20 @@ func (self *SBaseStorageDriver) RequestDeleteSnapshot(ctx context.Context, snaps
|
||||
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")
|
||||
}
|
||||
sDisk, _ := disk.(*models.SDisk)
|
||||
if sDisk.IsEncrypted() {
|
||||
if encryptInfo, err := sDisk.GetEncryptInfo(ctx, task.GetUserCred()); err != nil {
|
||||
return errors.Wrap(err, "faild get encryptInfo")
|
||||
} else {
|
||||
params.Set("encrypt_info", jsonutils.Marshal(encryptInfo))
|
||||
}
|
||||
}
|
||||
|
||||
if !snapshot.OutOfChain {
|
||||
if convertSnapshot != nil {
|
||||
params.Set("convert_snapshot", jsonutils.NewString(convertSnapshot.Id))
|
||||
|
||||
@@ -16,6 +16,7 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -112,6 +113,21 @@ func (self *SnapshotDeleteTask) OnReloadDiskSnapshot(ctx context.Context, snapsh
|
||||
}
|
||||
if snapshot.FakeDeleted {
|
||||
params := jsonutils.NewDict()
|
||||
disk, err := models.DiskManager.FetchById(snapshot.DiskId)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
self.TaskFailed(ctx, snapshot, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
}
|
||||
sDisk, _ := disk.(*models.SDisk)
|
||||
if sDisk.IsEncrypted() {
|
||||
if encryptInfo, err := sDisk.GetEncryptInfo(ctx, self.GetUserCred()); err != nil {
|
||||
self.TaskFailed(ctx, snapshot, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
} else {
|
||||
params.Set("encrypt_info", jsonutils.Marshal(encryptInfo))
|
||||
}
|
||||
}
|
||||
|
||||
params.Set("delete_snapshot", jsonutils.NewString(snapshot.Id))
|
||||
params.Set("disk_id", jsonutils.NewString(snapshot.DiskId))
|
||||
params.Set("auto_deleted", jsonutils.JSONTrue)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
@@ -721,6 +722,14 @@ func guestDeleteSnapshot(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
Disk: disk,
|
||||
}
|
||||
|
||||
if body.Contains("encrypt_info") {
|
||||
encryptInfo := apis.SEncryptInfo{}
|
||||
if err = body.Unmarshal(&encryptInfo, "encrypt_info"); err != nil {
|
||||
return nil, httperrors.NewInputParameterError("unmarshal encrypt_info failed %s", err)
|
||||
}
|
||||
params.EncryptInfo = encryptInfo
|
||||
}
|
||||
|
||||
// blockStream indicate snapshot<-disk
|
||||
blockStream := jsonutils.QueryBoolean(body, "block_stream", false)
|
||||
autoDeleted := jsonutils.QueryBoolean(body, "auto_deleted", false)
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
@@ -143,6 +144,7 @@ type SDeleteDiskSnapshot struct {
|
||||
Disk storageman.IDisk
|
||||
ConvertSnapshot string
|
||||
BlockStream bool
|
||||
EncryptInfo apis.SEncryptInfo
|
||||
}
|
||||
|
||||
type SLibvirtServer struct {
|
||||
|
||||
@@ -1291,11 +1291,11 @@ func (m *SGuestManager) DeleteSnapshot(ctx context.Context, params interface{})
|
||||
if len(delParams.ConvertSnapshot) > 0 || delParams.BlockStream {
|
||||
guest, _ := m.GetKVMServer(delParams.Sid)
|
||||
return guest.ExecDeleteSnapshotTask(ctx, delParams.Disk, delParams.DeleteSnapshot,
|
||||
delParams.ConvertSnapshot, delParams.BlockStream)
|
||||
delParams.ConvertSnapshot, delParams.BlockStream, delParams.EncryptInfo)
|
||||
} else {
|
||||
res := jsonutils.NewDict()
|
||||
res.Set("deleted", jsonutils.JSONTrue)
|
||||
return res, delParams.Disk.DeleteSnapshot(delParams.DeleteSnapshot, "", false)
|
||||
return res, delParams.Disk.DeleteSnapshot(delParams.DeleteSnapshot, "", false, delParams.EncryptInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"yunion.io/x/pkg/util/version"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
@@ -2041,19 +2042,21 @@ type SGuestSnapshotDeleteTask struct {
|
||||
deleteSnapshot string
|
||||
convertSnapshot string
|
||||
blockStream bool
|
||||
encryptInfo apis.SEncryptInfo
|
||||
|
||||
tmpPath string
|
||||
}
|
||||
|
||||
func NewGuestSnapshotDeleteTask(
|
||||
ctx context.Context, s *SKVMGuestInstance, disk storageman.IDisk,
|
||||
deleteSnapshot, convertSnapshot string, blockStream bool,
|
||||
deleteSnapshot, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo,
|
||||
) *SGuestSnapshotDeleteTask {
|
||||
return &SGuestSnapshotDeleteTask{
|
||||
SGuestReloadDiskTask: NewGuestReloadDiskTask(ctx, s, disk),
|
||||
deleteSnapshot: deleteSnapshot,
|
||||
convertSnapshot: convertSnapshot,
|
||||
blockStream: blockStream,
|
||||
encryptInfo: encryptInfo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2092,7 +2095,7 @@ func (s *SGuestSnapshotDeleteTask) onStreamDiskComplete() {
|
||||
}
|
||||
|
||||
func (s *SGuestSnapshotDeleteTask) doDiskConvert() error {
|
||||
return s.disk.ConvertSnapshot(s.convertSnapshot)
|
||||
return s.disk.ConvertSnapshot(s.convertSnapshot, s.encryptInfo)
|
||||
}
|
||||
|
||||
func (s *SGuestSnapshotDeleteTask) doReloadDisk(device string) {
|
||||
|
||||
@@ -918,7 +918,7 @@ func (s *SKVMGuestInstance) ImportServer(pendingDelete bool) {
|
||||
} else if s.Desc.IsSlave {
|
||||
go s.DirtyServerRequestStart()
|
||||
} else {
|
||||
s.StartGuest(context.Background(), nil, jsonutils.NewDict())
|
||||
s.StartGuest(context.Background(), auth.AdminCredential(), jsonutils.NewDict())
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -3182,25 +3182,25 @@ func (s *SKVMGuestInstance) StaticSaveSnapshot(
|
||||
|
||||
func (s *SKVMGuestInstance) ExecDeleteSnapshotTask(
|
||||
ctx context.Context, disk storageman.IDisk,
|
||||
deleteSnapshot string, convertSnapshot string, blockStream bool,
|
||||
deleteSnapshot string, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
if s.IsRunning() {
|
||||
if s.isLiveSnapshotEnabled() {
|
||||
task := NewGuestSnapshotDeleteTask(ctx, s, disk, deleteSnapshot, convertSnapshot, blockStream)
|
||||
task := NewGuestSnapshotDeleteTask(ctx, s, disk, deleteSnapshot, convertSnapshot, blockStream, encryptInfo)
|
||||
task.Start()
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("Guest dosen't support live snapshot delete")
|
||||
}
|
||||
} else {
|
||||
return s.deleteStaticSnapshotFile(ctx, disk, deleteSnapshot, convertSnapshot, blockStream)
|
||||
return s.deleteStaticSnapshotFile(ctx, disk, deleteSnapshot, convertSnapshot, blockStream, encryptInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) deleteStaticSnapshotFile(
|
||||
ctx context.Context, disk storageman.IDisk, deleteSnapshot, convertSnapshot string, blockStream bool,
|
||||
ctx context.Context, disk storageman.IDisk, deleteSnapshot, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
if err := disk.DeleteSnapshot(deleteSnapshot, convertSnapshot, blockStream); err != nil {
|
||||
if err := disk.DeleteSnapshot(deleteSnapshot, convertSnapshot, blockStream, encryptInfo); err != nil {
|
||||
log.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -2175,31 +2177,11 @@ func (h *SHostInfo) probeSyncIsolatedDevices() (*jsonutils.JSONArray, error) {
|
||||
sriovNics, offloadNics, options.HostOptions.PTNVMEConfigs, options.HostOptions.AMDVgpuPFs, options.HostOptions.NVIDIAVgpuPFs,
|
||||
enableDevWhitelist)
|
||||
|
||||
h.IsolatedDeviceMan.BatchCustomProbe()
|
||||
// sync each isolated device found
|
||||
updateDevs := jsonutils.NewArray()
|
||||
for _, dev := range h.IsolatedDeviceMan.GetDevices() {
|
||||
dev.SetHostId(h.HostId)
|
||||
data := isolated_device.GetApiResourceData(dev)
|
||||
updateDevs.Add(data)
|
||||
objs, err := h.getRemoteIsolatedDevices()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getRemoteIsolatedDevices")
|
||||
}
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("isolated_devices", updateDevs)
|
||||
ret, err := modules.Hosts.PerformAction(h.GetSession(), h.HostId, "sync-isolated-devices", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "sync isolated devices")
|
||||
}
|
||||
devRet, err := ret.Get("isolated_devices")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "sync isolated devices faild get dev rets")
|
||||
}
|
||||
devRets, _ := devRet.(*jsonutils.JSONArray)
|
||||
if devRets.Length() != len(h.IsolatedDeviceMan.GetDevices()) {
|
||||
return nil, errors.Wrap(err, "sync devices not match")
|
||||
}
|
||||
|
||||
objs, _ := devRets.GetArray()
|
||||
for _, obj := range objs {
|
||||
info := isolated_device.CloudDeviceInfo{}
|
||||
if err := obj.Unmarshal(&info); err != nil {
|
||||
@@ -2209,11 +2191,39 @@ func (h *SHostInfo) probeSyncIsolatedDevices() (*jsonutils.JSONArray, error) {
|
||||
if dev != nil {
|
||||
dev.SetDeviceInfo(info)
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "unknown device %s", obj)
|
||||
// detach device
|
||||
h.IsolatedDeviceMan.AppendDetachedDevice(&info)
|
||||
}
|
||||
}
|
||||
|
||||
return devRets, nil
|
||||
h.IsolatedDeviceMan.StartDetachTask()
|
||||
h.IsolatedDeviceMan.BatchCustomProbe()
|
||||
|
||||
// sync each isolated device found
|
||||
eg := errgroup.Group{}
|
||||
mtx := sync.Mutex{}
|
||||
updateDevs := jsonutils.NewArray()
|
||||
|
||||
devs := h.IsolatedDeviceMan.GetDevices()
|
||||
for i := range devs {
|
||||
dev := devs[i]
|
||||
eg.Go(func() error {
|
||||
if obj, err := isolated_device.SyncDeviceInfo(h.GetSession(), h.HostId, dev); err != nil {
|
||||
log.Errorf("Sync deviceInfo %s error: %v", dev.String(), err)
|
||||
return errors.Wrapf(err, "Sync device %s", dev.String())
|
||||
} else {
|
||||
mtx.Lock()
|
||||
updateDevs.Add(obj)
|
||||
mtx.Unlock()
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return updateDevs, nil
|
||||
}
|
||||
|
||||
func (h *SHostInfo) deployAdminAuthorizedKeys() {
|
||||
|
||||
@@ -92,6 +92,18 @@ func getPassthroughGPUs(filteredAddrs []string, enableWhitelist bool, whitelistM
|
||||
if utils.IsInStringArray(dev.Addr, filteredAddrs) {
|
||||
continue
|
||||
}
|
||||
if o.HostOptions.BootVgaPciAddr != "" {
|
||||
if dev.Addr == o.HostOptions.BootVgaPciAddr && !o.HostOptions.UseBootVga {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if ok, err := dev.IsBootVGA(); err != nil {
|
||||
return nil, err, nil
|
||||
} else if ok && !o.HostOptions.UseBootVga {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !utils.IsInArray(dev.ClassCode, GpuClassCodes) {
|
||||
continue
|
||||
}
|
||||
@@ -119,7 +131,7 @@ func getPassthroughGPUs(filteredAddrs []string, enableWhitelist bool, whitelistM
|
||||
continue
|
||||
}
|
||||
|
||||
if err := dev.forceBindVFIOPCIDriver(); err != nil {
|
||||
if err := dev.forceBindVFIOPCIDriver(o.HostOptions.UseBootVga, o.HostOptions.BootVgaPciAddr); err != nil {
|
||||
warns = append(warns, errors.Wrapf(err, "force bind vfio-pci driver %s", dev.Addr))
|
||||
continue
|
||||
}
|
||||
@@ -217,7 +229,7 @@ func NewPCIDevice(addr string, executors ...IExecutor) (*PCIDevice, error) {
|
||||
if err := dev.checkSameIOMMUGroupDevice(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := dev.forceBindVFIOPCIDriver(); err != nil {
|
||||
if err := dev.forceBindVFIOPCIDriver(o.HostOptions.UseBootVga, o.HostOptions.BootVgaPciAddr); err != nil {
|
||||
return nil, fmt.Errorf("Force bind vfio-pci driver: %v", err)
|
||||
}
|
||||
return dev, nil
|
||||
@@ -398,10 +410,32 @@ func (d *PCIDevice) IsBootVGA() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (d *PCIDevice) forceBindVFIOPCIDriver() error {
|
||||
if !utils.IsInArray(d.ClassCode, GpuClassCodes) {
|
||||
func (d *PCIDevice) forceBindVFIOPCIDriver(useBootVGA bool, bootVgaPciAddr string) error {
|
||||
if !utils.IsInStringArray(d.ClassCode, []string{CLASS_CODE_VGA, CLASS_CODE_3D}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !useBootVGA && bootVgaPciAddr != "" {
|
||||
if d.Addr == bootVgaPciAddr {
|
||||
log.Infof("device %#v is specific boot vga addr, skip it", d)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
isBootVGA, err := d.IsBootVGA()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !useBootVGA && isBootVGA {
|
||||
log.Infof("%#v is boot vga card, skip it", d)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if d.IsVFIOPCIDriverUsed() {
|
||||
log.Infof("%s already use vfio-pci driver", d)
|
||||
return nil
|
||||
}
|
||||
|
||||
devs := []*PCIDevice{}
|
||||
devs = append(devs, d.RestIOMMUGroupDevs...)
|
||||
devs = append(devs, d)
|
||||
|
||||
@@ -132,9 +132,10 @@ type SHostOptions struct {
|
||||
SetVncPassword bool `default:"true" help:"Auto set vnc password after monitor connected"`
|
||||
UseBootVga bool `default:"false" help:"Use boot VGA GPU for guest"`
|
||||
|
||||
EnableHostAgentNumaAllocate bool `default:"false" help:"Enable host agent numa allocate"`
|
||||
EnableCpuBinding bool `default:"true" help:"Enable cpu binding and rebalance"`
|
||||
EnableOpenflowController bool `default:"false"`
|
||||
EnableHostAgentNumaAllocate bool `default:"false" help:"Enable host agent numa allocate"`
|
||||
EnableCpuBinding bool `default:"true" help:"Enable cpu binding and rebalance"`
|
||||
EnableOpenflowController bool `default:"false"`
|
||||
BootVgaPciAddr string `help:"Specific boot vga pci addr incase detect wrong device"`
|
||||
|
||||
PingRegionInterval int `default:"60" help:"interval to ping region, deefault is 1 minute"`
|
||||
LogSystemdUnits []string `help:"Systemd units log collected by fluent-bit"`
|
||||
|
||||
@@ -72,10 +72,10 @@ type IDisk interface {
|
||||
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, blockStream bool) error
|
||||
DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error
|
||||
DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *desc.SGuestDesc,
|
||||
deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error)
|
||||
ConvertSnapshot(convertSnapshotId string) error
|
||||
ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error
|
||||
|
||||
// GetBackupDir() string
|
||||
DiskBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
|
||||
@@ -145,11 +145,11 @@ func (d *SBaseDisk) CreateSnapshot(snapshotId string, encryptKey string, encForm
|
||||
return errors.Errorf("unsupported operation")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) ConvertSnapshot(convertSnapshotId string) error {
|
||||
func (d *SBaseDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error {
|
||||
return errors.Errorf("unsupported operation")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
|
||||
func (d *SBaseDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
|
||||
return errors.Errorf("unsupported operation")
|
||||
}
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ func (d *SLocalDisk) CreateSnapshot(snapshotId string, encryptKey string, encFor
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string) error {
|
||||
func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error {
|
||||
snapshotDir := d.GetSnapshotDir()
|
||||
snapshotPath := path.Join(snapshotDir, convertSnapshotId)
|
||||
img, err := qemuimg.NewQemuImage(snapshotPath)
|
||||
@@ -482,7 +482,7 @@ func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
|
||||
func (d *SLocalDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
|
||||
snapshotDir := d.GetSnapshotDir()
|
||||
return DeleteLocalSnapshot(snapshotDir, snapshotId, d.getPath(), convertSnapshot, blockStream)
|
||||
}
|
||||
@@ -613,9 +613,15 @@ func (d *SLocalDisk) CleanupSnapshots(ctx context.Context, params interface{}) (
|
||||
|
||||
for _, snapshotId := range cleanupParams.DeleteSnapshots {
|
||||
snapId, _ := snapshotId.GetString()
|
||||
if err := procutils.NewCommand("rm", "-f", path.Join(snapshotDir, snapId)).Run(); err != nil {
|
||||
log.Errorln(err)
|
||||
return nil, err
|
||||
snapPath := path.Join(snapshotDir, snapId)
|
||||
if options.HostOptions.RecycleDiskfile {
|
||||
return nil, d.Storage.DeleteDiskfile(snapPath, false)
|
||||
} else {
|
||||
log.Infof("Delete disk(%s) snapshot %s", d.Id, snapId)
|
||||
if err := procutils.NewCommand("rm", "-f", snapPath).Run(); err != nil {
|
||||
log.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
@@ -387,23 +387,12 @@ func (d *SLVMDisk) PrepareSaveToGlance(ctx context.Context, params interface{})
|
||||
}
|
||||
|
||||
backupPath := path.Join(destDir, fmt.Sprintf("%s.%s", d.Id, appctx.AppContextTaskId(ctx)))
|
||||
srcInfo := qemuimg.SImageInfo{
|
||||
Path: d.GetPath(),
|
||||
Format: qemuImg.Format,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: "",
|
||||
}
|
||||
destInfo := qemuimg.SImageInfo{
|
||||
Path: backupPath,
|
||||
Format: qemuimgfmt.QCOW2,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: "",
|
||||
}
|
||||
if err = qemuimg.Convert(srcInfo, destInfo, true, nil); err != nil {
|
||||
if err := procutils.NewCommand("cp", "--sparse=always", "-f", d.GetPath(), backupPath).Run(); err != nil {
|
||||
log.Errorln(err)
|
||||
procutils.NewCommand("rm", "-f", backupPath).Run()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := jsonutils.NewDict()
|
||||
res.Set("backup", jsonutils.NewString(backupPath))
|
||||
return res, nil
|
||||
@@ -595,13 +584,13 @@ func (d *SLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (j
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
|
||||
func (d *SLVMDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
|
||||
if blockStream {
|
||||
if err := ConvertLVMDisk(d.Storage.GetPath(), d.Id); err != nil {
|
||||
if err := ConvertLVMDisk(d.Storage.GetPath(), d.Id, encryptInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(convertSnapshot) > 0 {
|
||||
if err := d.ConvertSnapshot(convertSnapshot); err != nil {
|
||||
if err := d.ConvertSnapshot(convertSnapshot, encryptInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -626,9 +615,9 @@ func (d *SLVMDisk) DeleteAllSnapshot(skipRecycle bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) ConvertSnapshot(convertSnapshot string) error {
|
||||
func (d *SLVMDisk) ConvertSnapshot(convertSnapshot string, encryptInfo apis.SEncryptInfo) error {
|
||||
convertSnapshotName := d.GetSnapshotName(convertSnapshot)
|
||||
return ConvertLVMDisk(d.Storage.GetPath(), convertSnapshotName)
|
||||
return ConvertLVMDisk(d.Storage.GetPath(), convertSnapshotName, encryptInfo)
|
||||
}
|
||||
|
||||
func (d *SLVMDisk) DoDeleteSnapshot(snapshotId string) error {
|
||||
|
||||
@@ -256,11 +256,11 @@ func (d *SRBDDisk) CreateSnapshot(snapshotId string, encryptKey string, encForma
|
||||
return storage.createSnapshot(d.Id, snapshotId)
|
||||
}
|
||||
|
||||
func (d *SRBDDisk) ConvertSnapshot(convertSnapshotId string) error {
|
||||
func (d *SRBDDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SRBDDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool) error {
|
||||
func (d *SRBDDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
|
||||
storage := d.Storage.(*SRbdStorage)
|
||||
return storage.deleteSnapshot(d.Id, snapshotId)
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func (d *SRBDDisk) DiskDeleteSnapshot(ctx context.Context, params interface{}) (
|
||||
if !ok {
|
||||
return nil, hostutils.ParamsError
|
||||
}
|
||||
err := d.DeleteSnapshot(snapshotId, "", false)
|
||||
err := d.DeleteSnapshot(snapshotId, "", false, apis.SEncryptInfo{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
|
||||
@@ -243,6 +243,46 @@ func (d *SSLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (d *SSLVMDisk) GetDiskDesc() jsonutils.JSONObject {
|
||||
active, err := lvmutils.LvIsActivated(d.GetPath())
|
||||
if err != nil {
|
||||
log.Errorf("failed check active of %s: %s", d.GetPath(), err)
|
||||
return nil
|
||||
}
|
||||
if !active {
|
||||
if err := lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false); err != nil {
|
||||
log.Errorf("failed active lv %s: %s", d.GetPath(), err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
res := d.SLVMDisk.GetDiskDesc()
|
||||
if !active {
|
||||
if err := lvmutils.LVDeactivate(d.GetPath()); err != nil {
|
||||
log.Errorf("failed deactivate lv %s: %s", d.GetPath(), err)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (d *SSLVMDisk) PrepareSaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
|
||||
active, err := lvmutils.LvIsActivated(d.GetPath())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "LvIsActivated")
|
||||
}
|
||||
if !active {
|
||||
if err := lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false); err != nil {
|
||||
return nil, errors.Wrap(err, "LVActive")
|
||||
}
|
||||
}
|
||||
res, e := d.SLVMDisk.PrepareSaveToGlance(ctx, params)
|
||||
if !active {
|
||||
if err := lvmutils.LVDeactivate(d.GetPath()); err != nil {
|
||||
log.Errorf("failed deactivate lv %s: %s", d.GetPath(), err)
|
||||
}
|
||||
}
|
||||
return res, e
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -261,3 +301,27 @@ func (d *SSLVMDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLoca
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (d *SSLVMDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error {
|
||||
err := lvmutils.LVActive(d.GetPath(), false, d.Storage.Lvmlockd())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "LVActive")
|
||||
}
|
||||
convertSnapshotPath := d.GetSnapshotPath(convertSnapshot)
|
||||
err = lvmutils.LVActive(convertSnapshotPath, false, d.Storage.Lvmlockd())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "LVActive convert snapshot")
|
||||
}
|
||||
|
||||
err = d.SLVMDisk.DeleteSnapshot(snapshotId, convertSnapshot, blockStream, encryptInfo)
|
||||
// active disk share mode
|
||||
e := lvmutils.LVActive(d.GetPath(), d.Storage.Lvmlockd(), false)
|
||||
if e != nil {
|
||||
log.Errorf("failed active with share mode: %s", e)
|
||||
}
|
||||
e = lvmutils.LVActive(convertSnapshotPath, d.Storage.Lvmlockd(), false)
|
||||
if e != nil {
|
||||
log.Errorf("failed active convert snapshot %s with share mode: %s", convertSnapshotPath, e)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
|
||||
@@ -38,10 +39,13 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/remotefile"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
identity_modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/image"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
"yunion.io/x/onecloud/pkg/util/qemuimg"
|
||||
"yunion.io/x/onecloud/pkg/util/seclib2"
|
||||
)
|
||||
|
||||
type SLVMStorage struct {
|
||||
@@ -212,12 +216,12 @@ func (s *SLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (j
|
||||
return nil, hostutils.ParamsError
|
||||
}
|
||||
if input.BlockStream {
|
||||
if err := ConvertLVMDisk(s.GetPath(), input.DiskId); err != nil {
|
||||
if err := ConvertLVMDisk(s.GetPath(), input.DiskId, input.EncryptInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if len(input.ConvertSnapshot) > 0 {
|
||||
convertSnapshotName := "snap_" + input.ConvertSnapshot
|
||||
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName); err != nil {
|
||||
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName, input.EncryptInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -275,9 +279,28 @@ func (s *SLVMStorage) SaveToGlance(ctx context.Context, input interface{}) (json
|
||||
imageId, _ = data.GetString("image_id")
|
||||
imagePath, _ = data.GetString("image_path")
|
||||
compress = jsonutils.QueryBoolean(data, "compress", true)
|
||||
encKeyId, _ = data.GetString("encrypt_key_id")
|
||||
err error
|
||||
)
|
||||
if err = s.saveToGlance(ctx, imageId, imagePath, compress); err != nil {
|
||||
|
||||
var (
|
||||
encKey string
|
||||
encFormat qemuimg.TEncryptFormat
|
||||
encAlg seclib2.TSymEncAlg
|
||||
)
|
||||
|
||||
if len(encKeyId) > 0 {
|
||||
session := auth.GetSession(ctx, info.UserCred, consts.GetRegion())
|
||||
key, err := identity_modules.Credentials.GetEncryptKey(session, encKeyId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetEncryptKey")
|
||||
}
|
||||
encKey = key.Key
|
||||
encFormat = qemuimg.EncryptFormatLuks
|
||||
encAlg = key.Alg
|
||||
}
|
||||
|
||||
if err = s.saveToGlance(ctx, imageId, imagePath, compress, encKey, encFormat, encAlg); err != nil {
|
||||
log.Errorf("Save to glance failed: %s", err)
|
||||
s.onSaveToGlanceFailed(ctx, imageId, err.Error())
|
||||
}
|
||||
@@ -300,11 +323,19 @@ func (s *SLVMStorage) SaveToGlance(ctx context.Context, input interface{}) (json
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *SLVMStorage) saveToGlance(ctx context.Context, imageId, imagePath string, compress bool) error {
|
||||
func (s *SLVMStorage) saveToGlance(
|
||||
ctx context.Context, imageId, imagePath string, compress bool,
|
||||
encryptKey string, encFormat qemuimg.TEncryptFormat, encAlg seclib2.TSymEncAlg,
|
||||
) error {
|
||||
log.Infof("saveToGlance %s", imagePath)
|
||||
diskInfo := &deployapi.DiskInfo{
|
||||
Path: imagePath,
|
||||
}
|
||||
if len(encryptKey) > 0 {
|
||||
diskInfo.EncryptPassword = encryptKey
|
||||
diskInfo.EncryptFormat = string(encFormat)
|
||||
diskInfo.EncryptAlg = string(encAlg)
|
||||
}
|
||||
ret, err := deployclient.GetDeployClient().SaveToGlance(ctx,
|
||||
&deployapi.SaveToGlanceParams{DiskInfo: diskInfo, Compress: compress})
|
||||
if err != nil {
|
||||
@@ -619,7 +650,7 @@ func (d *SLVMStorage) GetDisksPath() ([]string, error) {
|
||||
return disksPath, nil
|
||||
}
|
||||
|
||||
func ConvertLVMDisk(vgName, lvName string) error {
|
||||
func ConvertLVMDisk(vgName, lvName string, encryptInfo apis.SEncryptInfo) error {
|
||||
diskPath := path.Join("/dev", vgName, lvName)
|
||||
qemuImg, err := qemuimg.NewQemuImage(diskPath)
|
||||
if err != nil {
|
||||
@@ -638,16 +669,22 @@ func ConvertLVMDisk(vgName, lvName string) error {
|
||||
return errors.Wrap(err, "delete snapshot LvCreate")
|
||||
}
|
||||
srcInfo := qemuimg.SImageInfo{
|
||||
Path: diskPath,
|
||||
Format: qemuImg.Format,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: "",
|
||||
Path: diskPath,
|
||||
Format: qemuImg.Format,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
|
||||
Password: encryptInfo.Key,
|
||||
EncryptAlg: encryptInfo.Alg,
|
||||
EncryptFormat: qemuimg.EncryptFormatLuks,
|
||||
}
|
||||
destInfo := qemuimg.SImageInfo{
|
||||
Path: tmpVolumePath,
|
||||
Format: qemuimgfmt.QCOW2,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
Password: "",
|
||||
Path: tmpVolumePath,
|
||||
Format: qemuimgfmt.QCOW2,
|
||||
IoLevel: qemuimg.IONiceNone,
|
||||
|
||||
Password: encryptInfo.Key,
|
||||
EncryptAlg: encryptInfo.Alg,
|
||||
EncryptFormat: qemuimg.EncryptFormatLuks,
|
||||
}
|
||||
// convert /dev/vg/disk to /dev/vg/disk-convert.tmp
|
||||
if err = qemuimg.Convert(srcInfo, destInfo, false, nil); err != nil {
|
||||
|
||||
@@ -121,7 +121,7 @@ func (s *SSLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (
|
||||
return nil, errors.Wrap(err, "lvactive exclusive")
|
||||
}
|
||||
|
||||
err = ConvertLVMDisk(s.GetPath(), input.DiskId)
|
||||
err = ConvertLVMDisk(s.GetPath(), input.DiskId, input.EncryptInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func (s *SSLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (
|
||||
return nil, errors.Wrap(err, "lvactive exclusive")
|
||||
}
|
||||
|
||||
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName); err != nil {
|
||||
if err := ConvertLVMDisk(s.GetPath(), convertSnapshotName, input.EncryptInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
@@ -466,6 +467,15 @@ func storageDeleteSnapshot(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||
SnapshotId: snapshotId,
|
||||
}
|
||||
|
||||
if body.Contains("encrypt_info") {
|
||||
encryptInfo := apis.SEncryptInfo{}
|
||||
if err = body.Unmarshal(&encryptInfo, "encrypt_info"); err != nil {
|
||||
hostutils.Response(ctx, w, httperrors.NewInputParameterError("unmarshal encrypt_info failed %s", err))
|
||||
return
|
||||
}
|
||||
input.EncryptInfo = encryptInfo
|
||||
}
|
||||
|
||||
if !blockStream && !autoDeleted {
|
||||
convertSnapshot, err := body.GetString("convert_snapshot")
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
@@ -71,6 +72,7 @@ type SStorageDeleteSnapshot struct {
|
||||
SnapshotId string
|
||||
ConvertSnapshot string
|
||||
BlockStream bool
|
||||
EncryptInfo apis.SEncryptInfo
|
||||
}
|
||||
|
||||
type SDiskBackup struct {
|
||||
|
||||
@@ -372,10 +372,13 @@ func convertEncrypt(srcInfo, destInfo SImageInfo, compact bool, workerOpions []s
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "NewQemuImage dest %s", destInfo.Path)
|
||||
}
|
||||
err = target.CreateQcow2(source.GetSizeMB(), compact, "", destInfo.Password, destInfo.EncryptFormat, destInfo.EncryptAlg)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Create target image %s", destInfo.Path)
|
||||
if target.Format != qemuimgfmt.QCOW2 {
|
||||
err = target.CreateQcow2(source.GetSizeMB(), compact, "", destInfo.Password, destInfo.EncryptFormat, destInfo.EncryptAlg)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Create target image %s", destInfo.Path)
|
||||
}
|
||||
}
|
||||
|
||||
cmdline := []string{"-c", strconv.Itoa(int(srcInfo.IoLevel)), qemutils.GetQemuImg(), "convert"}
|
||||
if compact {
|
||||
cmdline = append(cmdline, "-c")
|
||||
|
||||
Reference in New Issue
Block a user