diff --git a/pkg/compute/tasks/guest_live_migrate_task.go b/pkg/compute/tasks/guest_live_migrate_task.go index 38b0b9f267..66f5da8298 100644 --- a/pkg/compute/tasks/guest_live_migrate_task.go +++ b/pkg/compute/tasks/guest_live_migrate_task.go @@ -285,9 +285,8 @@ func (self *GuestMigrateTask) localStorageMigrateConf(ctx context.Context, targetStorage := targetHost.GetHoststorageOfId(targetStorageId) sourceStorage := sourceHost.GetHoststorageOfId(disks[0].GetDisk().StorageId) if sourceStorage.MountPoint != targetStorage.MountPoint { - self.TaskFailed(ctx, guest, fmt.Sprintf("target host %s storage"+ - "mount point is different with source storage", targetHost.Id)) - return nil, true + // rebase disks backing file + body.Set("rebase_disks", jsonutils.JSONTrue) } body.Set("desc", targetDesc) body.Set("is_local_storage", jsonutils.JSONTrue) diff --git a/pkg/compute/tasks/storage_cache_image_task.go b/pkg/compute/tasks/storage_cache_image_task.go index bb9a9fdfbd..d0326f9337 100644 --- a/pkg/compute/tasks/storage_cache_image_task.go +++ b/pkg/compute/tasks/storage_cache_image_task.go @@ -70,7 +70,6 @@ func (self *StorageCacheImageTask) OnRelinquishLeastUsedCachedImageComplete(ctx errData := taskman.Error2TaskData(err) self.OnImageCacheCompleteFailed(ctx, storageCache, errData) } - } func (self *StorageCacheImageTask) OnImageCacheComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index a4e3483994..d91ebb84a9 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -317,6 +317,7 @@ func guestDestPrepareMigrate(ctx context.Context, sid string, body jsonutils.JSO } params.TargetStorageId = targetStorageId } + params.RebaseDisks = jsonutils.QueryBoolean(body, "rebase_disks", false) } hostutils.DelayTask(ctx, guestman.GetGuestManager().DestPrepareMigrate, params) return nil, nil diff --git a/pkg/hostman/guestman/guesthelper.go b/pkg/hostman/guestman/guesthelper.go index 664e169be7..327a0fc020 100644 --- a/pkg/hostman/guestman/guesthelper.go +++ b/pkg/hostman/guestman/guesthelper.go @@ -44,6 +44,7 @@ type SDestPrepareMigrate struct { DisksUri string TargetStorageId string LiveMigrate bool + RebaseDisks bool Desc jsonutils.JSONObject DisksBackingFile jsonutils.JSONObject diff --git a/pkg/hostman/guestman/guestman.go b/pkg/hostman/guestman/guestman.go index a9a7648444..7a70064705 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -491,7 +491,7 @@ func (m *SGuestManager) DestPrepareMigrate(ctx context.Context, params interface err := iStorage.DestinationPrepareMigrate( ctx, migParams.LiveMigrate, migParams.DisksUri, migParams.SnapshotsUri, - migParams.Desc, migParams.DisksBackingFile, migParams.SrcSnapshots) + migParams.Desc, migParams.DisksBackingFile, migParams.SrcSnapshots, migParams.RebaseDisks) if err != nil { return nil, fmt.Errorf("dest prepare migrate failed %s", err) } diff --git a/pkg/hostman/storageman/storage_base.go b/pkg/hostman/storageman/storage_base.go index 444c6b7833..ceed6451a3 100644 --- a/pkg/hostman/storageman/storage_base.go +++ b/pkg/hostman/storageman/storage_base.go @@ -112,7 +112,8 @@ type IStorage interface { GetFuseMountPath() string GetImgsaveBackupPath() string - DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, desc, disksBackingFile, srcSnapshots jsonutils.JSONObject) error + DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, + desc, disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool) error } type SBaseStorage struct { @@ -320,7 +321,10 @@ func (s *SBaseStorage) CreateDiskFromSnpashot(ctx context.Context, disk IDisk, c return disk.GetDiskDesc(), nil } -func (s *SBaseStorage) DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, desc, disksBackingFile, srcSnapshots jsonutils.JSONObject) error { +func (s *SBaseStorage) DestinationPrepareMigrate( + ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, + desc, disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool, +) error { return nil } diff --git a/pkg/hostman/storageman/storage_local.go b/pkg/hostman/storageman/storage_local.go index 854917ecd5..73c3759269 100644 --- a/pkg/hostman/storageman/storage_local.go +++ b/pkg/hostman/storageman/storage_local.go @@ -21,6 +21,7 @@ import ( "path" "time" + "github.com/pkg/errors" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/util/timeutils" @@ -322,7 +323,9 @@ func (s *SLocalStorage) DeleteSnapshots(ctx context.Context, params interface{}) return nil, nil } -func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, desc, disksBackingFile, srcSnapshots jsonutils.JSONObject) error { +func (s *SLocalStorage) DestinationPrepareMigrate( + ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, + desc, disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool) error { disks, _ := desc.GetArray("disks") for i, diskinfo := range disks { var ( @@ -336,6 +339,7 @@ func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigra "Storage %s create disk %s failed", s.GetId(), diskId) } + templateId, _ := diskinfo.GetString("template_id") // prepare disk snapshot dir if len(snapshots) > 0 && !fileutils2.Exists(disk.GetSnapshotDir()) { _, err := procutils.NewCommand("mkdir", "-p", disk.GetSnapshotDir()).Run() @@ -345,15 +349,30 @@ func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigra } // create snapshots form remote url - diskStorageId, _ := diskinfo.GetString("storage_id") - for _, snapshotId := range snapshots { + var ( + diskStorageId, _ = diskinfo.GetString("storage_id") + baseImagePath string + ) + for i, snapshotId := range snapshots { snapId, _ := snapshotId.GetString() - snapshotUrl := fmt.Sprintf("%s/%s/%s/%s", snapshotsUri, diskStorageId, diskId, snapId) snapshotPath := path.Join(disk.GetSnapshotDir(), snapId) log.Infof("Disk %s snapshot %s url: %s", diskId, snapId, snapshotUrl) - s.CreateSnapshotFormUrl(ctx, snapshotUrl, diskId, snapshotPath) + if err := s.CreateSnapshotFormUrl(ctx, snapshotUrl, diskId, snapshotPath); err != nil { + return errors.Wrap(err, "create from snapshot url failed") + } + baseImagePath = snapshotPath + if i == 0 && len(templateId) > 0 { + templatePath := path.Join(storageManager.LocalStorageImagecacheManager.GetPath(), templateId) + if err := doRebaseDisk(snapshotPath, templatePath); err != nil { + return err + } + } else if rebaseDisks { + if err := doRebaseDisk(snapshotPath, baseImagePath); err != nil { + return err + } + } } if liveMigrate { @@ -373,8 +392,30 @@ func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigra return err } } + if rebaseDisks && len(templateId) > 0 && len(baseImagePath) == 0 { + templatePath := path.Join(storageManager.LocalStorageImagecacheManager.GetPath(), templateId) + if err := doRebaseDisk(disk.GetPath(), templatePath); err != nil { + return err + } + } else if rebaseDisks && len(baseImagePath) > 0 { + if err := doRebaseDisk(disk.GetPath(), baseImagePath); err != nil { + return err + } + } diskDesc, _ := disks[i].(*jsonutils.JSONDict) diskDesc.Set("path", jsonutils.NewString(disk.GetPath())) } return nil } + +func doRebaseDisk(diskPath, newBasePath string) error { + img, err := qemuimg.NewQemuImage(diskPath) + if err != nil { + return errors.Wrap(err, "failed open disk as qemu image") + } + if err = img.Rebase(newBasePath, true); err != nil { + return errors.Wrap(err, "failed rebase disk backing file") + } + log.Infof("rebase disk %s backing file to %s ", diskPath, newBasePath) + return nil +}