Skip to content

Commit

Permalink
add: region/openstack 迁移接入
Browse files Browse the repository at this point in the history
  • Loading branch information
lvyangyang committed Jul 1, 2020
1 parent f97c397 commit 3867463
Show file tree
Hide file tree
Showing 12 changed files with 521 additions and 40 deletions.
3 changes: 3 additions & 0 deletions pkg/cloudprovider/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ type ICloudVM interface {

Renew(bc billing.SBillingCycle) error

MigrateVM(hostid string) error
LiveMigrateVM(hostid string) error

GetError() error
}

Expand Down
18 changes: 18 additions & 0 deletions pkg/cloudprovider/waitstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ func WaitStatus(res ICloudResource, expect string, interval time.Duration, timeo
return ErrTimeout
}

func WaitMultiStatus(res ICloudResource, expects []string, interval time.Duration, timeout time.Duration) error {
startTime := time.Now()
for time.Now().Sub(startTime) < timeout {
err := res.Refresh()
if err != nil {
return errors.Wrap(err, "resource.Refresh()")
}
log.Debugf("status %s expect %s", res.GetStatus(), expects)
for _, expect := range expects {
if res.GetStatus() == expect {
return nil
}
}
time.Sleep(interval)
}
return errors.Wrap(errors.ErrTimeout, "WaitMultistatus")
}

func WaitStatusWithDelay(res ICloudResource, expect string, delay time.Duration, interval time.Duration, timeout time.Duration) error {
time.Sleep(delay)
return WaitStatus(res, expect, interval, timeout)
Expand Down
23 changes: 23 additions & 0 deletions pkg/compute/guestdrivers/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,3 +358,26 @@ func (self *SBaseGuestDriver) IsSupportSetAutoRenew() bool {
func (self *SBaseGuestDriver) RequestSetAutoRenewInstance(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, autoRenew bool, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestSetAutoRenewInstance")
}

func (self *SBaseGuestDriver) IsSupportMigrate() bool {
return false
}

func (self *SBaseGuestDriver) IsSupportLiveMigrate() bool {
return false
}

func (self *SBaseGuestDriver) CheckMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewNotAcceptableError("Not allow for hypervisor %s", guest.GetHypervisor())
}

func (self *SBaseGuestDriver) CheckLiveMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewNotAcceptableError("Not allow for hypervisor %s", guest.GetHypervisor())
}
func (self *SBaseGuestDriver) RequestMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestMigrate")
}

func (self *SBaseGuestDriver) RequestLiveMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestLiveMigrate")
}
65 changes: 65 additions & 0 deletions pkg/compute/guestdrivers/kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/logclient"
Expand Down Expand Up @@ -543,3 +544,67 @@ func (self *SKVMGuestDriver) OnGuestChangeCpuMemFailed(ctx context.Context, gues
func (self *SKVMGuestDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
return true, nil
}

func (self *SKVMGuestDriver) IsSupportMigrate() bool {
return true
}

func (self *SKVMGuestDriver) IsSupportLiveMigrate() bool {
return true
}

func (self *SKVMGuestDriver) CheckMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
if len(guest.BackupHostId) > 0 {
return httperrors.NewBadRequestError("Guest have backup, can't migrate")
}
isRescueMode := jsonutils.QueryBoolean(data, "rescue_mode", false)
if !isRescueMode && guest.Status != api.VM_READY {
return httperrors.NewServerStatusError("Cannot normal migrate guest in status %s, try rescue mode or server-live-migrate?", guest.Status)
}
if isRescueMode {
guestDisks := guest.GetDisks()
for _, guestDisk := range guestDisks {
if utils.IsInStringArray(
guestDisk.GetDisk().GetStorage().StorageType, api.STORAGE_LOCAL_TYPES) {
return httperrors.NewBadRequestError("Rescue mode requires all disk store in shared storages")
}
}
}
devices := guest.GetIsolatedDevices()
if len(devices) > 0 {
return httperrors.NewBadRequestError("Cannot migrate with isolated devices")
}
preferHost, _ := data.GetString("prefer_host")
if len(preferHost) > 0 {
if !db.IsAdminAllowPerform(userCred, guest, "assign-host") {
return httperrors.NewBadRequestError("Only system admin can assign host")
}
}
return nil
}

