From 89574e954a32a0e02e974b823440aeef4c2f3c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Sat, 10 Nov 2018 11:24:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=82=E8=BD=BD=E7=A3=81=E7=9B=98=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=97=B6=E8=87=AA=E5=8A=A8=E8=A7=A3=E9=99=A4=E4=B8=8E?= =?UTF-8?q?=E8=99=9A=E6=9C=BA=E7=9A=84=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/guestdrivers/aliyun.go | 4 + pkg/compute/guestdrivers/baremetals.go | 4 + pkg/compute/guestdrivers/base.go | 9 +++ pkg/compute/guestdrivers/esxi.go | 4 + pkg/compute/guestdrivers/kvm.go | 8 ++ pkg/compute/guestdrivers/managedvirtual.go | 8 ++ pkg/compute/guestdrivers/virtualization.go | 9 +++ pkg/compute/models/disks.go | 1 + pkg/compute/models/guestdrivers.go | 3 + pkg/compute/models/guests.go | 59 ++++++++------ pkg/compute/tasks/guest_attach_disk_task.go | 89 +++++++++++++++++++++ pkg/compute/tasks/guest_detach_disk_task.go | 1 + pkg/compute/tasks/guest_sync_task.go | 2 + 13 files changed, 177 insertions(+), 24 deletions(-) create mode 100644 pkg/compute/tasks/guest_attach_disk_task.go diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index f68fa45796..cab128d8df 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -53,6 +53,10 @@ func (self *SAliyunGuestDriver) GetDetachDiskStatus() ([]string, error) { return []string{models.VM_READY, models.VM_RUNNING}, nil } +func (self *SAliyunGuestDriver) GetAttachDiskStatus() ([]string, error) { + return []string{models.VM_READY, models.VM_RUNNING}, nil +} + func (self *SAliyunGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) } diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index d12ebc0716..0289004d7b 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -170,6 +170,10 @@ func (self *SBaremetalGuestDriver) StartGuestDetachdiskTask(ctx context.Context, return fmt.Errorf("Cannot detach disk from a baremetal serer") } +func (self *SBaremetalGuestDriver) StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { + return fmt.Errorf("Cannot attach disk from a baremetal serer") +} + func (self *SBaremetalGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { return fmt.Errorf("Cannot suspend a baremetal serer") } diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index a63aa1470c..9a20a16aaf 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -86,6 +86,11 @@ func (self *SBaseGuestDriver) RequestDetachDisk(ctx context.Context, guest *mode return nil } +func (self *SBaseGuestDriver) RequestAttachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + task.ScheduleRun(nil) + return nil +} + func (self *SBaseGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { return fmt.Errorf("Not Implement") } @@ -94,6 +99,10 @@ func (self *SBaseGuestDriver) GetDetachDiskStatus() ([]string, error) { return []string{}, fmt.Errorf("This Guest driver dose not implement GetDetachDiskStatus") } +func (self *SBaseGuestDriver) GetAttachDiskStatus() ([]string, error) { + return []string{}, fmt.Errorf("This Guest driver dose not implement GetAttachDiskStatus") +} + func (self *SBaseGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error { return fmt.Errorf("Not Implement") } diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index f1ab950f82..7d06890ba5 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -29,6 +29,10 @@ func (self *SESXiGuestDriver) GetDetachDiskStatus() ([]string, error) { return []string{models.VM_READY}, nil } +func (self *SESXiGuestDriver) GetAttachDiskStatus() ([]string, error) { + return []string{models.VM_READY}, nil +} + func (self *SESXiGuestDriver) CanKeepDetachDisk() bool { return false } diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 97f808492f..f552b5758e 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -214,10 +214,18 @@ func (self *SKVMGuestDriver) RequestDetachDisk(ctx context.Context, guest *model return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) } +func (self *SKVMGuestDriver) RequestAttachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) +} + func (self *SKVMGuestDriver) GetDetachDiskStatus() ([]string, error) { return []string{models.VM_READY, models.VM_RUNNING}, nil } +func (self *SKVMGuestDriver) GetAttachDiskStatus() ([]string, error) { + return []string{models.VM_READY, models.VM_RUNNING}, nil +} + func (self *SKVMGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error { return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge) } diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 7d0df18dfa..5daf4d2496 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -103,6 +103,14 @@ func (self *SManagedVirtualizedGuestDriver) RequestGuestCreateAllDisks(ctx conte return storageCache.StartImageCacheTask(ctx, task.GetUserCred(), imageId, false, task.GetTaskId()) } +func (self *SManagedVirtualizedGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) +} + +func (self *SManagedVirtualizedGuestDriver) RequestAttachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) +} + func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { return nil } diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index d9e8daa68f..51088a14c5 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -186,6 +186,15 @@ func (self *SVirtualizedGuestDriver) StartGuestDetachdiskTask(ctx context.Contex return nil } +func (self *SVirtualizedGuestDriver) StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "GuestAttachDiskTask", guest, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + func (self *SVirtualizedGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { task, err := taskman.TaskManager.NewTask(ctx, "GuestSuspendTask", guest, userCred, params, parentTaskId, "", nil) if err != nil { diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index d3108001ce..d09be47d8c 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -42,6 +42,7 @@ const ( DISK_DEALLOC_FAILED = "dealloc_failed" DISK_UNKNOWN = "unknown" DISK_DETACHING = "detaching" + DISK_ATTACHING = "attaching" DISK_START_SAVE = "start_save" DISK_SAVING = "saving" diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 4d841ddae7..2e68cb1a20 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -77,12 +77,15 @@ type IGuestDriver interface { GetGuestVncInfo(userCred mcclient.TokenCredential, guest *SGuest, host *SHost) (*jsonutils.JSONDict, error) + RequestAttachDisk(ctx context.Context, guest *SGuest, task taskman.ITask) error RequestDetachDisk(ctx context.Context, guest *SGuest, task taskman.ITask) error GetDetachDiskStatus() ([]string, error) + GetAttachDiskStatus() ([]string, error) CanKeepDetachDisk() bool RequestDeleteDetachedDisk(ctx context.Context, disk *SDisk, task taskman.ITask, isPurge bool) error StartGuestDetachdiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error + StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error RqeuestSuspendOnHost(ctx context.Context, guest *SGuest, task taskman.ITask) error diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 79f8c3f915..a3a6f987f6 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -62,6 +62,9 @@ const ( VM_STOPPING = "stopping" VM_STOP_FAILED = "stop_fail" // # = running + VM_ATTACH_DISK_FAILED = "attach_disk_fail" + VM_DETACH_DISK_FAILED = "detach_disk_fail" + VM_START_SUSPEND = "start_suspend" VM_SUSPENDING = "suspending" VM_SUSPEND = "suspend" @@ -1821,44 +1824,52 @@ func (self *SGuest) ValidateAttachDisk(ctx context.Context, disk *SDisk) error { host := self.GetHost() if provider.Id != host.ManagerId { return httperrors.NewInputParameterError("Disk %s and guest not belong to the same account", disk.Name) - } else if storage.ZoneId != host.ZoneId { + } + if storage.ZoneId != host.ZoneId { return httperrors.NewInputParameterError("Disk %s and guest not belong to the same zone", disk.Name) } - return nil } if disk.isAttached() { return httperrors.NewInputParameterError("Disk %s has been attached", disk.Name) - } else if len(disk.GetPathAtHost(self.GetHost())) == 0 { + } + if len(disk.GetPathAtHost(self.GetHost())) == 0 { return httperrors.NewInputParameterError("Disk %s not belong the guest's host", disk.Name) - } else if disk.Status != DISK_READY { + } + if disk.Status != DISK_READY { return httperrors.NewInputParameterError("Disk in %s not able to attach", disk.Status) - } else if !utils.IsInStringArray(self.Status, []string{VM_RUNNING, VM_READY}) { - return httperrors.NewInputParameterError("Server in %s not able to attach disk", self.Status) + } + guestStatus, err := self.GetDriver().GetAttachDiskStatus() + if err != nil { + return err + } + if !utils.IsInStringArray(self.Status, guestStatus) { + return httperrors.NewInputParameterError("Guest %s not support attach disk in status %s", self.Name, self.Status) } return nil } func (self *SGuest) PerformAttachdisk(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if diskId, err := data.GetString("disk_id"); err != nil { + diskId, err := data.GetString("disk_id") + if err != nil { + return nil, err + } + disk, err := DiskManager.FetchByIdOrName(userCred.GetProjectId(), diskId) + if err != nil { + return nil, err + } + if disk == nil { + return nil, httperrors.NewResourceNotFoundError("Disk %s not found", diskId) + } + if err := self.ValidateAttachDisk(ctx, disk.(*SDisk)); err != nil { + return nil, err + } + + taskData := data.(*jsonutils.JSONDict) + taskData.Set("disk_id", jsonutils.NewString(disk.GetId())) + + if err := self.GetDriver().StartGuestAttachDiskTask(ctx, userCred, self, taskData, ""); err != nil { return nil, err - } else { - if disk, err := DiskManager.FetchByIdOrName(userCred.GetProjectId(), diskId); err != nil { - return nil, err - } else if disk == nil { - return nil, httperrors.NewResourceNotFoundError("Disk %s not found", diskId) - } else if err := self.ValidateAttachDisk(ctx, disk.(*SDisk)); err != nil { - return nil, err - } else { - driver, _ := data.GetString("driver") - cache, _ := data.GetString("cache") - mountpoint, _ := data.GetString("mountpoint") - if err := self.attach2Disk(disk.(*SDisk), userCred, driver, cache, mountpoint); err != nil { - return nil, err - } else { - self.StartSyncTask(ctx, userCred, false, "") - } - } } return nil, nil } diff --git a/pkg/compute/tasks/guest_attach_disk_task.go b/pkg/compute/tasks/guest_attach_disk_task.go new file mode 100644 index 0000000000..e1f182866f --- /dev/null +++ b/pkg/compute/tasks/guest_attach_disk_task.go @@ -0,0 +1,89 @@ +package tasks + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type GuestAttachDiskTask struct { + SGuestBaseTask +} + +func init() { + taskman.RegisterTask(GuestAttachDiskTask{}) +} + +func (self *GuestAttachDiskTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + diskId, _ := self.Params.GetString("disk_id") + objDisk, err := models.DiskManager.FetchById(diskId) + if err != nil { + self.OnTaskFail(ctx, guest, nil, err) + return + } + disk := objDisk.(*models.SDisk) + if disk == nil { + self.OnTaskFail(ctx, guest, nil, fmt.Errorf("Connot find disk %s", diskId)) + return + } + + driver, _ := self.Params.GetString("driver") + cache, _ := self.Params.GetString("cache") + mountpoint, _ := self.Params.GetString("mountpoint") + + err = guest.AttachDisk(disk, self.UserCred, driver, cache, mountpoint) + if err != nil { + self.OnTaskFail(ctx, guest, nil, err) + return + } + disk.SetStatus(self.UserCred, models.DISK_ATTACHING, "Disk attach") + self.SetStage("on_sync_config_complete", nil) + guest.GetDriver().RequestAttachDisk(ctx, guest, self) +} + +func (self *GuestAttachDiskTask) OnSyncConfigComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + diskId, _ := self.Params.GetString("disk_id") + objDisk, err := models.DiskManager.FetchById(diskId) + if err != nil { + self.OnTaskFail(ctx, guest, nil, err) + return + } + disk := objDisk.(*models.SDisk) + if disk == nil { + self.OnTaskFail(ctx, guest, nil, fmt.Errorf("Connot find disk %s", diskId)) + return + } + disk.SetStatus(self.UserCred, models.DISK_READY, "") + self.SetStageComplete(ctx, nil) +} + +func (self *GuestAttachDiskTask) OnSyncConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, resion jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + diskId, _ := self.Params.GetString("disk_id") + objDisk, err := models.DiskManager.FetchById(diskId) + if err != nil { + self.OnTaskFail(ctx, guest, nil, err) + return + } + disk := objDisk.(*models.SDisk) + db.OpsLog.LogEvent(disk, db.ACT_ATTACH, resion.String(), self.UserCred) + disk.SetStatus(self.UserCred, models.DISK_READY, "") + guest.DetachDisk(ctx, disk, self.UserCred) + self.OnTaskFail(ctx, guest, disk, fmt.Errorf(resion.String())) +} + +func (self *GuestAttachDiskTask) OnTaskFail(ctx context.Context, guest *models.SGuest, disk *models.SDisk, err error) { + if disk != nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") + } + guest.SetStatus(self.UserCred, models.VM_ATTACH_DISK_FAILED, err.Error()) + self.SetStageFailed(ctx, err.Error()) + log.Errorf("Guest %s GuestAttachDiskTask failed %s", guest.Name, err.Error()) +} diff --git a/pkg/compute/tasks/guest_detach_disk_task.go b/pkg/compute/tasks/guest_detach_disk_task.go index abbe01ea0e..8b976b0444 100644 --- a/pkg/compute/tasks/guest_detach_disk_task.go +++ b/pkg/compute/tasks/guest_detach_disk_task.go @@ -131,6 +131,7 @@ func (self *GuestDetachDiskTask) OnTaskFail(ctx context.Context, guest *models.S if disk != nil { disk.SetDiskReady(ctx, self.UserCred, "") } + guest.SetStatus(self.UserCred, models.VM_DETACH_DISK_FAILED, err.Error()) self.SetStageFailed(ctx, err.Error()) log.Errorf("Guest %s GuestDetachDiskTask failed %s", guest.Id, err.Error()) } diff --git a/pkg/compute/tasks/guest_sync_task.go b/pkg/compute/tasks/guest_sync_task.go index 1daeb9e058..ec41d19d54 100644 --- a/pkg/compute/tasks/guest_sync_task.go +++ b/pkg/compute/tasks/guest_sync_task.go @@ -55,6 +55,7 @@ func (self *GuestSyncConfTask) OnDiskSyncCompleteFailed(ctx context.Context, obj guest := obj.(*models.SGuest) db.OpsLog.LogEvent(guest, db.ACT_SYNC_CONF_FAIL, data.String(), self.UserCred) log.Errorf("Guest sync config failed: %v", data.String()) + self.SetStageFailed(ctx, data.String()) } func (self *GuestSyncConfTask) OnSyncCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -62,6 +63,7 @@ func (self *GuestSyncConfTask) OnSyncCompleteFailed(ctx context.Context, obj db. guest.SetStatus(self.GetUserCred(), models.VM_SYNC_FAIL, data.String()) log.Errorf("Guest sync config failed: %v", data.String()) db.OpsLog.LogEvent(guest, db.ACT_SYNC_CONF_FAIL, data.String(), self.UserCred) + self.SetStageFailed(ctx, data.String()) } func (self *GuestSyncConfTask) OnSyncStatusComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {