diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 6edbf44908..c351176f4e 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -1105,3 +1105,9 @@ type ServerLoginInfoOutput struct { Keypair string `json:"keypair"` Password string `json:"password"` } + +type GuestPerformStartInput struct { + // 指定启动虚拟机的Qemu版本,可选值:2.12.1, 4.2.0 + // 仅适用于KVM虚拟机 + QemuVersion string `json:"qemu_version"` +} diff --git a/pkg/apis/compute/host.go b/pkg/apis/compute/host.go index 313cbae0f8..eaa80f3b68 100644 --- a/pkg/apis/compute/host.go +++ b/pkg/apis/compute/host.go @@ -624,3 +624,6 @@ type HostLoginInfoOutput struct { Username string `json:"username"` Password string `json:"password"` } + +type HostPerformStartInput struct { +} diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index 24e3590fee..7a0905357d 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -332,6 +332,10 @@ func (self *SBaremetalGuestDriver) RequestStartOnHost(ctx context.Context, guest desc := guest.GetJsonDescAtBaremetal(ctx, host) config := jsonutils.NewDict() config.Set("desc", jsonutils.Marshal(desc)) + params := task.GetParams() + if params.Length() > 0 { + config.Add(params, "params") + } headers := task.GetTaskRequestHeader() url := fmt.Sprintf("/baremetals/%s/servers/%s/start", host.Id, guest.Id) _, err := host.BaremetalSyncRequest(ctx, "POST", url, headers, config) diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index a9489a7801..b03a340278 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1016,8 +1016,12 @@ func (self *SGuest) StartResumeTask(ctx context.Context, userCred mcclient.Token return self.GetDriver().StartResumeTask(ctx, userCred, self, nil, parentTaskId) } -func (self *SGuest) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (self *SGuest) PerformStart( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + input api.GuestPerformStartInput, +) (jsonutils.JSONObject, error) { if utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_START_FAILED, api.VM_SAVE_DISK_FAILED, api.VM_SUSPEND}) { if err := self.ValidateEncryption(ctx, userCred); err != nil { return nil, errors.Wrap(httperrors.ErrForbidden, "encryption key not accessible") @@ -1033,10 +1037,7 @@ func (self *SGuest) PerformStart(ctx context.Context, userCred mcclient.TokenCre } } if self.isAllDisksReady() { - var kwargs *jsonutils.JSONDict - if data != nil { - kwargs = data.(*jsonutils.JSONDict) - } + kwargs := jsonutils.Marshal(input).(*jsonutils.JSONDict) err := self.GetDriver().PerformStart(ctx, userCred, self, kwargs) return nil, err } else { diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index d0de367ab5..89b2947619 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -1677,12 +1677,8 @@ func (hh *SHost) GetNotReadyGuestsMemorySize() (int, error) { return stat.GuestVmemSize, nil } -func (hh *SHost) GetRunningGuestMemorySize() int { - res := hh.getGuestsResource(api.VM_RUNNING) - if res != nil { - return res.GuestVmemSize - } - return -1 +func (hh *SHost) GetRunningGuestResourceUsage() *SHostGuestResourceUsage { + return hh.getGuestsResource(api.VM_RUNNING) } func (hh *SHost) GetBaremetalnetworksQuery() *sqlchemy.SQuery { @@ -3730,6 +3726,13 @@ func (hh *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.Token return input, errors.Errorf("host mem is hugepage, cannot update mem_cmtbound") } + if input.CpuReserved != nil { + info := hh.GetMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_INFO, nil) + if len(info) > 0 { + return input, errors.Wrap(httperrors.ErrInputParameter, "host cpu has been reserved, cannot update cpu_reserved") + } + } + input.HostSizeAttributes, err = HostManager.ValidateSizeParams(input.HostSizeAttributes) if err != nil { return input, errors.Wrap(err, "ValidateSizeParams") @@ -3890,8 +3893,12 @@ func fetchIpmiInfo(data api.HostIpmiAttributes, hostId string) (types.SIPMIInfo, return info, nil } -func (hh *SHost) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (hh *SHost) PerformStart( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + input api.HostPerformStartInput, +) (jsonutils.JSONObject, error) { if !hh.IsBaremetal { return nil, httperrors.NewBadRequestError("Cannot start a non-baremetal host") } @@ -3907,7 +3914,7 @@ func (hh *SHost) PerformStart(ctx context.Context, userCred mcclient.TokenCreden // return nil, httperrors.NewBadRequestError("Cannot start baremetal with active guest") // } hh.SetStatus(userCred, api.BAREMETAL_START_MAINTAIN, "") - return guest.PerformStart(ctx, userCred, query, data) + return guest.PerformStart(ctx, userCred, query, api.GuestPerformStartInput{}) } params := jsonutils.NewDict() params.Set("force_reboot", jsonutils.NewBool(false)) diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 6e6b640ca3..5ee2db35fe 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -97,10 +97,14 @@ func (self *GuestSchedStartTask) OnInit(ctx context.Context, obj db.IStandaloneM func (self *GuestSchedStartTask) StartScheduler(ctx context.Context, guest *models.SGuest) { host, _ := guest.GetHost() - if guestsMem := host.GetRunningGuestMemorySize(); guestsMem < 0 { - self.TaskFailed(ctx, guest, jsonutils.NewString("Guest Start Failed: Can't Get Host Guests Memory")) + if request := host.GetRunningGuestResourceUsage(); request == nil { + self.TaskFailed(ctx, guest, jsonutils.NewString("Guest Start Failed: Can't Get Host Guests CPU Memory Usage")) } else { - if float32(guestsMem+guest.VmemSize) > host.GetVirtualMemorySize() { + if float32(request.GuestVmemSize+guest.VmemSize) > host.GetVirtualMemorySize() { + log.Infof("host memory not enough to start guest") + self.ScheduleFailed(ctx, guest) + } else if request.GuestVcpuCount+guest.VcpuCount > int(host.GetVirtualCPUCount()) { + log.Infof("host cpu not enough to start guest") self.ScheduleFailed(ctx, guest) } else { self.ScheduleSucc(ctx, guest) @@ -124,7 +128,7 @@ func (self *GuestSchedStartTask) OnGuestMigrateFailed(ctx context.Context, guest func (self *GuestSchedStartTask) ScheduleSucc(ctx context.Context, guest *models.SGuest) { self.SetStageComplete(ctx, nil) - guest.GuestNonSchedStartTask(ctx, self.UserCred, nil, "") + guest.GuestNonSchedStartTask(ctx, self.UserCred, self.Params, "") } func (self *GuestSchedStartTask) TaskFailed(ctx context.Context, guest *models.SGuest, reason jsonutils.JSONObject) {