func (self *SKVMGuestDriver) CheckLiveMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
if len(guest.BackupHostId) > 0 {
return httperrors.NewBadRequestError("Guest have backup, can't migrate")
}
if utils.IsInStringArray(guest.Status, []string{api.VM_RUNNING, api.VM_SUSPEND}) {
cdrom := guest.GetCdrom()
if cdrom != nil && len(cdrom.ImageId) > 0 {
return httperrors.NewBadRequestError("Cannot live migrate with cdrom")
}
devices := guest.GetIsolatedDevices()
if devices != nil && len(devices) > 0 {
return httperrors.NewBadRequestError("Cannot live migrate with isolated devices")
}
if !guest.CheckQemuVersion(guest.GetQemuVersion(userCred), "1.1.2") {
return httperrors.NewBadRequestError("Cannot do live migrate, too low qemu version")
}
preferHost, _ := data.GetString("prefer_host")
if len(preferHost) > 0 {
if !db.IsAdminAllowPerform(userCred, guest, "assign-host") {
return httperrors.NewBadRequestError("Only system admin can assign host")
}
}
}
return nil
}
96 changes: 96 additions & 0 deletions pkg/compute/guestdrivers/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,99 @@ func (self *SOpenStackGuestDriver) AllowReconfigGuest() bool {
func (self *SOpenStackGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return false
}

func (self *SOpenStackGuestDriver) IsSupportMigrate() bool {
return true
}

func (self *SOpenStackGuestDriver) IsSupportLiveMigrate() bool {
return true
}

func (self *SOpenStackGuestDriver) CheckMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return nil
}

func (self *SOpenStackGuestDriver) CheckLiveMigrate(guest *models.SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return nil
}

func (self *SOpenStackGuestDriver) RequestMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iVM, err := guest.GetIVM()
if err != nil {
return nil, errors.Wrap(err, "guest.GetIVM")
}
hostID, _ := data.GetString("prefer_host_id")
hostExternalId := ""
if hostID != "" {
iHost, err := models.HostManager.FetchById(hostID)
if err != nil {
return nil, errors.Wrapf(err, "models.HostManager.FetchById(%s)", hostID)
}
host := iHost.(*models.SHost)
hostExternalId = host.ExternalId
}
if err = iVM.MigrateVM(hostExternalId); err != nil {
return nil, errors.Wrapf(err, "iVM.MigrateVM(%s)", hostExternalId)
}
hostExternalId = iVM.GetIHostId()
if hostExternalId == "" {
return nil, errors.Wrap(fmt.Errorf("empty hostExternalId"), "iVM.GetIHostId()")
}
iHost, err := db.FetchByExternalId(models.HostManager, hostExternalId)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchByExternalId(models.HostManager,%s)", hostExternalId)
}
host := iHost.(*models.SHost)
_, err = db.Update(guest, func() error {
guest.HostId = host.GetId()
return nil
})
if err != nil {
return nil, errors.Wrap(err, "db.Update guest.hostId")
}
return nil, nil
})
return nil
}

func (self *SOpenStackGuestDriver) RequestLiveMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iVM, err := guest.GetIVM()
if err != nil {
return nil, errors.Wrap(err, "guest.GetIVM")
}
hostID, _ := data.GetString("prefer_host_id")
hostExternalId := ""
if hostID != "" {
iHost, err := models.HostManager.FetchById(hostID)
if err != nil {
return nil, errors.Wrapf(err, "models.HostManager.FetchById(%s)", hostID)
}
host := iHost.(*models.SHost)
hostExternalId = host.ExternalId
}
if err = iVM.LiveMigrateVM(hostExternalId); err != nil {
return nil, errors.Wrapf(err, "iVM.LiveMigrateVM(%s)", hostExternalId)
}
hostExternalId = iVM.GetIHostId()
if hostExternalId == "" {
return nil, errors.Wrap(fmt.Errorf("empty hostExternalId"), "iVM.GetIHostId()")
}
iHost, err := db.FetchByExternalId(models.HostManager, hostExternalId)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchByExternalId(models.HostManager,%s)", hostExternalId)
}
host := iHost.(*models.SHost)
_, err = db.Update(guest, func() error {
guest.HostId = host.GetId()
return nil
})
if err != nil {
return nil, errors.Wrap(err, "db.Update guest.hostId")
}
return nil, nil
})
return nil
}
58 changes: 18 additions & 40 deletions pkg/compute/models/guest_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,35 +317,19 @@ func (self *SGuest) AllowPerformMigrate(ctx context.Context, userCred mcclient.T
}

