From cafb619a9f76e65e033aa6c70b7d2f5d6e1bd595 Mon Sep 17 00:00:00 2001 From: wanyaoqi <18528551+wanyaoqi@users.noreply.github.com> Date: Wed, 15 May 2024 10:45:59 +0800 Subject: [PATCH] fix(region,host): slvm misc fix (#20270) --- pkg/compute/hostdrivers/baremetal.go | 2 +- pkg/compute/hostdrivers/kvm.go | 5 ++- pkg/compute/hostdrivers/managedvirtual.go | 2 +- pkg/compute/models/hostdrivers.go | 2 +- pkg/compute/models/storages.go | 14 +++++++ pkg/compute/tasks/guest_insert_iso_task.go | 1 + pkg/compute/tasks/storage_cache_image_task.go | 28 +++++++------ .../tasks/storage_uncache_image_task.go | 39 +++++++++++++++++-- pkg/hostman/guestman/qemu-kvm.go | 18 ++++++++- pkg/hostman/storageman/disk_lvm.go | 2 +- pkg/hostman/storageman/disk_slvm.go | 38 ++++++++++++++++++ .../storageman/diskhandlers/diskhandler.go | 11 +++++- pkg/hostman/storageman/imagecache_lvm.go | 7 +++- pkg/hostman/storageman/imagecache_rbd.go | 2 +- .../storageman/imagecachemanager_lvm.go | 17 +++++++- 15 files changed, 164 insertions(+), 24 deletions(-) diff --git a/pkg/compute/hostdrivers/baremetal.go b/pkg/compute/hostdrivers/baremetal.go index fbbd9f60d6..3c05fd7234 100644 --- a/pkg/compute/hostdrivers/baremetal.go +++ b/pkg/compute/hostdrivers/baremetal.go @@ -107,6 +107,6 @@ func (self *SBaremetalHostDriver) RequestSaveUploadImageOnHost(ctx context.Conte return fmt.Errorf("not supported") } -func (self *SBaremetalHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { +func (self *SBaremetalHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask, deactivateImage bool) error { return fmt.Errorf("not supported") } diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index bf2bd237b5..66237f297b 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -248,7 +248,7 @@ func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, userCred return nil } -func (self *SKVMHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { +func (self *SKVMHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask, deactivateImage bool) error { type contentStruct struct { ImageId string StoragecacheId string @@ -268,6 +268,9 @@ func (self *SKVMHostDriver) RequestUncacheImage(ctx context.Context, host *model body := jsonutils.NewDict() body.Add(jsonutils.Marshal(&content), "disk") + if deactivateImage { + body.Add(jsonutils.JSONTrue, "deactivate_image") + } header := task.GetTaskRequestHeader() diff --git a/pkg/compute/hostdrivers/managedvirtual.go b/pkg/compute/hostdrivers/managedvirtual.go index 1e24bba272..b285f8956a 100644 --- a/pkg/compute/hostdrivers/managedvirtual.go +++ b/pkg/compute/hostdrivers/managedvirtual.go @@ -160,7 +160,7 @@ func (self *SManagedVirtualizationHostDriver) CheckAndSetCacheImage(ctx context. return nil } -func (self *SManagedVirtualizationHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { +func (self *SManagedVirtualizationHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask, deactivateImage bool) error { params := task.GetParams() imageId, err := params.GetString("image_id") if err != nil { diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 44605659c1..fce37f4efa 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -30,7 +30,7 @@ type IHostDriver interface { GetHypervisor() string CheckAndSetCacheImage(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, storagecache *SStoragecache, task taskman.ITask) error - RequestUncacheImage(ctx context.Context, host *SHost, storageCache *SStoragecache, task taskman.ITask) error + RequestUncacheImage(ctx context.Context, host *SHost, storageCache *SStoragecache, task taskman.ITask, deactivateImage bool) error ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, input api.DiskUpdateInput) (api.DiskUpdateInput, error) ValidateResetDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, snapshot *SSnapshot, guests []SGuest, input *api.DiskResetInput) (*api.DiskResetInput, error) diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index b9c9d96a3c..9d8ae523b3 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -221,6 +221,10 @@ func (self *SStorage) IsNeedDeleteStoragecache() (bool, error) { return cnt == 0, nil } +func (self *SStorage) IsNeedDeactivateOnAllHost() bool { + return self.StorageType == api.STORAGE_SLVM +} + func (manager *SStorageManager) GetStorageTypesByHostType(hostType string) ([]string, error) { q := manager.Query("storage_type") hosts := HostManager.Query().SubQuery() @@ -870,6 +874,16 @@ func (manager *SStorageManager) getStoragesByZone(zone *SZone, provider *SCloudp return storages, nil } +func (manager *SStorageManager) GetStorageByStoragecache(storagecacheId string) (*SStorage, error) { + s := SStorage{} + s.SetModelManager(StorageManager, &s) + err := manager.Query().Equals("storagecache_id", storagecacheId).First(&s) + if err != nil { + return nil, errors.Wrap(err, "get storage by storagecache") + } + return &s, nil +} + func (manager *SStorageManager) scanLegacyStorages() error { storages := make([]SStorage, 0) table := manager.Query().SubQuery() diff --git a/pkg/compute/tasks/guest_insert_iso_task.go b/pkg/compute/tasks/guest_insert_iso_task.go index 6e9b471370..a8e8068550 100644 --- a/pkg/compute/tasks/guest_insert_iso_task.go +++ b/pkg/compute/tasks/guest_insert_iso_task.go @@ -56,6 +56,7 @@ func (self *GuestInsertIsoTask) prepareIsoImage(ctx context.Context, obj db.ISta ImageId: imageId, Format: "iso", ParentTaskId: self.GetTaskId(), + ServerId: guest.Id, } storageCache.StartImageCacheTask(ctx, self.UserCred, input) } else { diff --git a/pkg/compute/tasks/storage_cache_image_task.go b/pkg/compute/tasks/storage_cache_image_task.go index 985262fbaa..81a0ab999d 100644 --- a/pkg/compute/tasks/storage_cache_image_task.go +++ b/pkg/compute/tasks/storage_cache_image_task.go @@ -64,19 +64,25 @@ func (self *StorageCacheImageTask) OnRelinquishLeastUsedCachedImageComplete(ctx self.SetStage("OnImageCacheComplete", nil) - host, err := storageCache.GetMasterHost() - if err != nil { - errData := taskman.Error2TaskData(err) - self.OnImageCacheCompleteFailed(ctx, storageCache, errData) - return - } - + var host *models.SHost + var err error serverId, _ := self.Params.GetString("server_id") if len(serverId) > 0 { - guest, _ := models.GuestManager.FetchById(serverId) - if guest != nil { - server := guest.(*models.SGuest) - server.SetStatus(ctx, self.GetUserCred(), api.VM_IMAGE_CACHING, "") + guest, err := models.GuestManager.FetchById(serverId) + if err != nil { + errData := taskman.Error2TaskData(err) + self.OnImageCacheCompleteFailed(ctx, storageCache, errData) + return + } + server := guest.(*models.SGuest) + server.SetStatus(ctx, self.GetUserCred(), api.VM_IMAGE_CACHING, "") + host, _ = server.GetHost() + } else { + host, err = storageCache.GetMasterHost() + if err != nil { + errData := taskman.Error2TaskData(err) + self.OnImageCacheCompleteFailed(ctx, storageCache, errData) + return } } diff --git a/pkg/compute/tasks/storage_uncache_image_task.go b/pkg/compute/tasks/storage_uncache_image_task.go index 60329eab63..afa6a641d0 100644 --- a/pkg/compute/tasks/storage_uncache_image_task.go +++ b/pkg/compute/tasks/storage_uncache_image_task.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" @@ -56,6 +57,39 @@ func (self *StorageUncacheImageTask) OnInit(ctx context.Context, obj db.IStandal return } + storage, err := models.StorageManager.GetStorageByStoragecache(storageCache.Id) + if err != nil { + self.OnTaskFailed(ctx, storageCache, jsonutils.NewString(fmt.Sprintf("fail to get storage by storagecache %s", err))) + return + } + if storage.IsNeedDeactivateOnAllHost() { + self.RequestUncacheDeactivateImage(ctx, storageCache) + return + } + self.RequestUncacheRemoveImage(ctx, storageCache) +} + +func (self *StorageUncacheImageTask) RequestUncacheDeactivateImage(ctx context.Context, storageCache *models.SStoragecache) { + hosts, err := storageCache.GetHosts() + if err != nil { + self.OnTaskFailed(ctx, storageCache, jsonutils.NewString(fmt.Sprintf("fail to get hosts %s", err))) + return + } + for i := range hosts { + if !hosts[i].Enabled.IsTrue() || hosts[i].HostStatus != compute.HOST_ONLINE { + continue + } + err = hosts[i].GetHostDriver().RequestUncacheImage(ctx, &hosts[i], storageCache, self, true) + if err != nil { + self.OnTaskFailed(ctx, storageCache, jsonutils.NewString(err.Error())) + return + } + } + + self.RequestUncacheRemoveImage(ctx, storageCache) +} + +func (self *StorageUncacheImageTask) RequestUncacheRemoveImage(ctx context.Context, storageCache *models.SStoragecache) { host, err := storageCache.GetMasterHost() if err != nil { self.OnTaskFailed(ctx, storageCache, jsonutils.NewString(fmt.Sprintf("fail to get host %s", err))) @@ -63,13 +97,12 @@ func (self *StorageUncacheImageTask) OnInit(ctx context.Context, obj db.IStandal } if host == nil { - self.OnImageUncacheComplete(ctx, obj, data) + self.OnImageUncacheComplete(ctx, storageCache, nil) return } self.SetStage("OnImageUncacheComplete", nil) - - err = host.GetHostDriver().RequestUncacheImage(ctx, host, storageCache, self) + err = host.GetHostDriver().RequestUncacheImage(ctx, host, storageCache, self, false) if err != nil { self.OnTaskFailed(ctx, storageCache, jsonutils.NewString(err.Error())) diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 9705751756..21b558be89 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -2095,7 +2095,13 @@ func (s *SKVMGuestInstance) DeployFs(ctx context.Context, userCred mcclient.Toke return nil, errors.Wrapf(err, "GetDiskByPath(%s)", diskPath) } diskInfo.Path = disk.GetPath() - return disk.DeployGuestFs(&diskInfo, s.Desc, deployInfo) + ret, err := disk.DeployGuestFs(&diskInfo, s.Desc, deployInfo) + if utils.IsInStringArray(disk.GetType(), []string{api.STORAGE_SLVM, api.STORAGE_CLVM}) { + if errDeactive := lvmutils.LVDeactivate(diskPath); err != nil { + log.Errorf("failed deactive disk %s: %s", diskPath, errDeactive) + } + } + return ret, err } else { return nil, fmt.Errorf("Guest dosen't have disk ??") } @@ -3467,6 +3473,7 @@ func (s *SKVMGuestInstance) IsSharedStorage() bool { } func (s *SKVMGuestInstance) generateDiskSetupScripts(disks []*desc.SGuestDisk) (string, error) { + slvmImages := map[string]string{} cmd := " " for i := range disks { diskPath := disks[i].Path @@ -3474,12 +3481,21 @@ func (s *SKVMGuestInstance) generateDiskSetupScripts(disks []*desc.SGuestDisk) ( if err != nil { return "", errors.Wrapf(err, "GetDiskByPath(%s)", diskPath) } + if d.GetType() == api.STORAGE_SLVM && disks[i].TemplateId != "" { + slvmImages[disks[i].StorageId] = disks[i].TemplateId + } if len(disks[i].StorageType) == 0 { disks[i].StorageType = d.GetType() } diskIndex := disks[i].Index cmd += d.GetDiskSetupScripts(int(diskIndex)) } + + for storageId, imageId := range slvmImages { + storage := storageman.GetManager().GetStorage(storageId) + imageCacheManager := storageman.GetManager().GetStoragecacheById(storage.GetStoragecacheId()) + imageCacheManager.LoadImageCache(imageId) + } return cmd, nil } diff --git a/pkg/hostman/storageman/disk_lvm.go b/pkg/hostman/storageman/disk_lvm.go index 4df2784c1f..9296dcdebe 100644 --- a/pkg/hostman/storageman/disk_lvm.go +++ b/pkg/hostman/storageman/disk_lvm.go @@ -77,7 +77,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_" + d.Id + "_" + snapshotId } func (d *SLVMDisk) GetSnapshotPath(snapshotId string) string { diff --git a/pkg/hostman/storageman/disk_slvm.go b/pkg/hostman/storageman/disk_slvm.go index f25c93a686..8f0a3fac69 100644 --- a/pkg/hostman/storageman/disk_slvm.go +++ b/pkg/hostman/storageman/disk_slvm.go @@ -28,6 +28,7 @@ import ( "yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/qemuimg" + "yunion.io/x/onecloud/pkg/util/seclib2" ) // shared lvm @@ -170,3 +171,40 @@ func (d *SSLVMDisk) Delete(ctx context.Context, params interface{}) (jsonutils.J } 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) + 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) + } + return err + } + snapPath := d.GetSnapshotPath(snapshotId) + err = lvmutils.LVActive(snapPath, false, true) + if err != nil { + return errors.Wrap(err, "lvactive snapshot share") + } + return nil +} + +func (d *SSLVMDisk) ResetFromSnapshot(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { + err := lvmutils.LVActive(d.GetPath(), false, true) + 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) + if err != nil { + log.Errorf("failed lvactive share %s", err) + } + return nil, err + } + return ret, nil +} diff --git a/pkg/hostman/storageman/diskhandlers/diskhandler.go b/pkg/hostman/storageman/diskhandlers/diskhandler.go index a4c22c979f..efba2d7e4c 100644 --- a/pkg/hostman/storageman/diskhandlers/diskhandler.go +++ b/pkg/hostman/storageman/diskhandlers/diskhandler.go @@ -118,7 +118,16 @@ func performImageCache( if performAction == "perfetch" { performTask = storagecache.PrefetchImageCache } else { - performTask = storagecache.DeleteImageCache + if jsonutils.QueryBoolean(body, "deactivate_image", false) { + _, err := storagecache.DeleteImageCache(ctx, body) + if err != nil { + hostutils.Response(ctx, w, err) + } + hostutils.ResponseOk(ctx, w) + return + } else { + performTask = storagecache.DeleteImageCache + } } hostutils.DelayTask(ctx, performTask, disk) diff --git a/pkg/hostman/storageman/imagecache_lvm.go b/pkg/hostman/storageman/imagecache_lvm.go index 0e6c00c7e2..183a0e684c 100644 --- a/pkg/hostman/storageman/imagecache_lvm.go +++ b/pkg/hostman/storageman/imagecache_lvm.go @@ -24,6 +24,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/httputils" + "yunion.io/x/pkg/util/qemuimgfmt" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/hostman/hostutils" @@ -123,9 +124,13 @@ func (c *SLVMImageCache) Acquire( } } + targetImageFormat := "qcow2" + if localImg.Format != qemuimgfmt.QCOW2 { + targetImageFormat = "raw" + } log.Infof("convert local image %s to lvm %s", c.imageId, c.GetPath()) out, err := procutils.NewRemoteCommandAsFarAsPossible(qemutils.GetQemuImg(), - "convert", "-W", "-m", "16", "-O", "qcow2", localImageCache.GetPath(), c.GetPath()).Output() + "convert", "-W", "-m", "16", "-O", targetImageFormat, localImageCache.GetPath(), c.GetPath()).Output() if err != nil { return errors.Wrapf(err, "convert local image %s to lvm %s: %s", c.imageId, c.GetPath(), out) } diff --git a/pkg/hostman/storageman/imagecache_rbd.go b/pkg/hostman/storageman/imagecache_rbd.go index 341f3a48d5..5a3f987a2f 100644 --- a/pkg/hostman/storageman/imagecache_rbd.go +++ b/pkg/hostman/storageman/imagecache_rbd.go @@ -88,7 +88,7 @@ func (r *SRbdImageCache) Acquire(ctx context.Context, input api.CacheImageInput, err := procutils.NewRemoteCommandAsFarAsPossible(qemutils.GetQemuImg(), "convert", "-W", "-m", "16", "-O", "raw", localImageCache.GetPath(), r.GetPath()).Run() if err != nil { - return errors.Wrapf(err, "convert loca image %s to rbd pool %s at host %s", r.imageId, r.Manager.GetPath(), options.HostOptions.Hostname) + return errors.Wrapf(err, "convert local image %s to rbd pool %s at host %s", r.imageId, r.Manager.GetPath(), options.HostOptions.Hostname) } if len(input.ServerId) > 0 { modules.Servers.Update(hostutils.GetComputeSession(context.Background()), input.ServerId, jsonutils.Marshal(map[string]float32{"progress": 100.0})) diff --git a/pkg/hostman/storageman/imagecachemanager_lvm.go b/pkg/hostman/storageman/imagecachemanager_lvm.go index e488031921..368e8321b0 100644 --- a/pkg/hostman/storageman/imagecachemanager_lvm.go +++ b/pkg/hostman/storageman/imagecachemanager_lvm.go @@ -165,7 +165,22 @@ func (c *SLVMImageCacheManager) DeleteImageCache(ctx context.Context, data inter } imageId, _ := body.GetString("image_id") - return nil, c.RemoveImage(ctx, imageId) + if jsonutils.QueryBoolean(body, "deactivate_image", false) { + return nil, c.DeactiveImageCacahe(ctx, imageId) + } else { + return nil, c.RemoveImage(ctx, imageId) + } +} + +func (c *SLVMImageCacheManager) DeactiveImageCacahe(ctx context.Context, imageId string) error { + lockman.LockRawObject(ctx, "image-cache", imageId) + defer lockman.ReleaseRawObject(ctx, "image-cache", imageId) + + if img, ok := c.cachedImages.Load(imageId); ok { + c.cachedImages.Delete(imageId) + return lvmutils.LVDeactivate(img.(IImageCache).GetPath()) + } + return nil } func (c *SLVMImageCacheManager) RemoveImage(ctx context.Context, imageId string) error {