diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index c20d1ad85c..d6aa054b23 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -798,7 +798,39 @@ func (self *SGuest) StartInsertIsoTask(ctx context.Context, imageId string, host return nil } -func (self *SGuest) StartGueststartTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { +func (self *SGuest) IsDisksShared() bool { + return self.getDefaultStorageType() == api.STORAGE_RBD +} + +func (self *SGuest) StartGueststartTask( + ctx context.Context, userCred mcclient.TokenCredential, + data *jsonutils.JSONDict, parentTaskId string, +) error { + if self.Hypervisor == api.HYPERVISOR_KVM && self.IsDisksShared() { + return self.GuestSchedStartTask(ctx, userCred, data, parentTaskId) + } else { + return self.GuestNonSchedStartTask(ctx, userCred, data, parentTaskId) + } +} + +func (self *SGuest) GuestSchedStartTask( + ctx context.Context, userCred mcclient.TokenCredential, + data *jsonutils.JSONDict, parentTaskId string, +) error { + self.SetStatus(userCred, api.VM_SCHEDULE, "") + task, err := taskman.TaskManager.NewTask(ctx, "GuestSchedStartTask", self, userCred, data, + parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SGuest) GuestNonSchedStartTask( + ctx context.Context, userCred mcclient.TokenCredential, + data *jsonutils.JSONDict, parentTaskId string, +) error { self.SetStatus(userCred, api.VM_START_START, "") task, err := taskman.TaskManager.NewTask(ctx, "GuestStartTask", self, userCred, data, parentTaskId, "", nil) if err != nil { diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 68bc1406d5..7019a47e55 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -1215,6 +1215,14 @@ func (self *SHost) GetRunningGuestCount() (int, error) { return q.CountWithError() } +func (self *SHost) GetRunningGuestMemorySize() int { + res := self.getGuestsResource(api.VM_RUNNING) + if res != nil { + return res.GuestVmemSize + } + return -1 +} + func (self *SHost) GetBaremetalnetworksQuery() *sqlchemy.SQuery { return HostnetworkManager.Query().Equals("baremetal_id", self.Id) } diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 00f0e6402e..f3bfffe050 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -154,3 +154,52 @@ func (self *GuestStartTask) taskComplete(ctx context.Context, guest *models.SGue models.HostManager.ClearSchedDescCache(guest.HostId) self.SetStageComplete(ctx, nil) } + +type GuestSchedStartTask struct { + SGuestBaseTask +} + +func (self *GuestSchedStartTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + self.StartScheduler(ctx, guest) +} + +func (self *GuestSchedStartTask) StartScheduler(ctx context.Context, guest *models.SGuest) { + host := guest.GetHost() + if guestsMem := host.GetRunningGuestMemorySize(); guestsMem < 0 { + self.TaskFailed(ctx, guest, "Guest Start Failed: Can't Get Host Guests Memory") + } else { + if float32(guestsMem+guest.VmemSize) > host.GetVirtualMemorySize() { + self.ScheduleFailed(ctx, guest) + } else { + self.ScheduleSucc(ctx, guest) + } + } +} + +func (self *GuestSchedStartTask) ScheduleFailed(ctx context.Context, guest *models.SGuest) { + self.SetStage("OnGuestMigrate", nil) + guest.StartMigrateTask(ctx, self.UserCred, false, false, guest.Status, "", self.GetId()) +} + +func (self *GuestSchedStartTask) OnGuestMigrate(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) + guest.GuestNonSchedStartTask(ctx, self.UserCred, nil, "") +} + +func (self *GuestSchedStartTask) OnGuestMigrateFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + self.TaskFailed(ctx, guest, fmt.Sprintf("OnGuestMigrateFailed %s", data)) +} + +func (self *GuestSchedStartTask) ScheduleSucc(ctx context.Context, guest *models.SGuest) { + self.SetStageComplete(ctx, nil) + guest.GuestNonSchedStartTask(ctx, self.UserCred, nil, "") +} + +func (self *GuestSchedStartTask) TaskFailed(ctx context.Context, guest *models.SGuest, reason string) { + self.SetStageFailed(ctx, reason) + guest.SetStatus(self.UserCred, api.VM_START_FAILED, reason) + db.OpsLog.LogEvent(guest, db.ACT_START_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable( + self, guest, logclient.ACT_VM_START, reason, self.UserCred, false) +}