Merge pull request #453 in YUNIONIO/onecloud from ~QUXUAN/onecloud:hotfix/qx-guest-attach-disk to release/2.1.0

* commit '89574e954a32a0e02e974b823440aeef4c2f3c18':
  挂载磁盘失败时自动解除与虚机的关系
This commit is contained in:
邱剑
2018-11-10 14:31:11 +08:00
13 changed files with 177 additions and 24 deletions
+4
View File
@@ -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())
}
+4
View File
@@ -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")
}
+9
View File
@@ -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")
}
+4
View File
@@ -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
}
+8
View File
@@ -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)
}
@@ -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
}
@@ -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 {
+1
View File
@@ -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"
+3
View File
@@ -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
+35 -24
View File
@@ -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
}
@@ -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())
}
@@ -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())
}
+2
View File
@@ -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) {