From 668c8bd921917027c26c272a11d0677c26ce7550 Mon Sep 17 00:00:00 2001 From: ioito Date: Tue, 2 Jul 2019 14:57:47 +0800 Subject: [PATCH] fix not set guest status after attach or detach disk --- pkg/apis/compute/guest_const.go | 2 + pkg/cloudprovider/waitstatus.go | 15 ++++++ pkg/compute/guestdrivers/managedvirtual.go | 53 +++++++++++++++++++++ pkg/compute/models/guest_actions.go | 3 ++ pkg/compute/tasks/guest_attach_disk_task.go | 2 +- pkg/compute/tasks/guest_detach_disk_task.go | 33 +++++++------ pkg/util/openstack/shell/instance.go | 8 ++++ 7 files changed, 101 insertions(+), 15 deletions(-) diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index a4aed0b52e..a995c29265 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -38,6 +38,8 @@ const ( VM_STOP_FAILED = "stop_fail" // # = running VM_RENEWING = "renewing" VM_RENEW_FAILED = "renew_failed" + VM_ATTACH_DISK = "attach_disk" + VM_DETACH_DISK = "detach_disk" VM_BACKUP_STARTING = "backup_starting" VM_BACKUP_CREATING = "backup_creating" diff --git a/pkg/cloudprovider/waitstatus.go b/pkg/cloudprovider/waitstatus.go index f1ed001737..e098173954 100644 --- a/pkg/cloudprovider/waitstatus.go +++ b/pkg/cloudprovider/waitstatus.go @@ -77,6 +77,21 @@ func WaitDeleted(res ICloudResource, interval time.Duration, timeout time.Durati return ErrTimeout } +func Wait(interval time.Duration, timeout time.Duration, callback func() (bool, error)) error { + startTime := time.Now() + for time.Now().Sub(startTime) < timeout { + ok, err := callback() + if err != nil { + return err + } + if ok { + return nil + } + time.Sleep(interval) + } + return ErrTimeout +} + func WaitCreated(interval time.Duration, timeout time.Duration, callback func() bool) error { startTime := time.Now() for time.Now().Sub(startTime) < timeout { diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 51330d2fa3..1e449adb6a 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -161,6 +161,34 @@ func (self *SManagedVirtualizedGuestDriver) RequestDetachDisk(ctx context.Contex if err != nil { return nil, errors.Wrapf(err, "iVM.DetachDisk") } + + err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { + err := iVM.Refresh() + if err != nil { + return false, errors.Wrapf(err, "iVM.Refresh") + } + iDisks, err := iVM.GetIDisks() + if err != nil { + return false, errors.Wrapf(err, "RequestDetachDisk.iVM.GetIDisks") + } + + exist := false + for i := 0; i < len(iDisks); i++ { + if iDisks[i].GetGlobalId() == disk.ExternalId { + exist = true + } + } + + if !exist { + return true, nil + } + return false, nil + }) + + if err != nil { + return nil, errors.Wrapf(err, "RequestDetachDisk.Wait") + } + return nil, nil }) return nil @@ -179,6 +207,31 @@ func (self *SManagedVirtualizedGuestDriver) RequestAttachDisk(ctx context.Contex if err != nil { return nil, errors.Wrapf(err, "iVM.AttachDisk") } + + err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { + err := iVM.Refresh() + if err != nil { + return false, errors.Wrapf(err, "iVM.Refresh") + } + + iDisks, err := iVM.GetIDisks() + if err != nil { + return false, errors.Wrapf(err, "RequestAttachDisk.iVM.GetIDisks") + } + + for i := 0; i < len(iDisks); i++ { + if iDisks[i].GetGlobalId() == disk.ExternalId { + return true, nil + } + } + + return false, nil + }) + + if err != nil { + return nil, errors.Wrapf(err, "RequestAttachDisk.Wait") + } + return nil, nil }) return nil diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index c2bd05de33..e4524f2069 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -582,6 +582,8 @@ func (self *SGuest) PerformAttachdisk(ctx context.Context, userCred mcclient.Tok taskData := data.(*jsonutils.JSONDict) taskData.Set("disk_id", jsonutils.NewString(disk.GetId())) + self.SetStatus(userCred, api.VM_ATTACH_DISK, "") + if err := self.GetDriver().StartGuestAttachDiskTask(ctx, userCred, self, taskData, ""); err != nil { return nil, err } @@ -1422,6 +1424,7 @@ func (self *SGuest) PerformDetachdisk(ctx context.Context, userCred mcclient.Tok return nil, httperrors.NewInputParameterError("Cannot keep detached disk") } if utils.IsInStringArray(self.Status, detachDiskStatus) { + self.SetStatus(userCred, api.VM_DETACH_DISK, "") err = self.StartGuestDetachdiskTask(ctx, userCred, disk, keepDisk, "") return nil, err } else { diff --git a/pkg/compute/tasks/guest_attach_disk_task.go b/pkg/compute/tasks/guest_attach_disk_task.go index 88a8481a50..847ae02835 100644 --- a/pkg/compute/tasks/guest_attach_disk_task.go +++ b/pkg/compute/tasks/guest_attach_disk_task.go @@ -76,7 +76,7 @@ func (self *GuestAttachDiskTask) OnSyncConfigComplete(ctx context.Context, guest self.OnTaskFail(ctx, guest, nil, fmt.Errorf("Connot find disk %s", diskId)) return } - disk.SetStatus(self.UserCred, api.DISK_READY, "") + disk.SetDiskReady(ctx, self.UserCred, "") self.SetStageComplete(ctx, nil) logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_ATTACH_DISK, nil, self.UserCred, true) } diff --git a/pkg/compute/tasks/guest_detach_disk_task.go b/pkg/compute/tasks/guest_detach_disk_task.go index e4063e039a..41f7f5272b 100644 --- a/pkg/compute/tasks/guest_detach_disk_task.go +++ b/pkg/compute/tasks/guest_detach_disk_task.go @@ -22,7 +22,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -67,20 +66,16 @@ func (self *GuestDetachDiskTask) OnInit(ctx context.Context, obj db.IStandaloneM if host != nil && host.Status == api.HOST_DISABLED && jsonutils.QueryBoolean(self.Params, "purge", false) { purge = true } - detachStatus, err := guest.GetDriver().GetDetachDiskStatus() - if err != nil { - self.OnTaskFail(ctx, guest, disk, err) - return - } - if utils.IsInStringArray(guest.Status, detachStatus) && !purge { - self.SetStage("on_sync_config_complete", nil) + + if !purge { + self.SetStage("OnDetachDiskComplete", nil) guest.GetDriver().RequestDetachDisk(ctx, guest, disk, self) } else { - self.OnSyncConfigComplete(ctx, guest, nil) + self.OnDetachDiskComplete(ctx, guest, nil) } } -func (self *GuestDetachDiskTask) OnSyncConfigComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { +func (self *GuestDetachDiskTask) OnDetachDiskComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { diskId, _ := self.Params.GetString("disk_id") objDisk, err := models.DiskManager.FetchById(diskId) if err != nil { @@ -92,7 +87,7 @@ func (self *GuestDetachDiskTask) OnSyncConfigComplete(ctx context.Context, guest self.OnTaskFail(ctx, guest, nil, fmt.Errorf("Connot find disk %s", diskId)) return } - disk.SetDiskReady(ctx, self.UserCred, "") + disk.SetStatus(self.UserCred, api.DISK_READY, "") keepDisk := jsonutils.QueryBoolean(self.Params, "keep_disk", true) host := guest.GetHost() purge := false @@ -114,7 +109,7 @@ func (self *GuestDetachDiskTask) OnSyncConfigComplete(ctx context.Context, guest self.OnDiskDeleteComplete(ctx, guest, nil) } -func (self *GuestDetachDiskTask) OnSyncConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, reason jsonutils.JSONObject) { +func (self *GuestDetachDiskTask) OnDetachDiskCompleteFailed(ctx context.Context, obj db.IStandaloneModel, reason jsonutils.JSONObject) { guest := obj.(*models.SGuest) driver, _ := self.Params.GetString("driver") cache, _ := self.Params.GetString("cache") @@ -128,7 +123,7 @@ func (self *GuestDetachDiskTask) OnSyncConfigCompleteFailed(ctx context.Context, } disk := objDisk.(*models.SDisk) db.OpsLog.LogEvent(disk, db.ACT_DETACH, reason.String(), self.UserCred) - disk.SetDiskReady(ctx, self.UserCred, "") + disk.SetStatus(self.UserCred, api.DISK_READY, "") err = guest.AttachDisk(ctx, disk, self.UserCred, driver, cache, mountpoint) if err != nil { log.Warningf("recover attach disk %s(%s) for guest %s(%s) error: %v", disk.Name, disk.Id, guest.Name, guest.Id, err) @@ -138,7 +133,7 @@ func (self *GuestDetachDiskTask) OnSyncConfigCompleteFailed(ctx context.Context, func (self *GuestDetachDiskTask) OnTaskFail(ctx context.Context, guest *models.SGuest, disk *models.SDisk, err error) { if disk != nil { - disk.SetDiskReady(ctx, self.UserCred, "") + disk.SetStatus(self.UserCred, api.DISK_READY, "") } guest.SetStatus(self.UserCred, api.VM_DETACH_DISK_FAILED, err.Error()) self.SetStageFailed(ctx, err.Error()) @@ -147,6 +142,16 @@ func (self *GuestDetachDiskTask) OnTaskFail(ctx context.Context, guest *models.S } func (self *GuestDetachDiskTask) OnDiskDeleteComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + self.SetStage("OnSyncstatusComplete", nil) + guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) +} + +func (self *GuestDetachDiskTask) OnSyncstatusComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { self.SetStageComplete(ctx, nil) logclient.AddActionLogWithStartable(self, obj, logclient.ACT_VM_DETACH_DISK, nil, self.UserCred, true) } + +func (self *GuestDetachDiskTask) OnSyncstatusCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.OnSyncstatusComplete(ctx, obj, data) +} diff --git a/pkg/util/openstack/shell/instance.go b/pkg/util/openstack/shell/instance.go index 6d82799df5..2f211d43bf 100644 --- a/pkg/util/openstack/shell/instance.go +++ b/pkg/util/openstack/shell/instance.go @@ -78,4 +78,12 @@ func init() { return cli.ChangeConfig(instance, args.FLAVOR_ID) }) + type InstanceDiskOptions struct { + ID string `help:"Instance ID"` + DISK string `help:"DiskId"` + } + + shellutils.R(&InstanceDiskOptions{}, "instance-detach-disk", "Detach instance disk", func(cli *openstack.SRegion, args *InstanceDiskOptions) error { + return cli.DetachDisk(args.ID, args.DISK) + }) }