diff --git a/pkg/compute/models/guestdisks.go b/pkg/compute/models/guestdisks.go index bee32cc17f..74ae4c81e8 100644 --- a/pkg/compute/models/guestdisks.go +++ b/pkg/compute/models/guestdisks.go @@ -212,15 +212,11 @@ func (self *SGuestdisk) GetJsonDescAtHost(host *SHost) jsonutils.JSONObject { desc.Add(jsonutils.NewString(storagecacheimg.Path), "image_path") } } - storage := disk.GetStorage() - // XXX ??? if host.HostType == api.HOST_TYPE_HYPERVISOR { desc.Add(jsonutils.NewString(disk.StorageId), "storage_id") localpath := disk.GetPathAtHost(host) if len(localpath) == 0 { desc.Add(jsonutils.JSONTrue, "migrating") - target := host.GetLeastUsedStorage(storage.StorageType) - desc.Add(jsonutils.NewString(target.Id), "target_storage_id") disk.SetStatus(nil, api.DISK_START_MIGRATE, "migration") } else { desc.Add(jsonutils.NewString(localpath), "path") diff --git a/pkg/compute/tasks/guest_live_migrate_task.go b/pkg/compute/tasks/guest_live_migrate_task.go index 23aadb71cc..7209046767 100644 --- a/pkg/compute/tasks/guest_live_migrate_task.go +++ b/pkg/compute/tasks/guest_live_migrate_task.go @@ -105,6 +105,17 @@ func (self *GuestMigrateTask) SaveScheduleResult(ctx context.Context, obj ISched isLocalStorage := utils.IsInStringArray(disk.GetStorage().StorageType, api.STORAGE_LOCAL_TYPES) if isLocalStorage { + targetStorages := jsonutils.NewArray() + for i := 0; i < len(disks); i++ { + var targetStroage string + if len(target.Disks[i].StorageIds) == 0 { + targetStroage = targetHost.GetLeastUsedStorage(disk.GetStorage().StorageType).Id + } else { + targetStroage = target.Disks[i].StorageIds[0] + } + targetStorages.Add(jsonutils.NewString(targetStroage)) + } + body.Set("target_storages", targetStorages) body.Set("is_local_storage", jsonutils.JSONTrue) } else { body.Set("is_local_storage", jsonutils.JSONFalse) @@ -309,19 +320,14 @@ func (self *GuestMigrateTask) localStorageMigrateConf(ctx context.Context, self.TaskFailed(ctx, guest, "Get disksDesc error") return nil, true } - targetStorageId, _ := disksDesc[0].GetString("target_storage_id") - if len(targetStorageId) == 0 { - self.TaskFailed(ctx, guest, "Get targetStorageId error") - return nil, true + targetStorages, _ := self.Params.GetArray("target_storages") + for i := 0; i < len(disks); i++ { + diskDesc := disksDesc[i].(*jsonutils.JSONDict) + diskDesc.Set("target_storage_id", targetStorages[i]) } - targetStorage := targetHost.GetHoststorageOfId(targetStorageId) - sourceStorage := sourceHost.GetHoststorageOfId(disks[0].GetDisk().StorageId) - if sourceStorage.MountPoint != targetStorage.MountPoint { - // rebase disks backing file - body.Set("rebase_disks", jsonutils.JSONTrue) - } body.Set("desc", targetDesc) + body.Set("rebase_disks", jsonutils.JSONTrue) body.Set("is_local_storage", jsonutils.JSONTrue) return body, false } @@ -363,20 +369,19 @@ func (self *GuestLiveMigrateTask) OnStartDestCompleteFailed(ctx context.Context, func (self *GuestMigrateTask) setGuest(ctx context.Context, guest *models.SGuest) error { targetHostId, _ := self.Params.GetString("target_host_id") if jsonutils.QueryBoolean(self.Params, "is_local_storage", false) { - targetHost := models.HostManager.FetchHostById(targetHostId) - targetStorage := targetHost.GetLeastUsedStorage(api.STORAGE_LOCAL) + targetStorages, _ := self.Params.GetArray("target_storages") guestDisks := guest.GetDisks() for i := 0; i < len(guestDisks); i++ { disk := guestDisks[i].GetDisk() db.Update(disk, func() error { disk.Status = api.DISK_READY - disk.StorageId = targetStorage.Id + disk.StorageId, _ = targetStorages[i].GetString() return nil }) snapshots := models.SnapshotManager.GetDiskSnapshots(disk.Id) for _, snapshot := range snapshots { db.Update(&snapshot, func() error { - snapshot.StorageId = targetStorage.Id + snapshot.StorageId, _ = targetStorages[i].GetString() return nil }) } diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 2b33bbf5b0..94bba8363d 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -331,11 +331,17 @@ func guestDestPrepareMigrate(ctx context.Context, sid string, body jsonutils.JSO if err != nil { return nil, httperrors.NewInputParameterError("Get desc disks error") } else { - targetStorageId, _ := disks[0].GetString("target_storage_id") - if len(targetStorageId) == 0 { - return nil, httperrors.NewMissingParameterError("target_storage_id") + targetStorageIds := []string{} + for i := 0; i < len(disks); i++ { + targetStorageId, _ := disks[i].GetString("target_storage_id") + if len(targetStorageId) == 0 { + return nil, httperrors.NewMissingParameterError("target_storage_id") + } + targetStorageIds = append(targetStorageIds, targetStorageId) + // params.TargetStorageId = targetStorageId + params.TargetStorageIds = targetStorageIds } - params.TargetStorageId = targetStorageId + } params.RebaseDisks = jsonutils.QueryBoolean(body, "rebase_disks", false) } diff --git a/pkg/hostman/guestman/guesthelper.go b/pkg/hostman/guestman/guesthelper.go index 61cc7d549c..7cd9344c51 100644 --- a/pkg/hostman/guestman/guesthelper.go +++ b/pkg/hostman/guestman/guesthelper.go @@ -38,14 +38,15 @@ type SSrcPrepareMigrate struct { } type SDestPrepareMigrate struct { - Sid string - ServerUrl string - QemuVersion string - SnapshotsUri string - DisksUri string - TargetStorageId string - LiveMigrate bool - RebaseDisks bool + Sid string + ServerUrl string + QemuVersion string + SnapshotsUri string + DisksUri string + // TargetStorageId string + TargetStorageIds []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 61db71f8a5..af4fa6610d 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -598,23 +598,27 @@ func (m *SGuestManager) DestPrepareMigrate(ctx context.Context, params interface return nil, err } - if len(migParams.TargetStorageId) > 0 { - iStorage := storageman.GetManager().GetStorage(migParams.TargetStorageId) - if iStorage == nil { - return nil, fmt.Errorf("Target storage %s not found", migParams.TargetStorageId) - } + disks, _ := migParams.Desc.GetArray("disks") + if len(migParams.TargetStorageIds) > 0 { + for i := 0; i < len(migParams.TargetStorageIds); i++ { + iStorage := storageman.GetManager().GetStorage(migParams.TargetStorageIds[i]) + if iStorage == nil { + return nil, fmt.Errorf("Target storage %s not found", migParams.TargetStorageIds[i]) + } - err := iStorage.DestinationPrepareMigrate( - ctx, migParams.LiveMigrate, migParams.DisksUri, migParams.SnapshotsUri, - migParams.Desc, migParams.DisksBackingFile, migParams.SrcSnapshots, migParams.RebaseDisks) - if err != nil { - return nil, fmt.Errorf("dest prepare migrate failed %s", err) + err := iStorage.DestinationPrepareMigrate( + ctx, migParams.LiveMigrate, migParams.DisksUri, migParams.SnapshotsUri, + migParams.DisksBackingFile, migParams.SrcSnapshots, migParams.RebaseDisks, disks[i], + ) + if err != nil { + return nil, fmt.Errorf("dest prepare migrate failed %s", err) + } } - - if err = guest.SaveDesc(migParams.Desc); err != nil { + if err := guest.SaveDesc(migParams.Desc); err != nil { log.Errorln(err) return nil, err } + } if migParams.LiveMigrate { diff --git a/pkg/hostman/storageman/storage_base.go b/pkg/hostman/storageman/storage_base.go index fd546283e2..b40d4f8874 100644 --- a/pkg/hostman/storageman/storage_base.go +++ b/pkg/hostman/storageman/storage_base.go @@ -120,7 +120,7 @@ type IStorage interface { GetImgsaveBackupPath() string DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, - desc, disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool) error + disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool, diskDesc jsonutils.JSONObject) error Accessible() error } @@ -312,7 +312,7 @@ func (s *SBaseStorage) CreateDiskFromSnpashot(ctx context.Context, disk IDisk, c func (s *SBaseStorage) DestinationPrepareMigrate( ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, - desc, disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool, + disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool, diskinfo jsonutils.JSONObject, ) error { return nil } diff --git a/pkg/hostman/storageman/storage_local.go b/pkg/hostman/storageman/storage_local.go index b65208f899..ec7c5d0592 100644 --- a/pkg/hostman/storageman/storage_local.go +++ b/pkg/hostman/storageman/storage_local.go @@ -342,86 +342,83 @@ func (s *SLocalStorage) DeleteSnapshots(ctx context.Context, params interface{}) 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 ( - diskId, _ = diskinfo.GetString("disk_id") - snapshots, _ = srcSnapshots.GetArray(diskId) - disk = s.CreateDisk(diskId) - ) + disksBackingFile, srcSnapshots jsonutils.JSONObject, rebaseDisks bool, diskinfo jsonutils.JSONObject) error { + var ( + diskId, _ = diskinfo.GetString("disk_id") + snapshots, _ = srcSnapshots.GetArray(diskId) + disk = s.CreateDisk(diskId) + ) - if disk == nil { - return fmt.Errorf( - "Storage %s create disk %s failed", s.GetId(), diskId) - } + if disk == nil { + return fmt.Errorf( + "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()).Output() - if err != nil { - return err - } + templateId, _ := diskinfo.GetString("template_id") + // prepare disk snapshot dir + if len(snapshots) > 0 && !fileutils2.Exists(disk.GetSnapshotDir()) { + _, err := procutils.NewCommand("mkdir", "-p", disk.GetSnapshotDir()).Output() + if err != nil { + return err } + } - // create snapshots form remote url - 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) - 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 - } - } + // create snapshots form remote url + 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) + if err := s.CreateSnapshotFormUrl(ctx, snapshotUrl, diskId, snapshotPath); err != nil { + return errors.Wrap(err, "create from snapshot url failed") } - - if liveMigrate { - // create local disk - backingFile, _ := disksBackingFile.GetString(diskId) - size, _ := diskinfo.Int("size") - _, err := disk.CreateRaw(ctx, int(size), "qcow2", "", false, "", backingFile) - if err != nil { - log.Errorln(err) - return err - } - } else { - // download disk form remote url - diskUrl := fmt.Sprintf("%s/%s/%s", disksUri, diskStorageId, diskId) - if err := disk.CreateFromUrl(ctx, diskUrl, 0); err != nil { - log.Errorln(err) - return err - } - } - if rebaseDisks && len(templateId) > 0 && len(baseImagePath) == 0 { + if i == 0 && len(templateId) > 0 { templatePath := path.Join(storageManager.LocalStorageImagecacheManager.GetPath(), templateId) - if err := doRebaseDisk(disk.GetPath(), templatePath); err != nil { + if err := doRebaseDisk(snapshotPath, templatePath); err != nil { return err } } else if rebaseDisks && len(baseImagePath) > 0 { - if err := doRebaseDisk(disk.GetPath(), baseImagePath); err != nil { + if err := doRebaseDisk(snapshotPath, baseImagePath); err != nil { return err } } - diskDesc, _ := disks[i].(*jsonutils.JSONDict) - diskDesc.Set("path", jsonutils.NewString(disk.GetPath())) + baseImagePath = snapshotPath } + + if liveMigrate { + // create local disk + backingFile, _ := disksBackingFile.GetString(diskId) + size, _ := diskinfo.Int("size") + _, err := disk.CreateRaw(ctx, int(size), "qcow2", "", false, "", backingFile) + if err != nil { + log.Errorln(err) + return err + } + } else { + // download disk form remote url + diskUrl := fmt.Sprintf("%s/%s/%s", disksUri, diskStorageId, diskId) + if err := disk.CreateFromUrl(ctx, diskUrl, 0); err != nil { + log.Errorln(err) + 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, _ := diskinfo.(*jsonutils.JSONDict) + diskDesc.Set("path", jsonutils.NewString(disk.GetPath())) return nil }