func (self *SGuest) PerformMigrate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.GetHypervisor() != api.HYPERVISOR_KVM {
if !self.GetDriver().IsSupportMigrate() {
return nil, httperrors.NewNotAcceptableError("Not allow for hypervisor %s", self.GetHypervisor())
}
if len(self.BackupHostId) > 0 {
return nil, httperrors.NewBadRequestError("Guest have backup, can't migrate")
if err := self.GetDriver().CheckMigrate(self, userCred, data); err != nil {
return nil, err
}
isRescueMode := jsonutils.QueryBoolean(data, "rescue_mode", false)
if !isRescueMode && self.Status != api.VM_READY {
if self.Status != api.VM_READY {
return nil, httperrors.NewServerStatusError("Cannot normal migrate guest in status %s, try rescue mode or server-live-migrate?", self.Status)
}
if isRescueMode {
guestDisks := self.GetDisks()
for _, guestDisk := range guestDisks {
if utils.IsInStringArray(
guestDisk.GetDisk().GetStorage().StorageType, api.STORAGE_LOCAL_TYPES) {
return nil, httperrors.NewBadRequestError("Rescue mode requires all disk store in shared storages")
}
}
}
devices := self.GetIsolatedDevices()
if len(devices) > 0 {
return nil, httperrors.NewBadRequestError("Cannot migrate with isolated devices")
}
isRescueMode := jsonutils.QueryBoolean(data, "rescue_mode", false)
var preferHostId string
preferHost, _ := data.GetString("prefer_host")
if len(preferHost) > 0 {
if !db.IsAdminAllowPerform(userCred, self, "assign-host") {
return nil, httperrors.NewBadRequestError("Only system admin can assign host")
}
iHost, _ := HostManager.FetchByIdOrName(userCred, preferHost)
if iHost == nil {
return nil, httperrors.NewBadRequestError("Host %s not found", preferHost)
Expand Down Expand Up @@ -374,7 +358,11 @@ func (self *SGuest) StartMigrateTask(
data.Set("auto_start", jsonutils.JSONTrue)
}
data.Set("guest_status", jsonutils.NewString(guestStatus))
if task, err := taskman.TaskManager.NewTask(ctx, "GuestMigrateTask", self, userCred, data, parentTaskId, "", nil); err != nil {
dedicateMigrateTask := "GuestMigrateTask"
if self.GetHypervisor() != api.HYPERVISOR_KVM {
dedicateMigrateTask = "ManagedGuestMigrateTask" //托管私有云
}
if task, err := taskman.TaskManager.NewTask(ctx, dedicateMigrateTask, self, userCred, data, parentTaskId, "", nil); err != nil {
log.Errorln(err)
return err
} else {
Expand All @@ -388,30 +376,16 @@ func (self *SGuest) AllowPerformLiveMigrate(ctx context.Context, userCred mcclie
}

func (self *SGuest) PerformLiveMigrate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.GetHypervisor() != api.HYPERVISOR_KVM {
if !self.GetDriver().IsSupportLiveMigrate() {
return nil, httperrors.NewNotAcceptableError("Not allow for hypervisor %s", self.GetHypervisor())
}
if len(self.BackupHostId) > 0 {
return nil, httperrors.NewBadRequestError("Guest have backup, can't migrate")
if err := self.GetDriver().CheckLiveMigrate(self, userCred, data); err != nil {
return nil, err
}
if utils.IsInStringArray(self.Status, []string{api.VM_RUNNING, api.VM_SUSPEND}) {
cdrom := self.getCdrom(false)
if cdrom != nil && len(cdrom.ImageId) > 0 {
return nil, httperrors.NewBadRequestError("Cannot live migrate with cdrom")
}
devices := self.GetIsolatedDevices()
if devices != nil && len(devices) > 0 {
return nil, httperrors.NewBadRequestError("Cannot live migrate with isolated devices")
}
if !self.CheckQemuVersion(self.GetQemuVersion(userCred), "1.1.2") {
return nil, httperrors.NewBadRequestError("Cannot do live migrate, too low qemu version")
}
var preferHostId string
preferHost, _ := data.GetString("prefer_host")
if len(preferHost) > 0 {
if !db.IsAdminAllowPerform(userCred, self, "assign-host") {
return nil, httperrors.NewBadRequestError("Only system admin can assign host")
}
iHost, _ := HostManager.FetchByIdOrName(userCred, preferHost)
if iHost == nil {
return nil, httperrors.NewBadRequestError("Host %s not found", preferHost)
Expand All @@ -432,7 +406,11 @@ func (self *SGuest) StartGuestLiveMigrateTask(ctx context.Context, userCred mccl
data.Set("prefer_host_id", jsonutils.NewString(preferHostId))
}
data.Set("guest_status", jsonutils.NewString(guestStatus))
if task, err := taskman.TaskManager.NewTask(ctx, "GuestLiveMigrateTask", self, userCred, data, parentTaskId, "", nil); err != nil {
dedicateMigrateTask := "GuestLiveMigrateTask"
if self.GetHypervisor() != api.HYPERVISOR_KVM {
dedicateMigrateTask = "ManagedGuestLiveMigrateTask" //托管私有云
}
if task, err := taskman.TaskManager.NewTask(ctx, dedicateMigrateTask, self, userCred, data, parentTaskId, "", nil); err != nil {
log.Errorln(err)
return err
} else {
Expand Down
6 changes: 6 additions & 0 deletions pkg/compute/models/guestdrivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ type IGuestDriver interface {

IsSupportSetAutoRenew() bool
RequestSetAutoRenewInstance(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, autoRenew bool, task taskman.ITask) error
IsSupportMigrate() bool
IsSupportLiveMigrate() bool
CheckMigrate(guest *SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error
CheckLiveMigrate(guest *SGuest, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error
RequestMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error
RequestLiveMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error
}

var guestDrivers map[string]IGuestDriver
Expand Down

0 comments on commit 3867463

Please sign in to comment.