diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index fe04acab1b..bae8e02bc3 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -842,10 +842,11 @@ type ServerChangeDiskStorageInput struct { type ServerChangeDiskStorageInternalInput struct { ServerChangeDiskStorageInput - StorageId string `json:"storage_id"` - TargetDiskId string `json:"target_disk_id"` - DiskFormat string `json:"disk_format"` - GuestRunning bool `josn:"guest_running"` + StorageId string `json:"storage_id"` + TargetDiskId string `json:"target_disk_id"` + DiskFormat string `json:"disk_format"` + GuestRunning bool `josn:"guest_running"` + TargetDiskDesc *GuestdiskJsonDesc `json:"target_disk_desc"` } type ServerSetExtraOptionInput struct { diff --git a/pkg/compute/models/guestdisks.go b/pkg/compute/models/guestdisks.go index 95d8239b14..43b7256de2 100644 --- a/pkg/compute/models/guestdisks.go +++ b/pkg/compute/models/guestdisks.go @@ -175,8 +175,12 @@ func (self *SGuestdisk) GetDisk() *SDisk { func (self *SGuestdisk) GetJsonDescAtHost(ctx context.Context, host *SHost) *api.GuestdiskJsonDesc { disk := self.GetDisk() + return self.GetDiskJsonDescAtHost(ctx, host, disk) +} + +func (self *SGuestdisk) GetDiskJsonDescAtHost(ctx context.Context, host *SHost, disk *SDisk) *api.GuestdiskJsonDesc { desc := &api.GuestdiskJsonDesc{ - DiskId: self.DiskId, + DiskId: disk.Id, Driver: self.Driver, CacheMode: self.CacheMode, AioMode: self.AioMode, @@ -185,9 +189,9 @@ func (self *SGuestdisk) GetJsonDescAtHost(ctx context.Context, host *SHost) *api Size: disk.DiskSize, } desc.TemplateId = disk.GetTemplateId() + storage, _ := disk.GetStorage() + desc.StorageType = storage.StorageType if len(desc.TemplateId) > 0 { - storage, _ := disk.GetStorage() - desc.StorageType = storage.StorageType storagecacheimg := StoragecachedimageManager.GetStoragecachedimage(storage.StoragecacheId, desc.TemplateId) if storagecacheimg != nil { desc.ImagePath = storagecacheimg.Path diff --git a/pkg/compute/tasks/guest_change_disk_storage_task.go b/pkg/compute/tasks/guest_change_disk_storage_task.go index 68aab82c50..2de1aa9193 100644 --- a/pkg/compute/tasks/guest_change_disk_storage_task.go +++ b/pkg/compute/tasks/guest_change_disk_storage_task.go @@ -118,6 +118,26 @@ func (t *GuestChangeDiskStorageTask) OnDiskLiveChangeStorageReady( ) { if !jsonutils.QueryBoolean(data, "block_jobs_ready", false) { log.Infof("OnDiskLiveChangeStorageReady block jobs not ready") + resp := new(hostapi.ServerCloneDiskFromStorageResponse) + if err := data.Unmarshal(resp); err != nil { + t.TaskFailed(ctx, guest, + jsonutils.NewString(fmt.Sprintf("unmarshal OnDiskLiveChangeStorageReady resp failed %s", err)), + ) + return + } + targetDisk, err := t.GetTargetDisk() + if err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed get target disk %s", err))) + return + } + if _, err := db.UpdateWithLock(ctx, targetDisk, func() error { + targetDisk.AccessPath = resp.TargetAccessPath + targetDisk.DiskFormat = resp.TargetFormat + return nil + }); err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update target disk attributes error: %v", err))) + return + } return } @@ -126,6 +146,22 @@ func (t *GuestChangeDiskStorageTask) OnDiskLiveChangeStorageReady( t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("GetInputParams error: %v", err))) return } + guestdisk := guest.GetGuestDisk(input.DiskId) + if guestdisk == nil { + t.TaskFailed(ctx, guest, jsonutils.NewString("failed get guest disk")) + return + } + host, err := guest.GetHost() + if err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed get host %s", err))) + return + } + targetDisk, err := t.GetTargetDisk() + if err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed get target disk %s", err))) + return + } + input.TargetDiskDesc = guestdisk.GetDiskJsonDescAtHost(ctx, host, targetDisk) t.SetStage("OnDiskChangeStorageComplete", nil) // block job ready, start switch to target storage disk @@ -157,29 +193,36 @@ func (t *GuestChangeDiskStorageTask) OnDiskChangeStorageComplete(ctx context.Con return } - // update target disk attributes by response - resp := new(hostapi.ServerCloneDiskFromStorageResponse) - if err := data.Unmarshal(resp); err != nil { - t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Unmarshal response: %v", err))) - return - } - - if len(resp.TargetFormat) == 0 { - resp.TargetFormat = srcDisk.DiskFormat - } - - targetDisk, err := t.GetTargetDisk() + input, err := t.GetInputParams() if err != nil { - t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("GetTargetDisk error: %v", err))) + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("GetInputParams error: %v", err))) return } - if _, err := db.UpdateWithLock(ctx, targetDisk, func() error { - targetDisk.AccessPath = resp.TargetAccessPath - targetDisk.DiskFormat = resp.TargetFormat - return nil - }); err != nil { - t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update target disk attributes error: %v", err))) - return + + if !input.GuestRunning { + resp := new(hostapi.ServerCloneDiskFromStorageResponse) + err = data.Unmarshal(resp) + if err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Unmarshal response: %v", err))) + return + } + if len(resp.TargetFormat) == 0 { + resp.TargetFormat = srcDisk.DiskFormat + } + + targetDisk, err := t.GetTargetDisk() + if err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("GetTargetDisk error: %v", err))) + return + } + if _, err := db.UpdateWithLock(ctx, targetDisk, func() error { + targetDisk.AccessPath = resp.TargetAccessPath + targetDisk.DiskFormat = resp.TargetFormat + return nil + }); err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update target disk attributes error: %v", err))) + return + } } guestSrcDisk := guest.GetGuestDisk(srcDisk.GetId()) @@ -248,9 +291,20 @@ func (t *GuestChangeDiskStorageTask) attachTargetDisk(ctx context.Context, guest } func (t *GuestChangeDiskStorageTask) OnTargetDiskAttachComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + t.SetStage("OnGuestSyncStatus", nil) + if err := guest.StartSyncstatus(ctx, t.UserCred, t.Id); err != nil { + t.TaskFailed(ctx, guest, jsonutils.NewString(err.Error())) + } +} + +func (t *GuestChangeDiskStorageTask) OnGuestSyncStatus(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { t.TaskComplete(ctx, guest, nil) } +func (t *GuestChangeDiskStorageTask) OnGuestSyncStatusFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + t.TaskFailed(ctx, guest, data) +} + func (t *GuestChangeDiskStorageTask) OnTargetDiskAttachCompleteFailed(ctx context.Context, guest *models.SGuest, err jsonutils.JSONObject) { t.TaskFailed(ctx, guest, err) } diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 2ad2ca8402..980fcbddfe 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -389,7 +389,7 @@ func guestDestPrepareMigrateInternal(ctx context.Context, userCred mcclient.Toke params.DisksBackingFile = disksBack } disks := guestDesc.Disks - if err != nil { + if disks == nil { return httperrors.NewInputParameterError("Get desc disks error") } else { targetStorageIds := []string{} @@ -666,12 +666,13 @@ func formatCloneDiskParams(sid string, body jsonutils.JSONObject) (*guestman.SSt } params := &guestman.SStorageCloneDisk{ - ServerId: sid, - SourceStorage: srcStorage, - SourceDisk: srcDisk, - TargetStorage: targetStorage, - TargetDiskId: input.TargetDiskId, - DiskFormat: input.DiskFormat, + ServerId: sid, + SourceStorage: srcStorage, + SourceDisk: srcDisk, + TargetStorage: targetStorage, + TargetDiskId: input.TargetDiskId, + DiskFormat: input.DiskFormat, + TargetDiskDesc: input.TargetDiskDesc, } return params, nil } diff --git a/pkg/hostman/guestman/guestman.go b/pkg/hostman/guestman/guestman.go index af2c00d663..21df39ce07 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -1278,12 +1278,13 @@ func (m *SGuestManager) ExitGuestCleanup() { } type SStorageCloneDisk struct { - ServerId string - SourceStorage storageman.IStorage - SourceDisk storageman.IDisk - TargetStorage storageman.IStorage - TargetDiskId string - DiskFormat string + ServerId string + SourceStorage storageman.IStorage + SourceDisk storageman.IDisk + TargetStorage storageman.IStorage + TargetDiskId string + DiskFormat string + TargetDiskDesc *compute.GuestdiskJsonDesc } func (m *SGuestManager) StorageCloneDisk(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { diff --git a/pkg/hostman/guestman/guesttasks.go b/pkg/hostman/guestman/guesttasks.go index b0be1e9e25..d118f13eb4 100644 --- a/pkg/hostman/guestman/guesttasks.go +++ b/pkg/hostman/guestman/guesttasks.go @@ -2359,6 +2359,7 @@ func (t *SGuestStorageCloneDiskTask) Start(guestRunning bool) { disks := t.Desc.Disks for diskIndex = 0; diskIndex < len(disks); diskIndex++ { if disks[diskIndex].DiskId == t.params.SourceDisk.GetId() { + diskIndex = int(disks[diskIndex].Index) break } } @@ -2444,6 +2445,7 @@ func NewGuestLiveChangeDiskTask(ctx context.Context, guest *SKVMGuestInstance, p disks := guest.Desc.Disks for diskIndex = 0; diskIndex < len(disks); diskIndex++ { if disks[diskIndex].DiskId == params.SourceDisk.GetId() { + diskIndex = int(disks[diskIndex].Index) break } } @@ -2495,6 +2497,16 @@ func (t *SGuestLiveChangeDisk) onReopenImageSuccess(res string) { hostutils.TaskFailed(t.ctx, fmt.Sprintf("reopen image failed: %s", res)) return } + if t.params.TargetDiskDesc != nil { + for i := 0; i < len(t.Desc.Disks); i++ { + if t.Desc.Disks[i].Index == int8(t.diskIndex) { + log.Debugf("update guest disk %s desc", t.Desc.Disks[i].DiskId) + t.Desc.Disks[i].GuestdiskJsonDesc = *t.params.TargetDiskDesc + t.SaveLiveDesc(t.Desc) + break + } + } + } resp := &hostapi.ServerCloneDiskFromStorageResponse{ TargetAccessPath: t.targetDisk.GetPath(),