diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index 80b546e4a58..d735885450d 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -433,6 +433,10 @@ const ( VM_METADATA_OS_VERSION = "os_version" VM_METADATA_CGROUP_CPUSET = "cgroup_cpuset" VM_METADATA_ENABLE_MEMCLEAN = "enable_memclean" + VM_METADATA_HOTPLUG_CPU_MEM = "hotplug_cpu_mem" + VM_METADATA_HOT_REMOVE_NIC = "hot_remove_nic" + VM_METADATA_START_VMEM_MB = "start_vmem_mb" + VM_METADATA_START_VCPU_COUNT = "start_vcpu_count" ) func Hypervisors2HostTypes(hypervisors []string) []string { diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 201b5273085..78f08a192bc 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -321,7 +321,7 @@ func (drv *SBaseGuestDriver) IsSupportPublicIp() bool { return false } -func (drv *SBaseGuestDriver) NeedStopForChangeSpec(ctx context.Context, guest *models.SGuest, cpuChanged, memChanged bool) bool { +func (drv *SBaseGuestDriver) NeedStopForChangeSpec(ctx context.Context, guest *models.SGuest, addCpu int, addMemMb int) bool { return false } diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index 0d323c8228b..f1d857d3b25 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "sort" + "strconv" "time" "yunion.io/x/cloudmux/pkg/cloudprovider" @@ -861,3 +862,23 @@ func (drv *SESXiGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, gue }) return nil } + +func (drv *SESXiGuestDriver) NeedStopForChangeSpec(ctx context.Context, guest *models.SGuest, addCpu int, addMemMb int) bool { + // https://kb.vmware.com/s/article/2008405 + startVmem := guest.VmemSize + vmemMbStr := guest.GetMetadata(ctx, api.VM_METADATA_START_VMEM_MB, nil) + if len(vmemMbStr) > 0 { + vmemMb, _ := strconv.Atoi(vmemMbStr) + if vmemMb > 0 { + startVmem = int(vmemMb) + } + } + maxAllowVmem := 16 * startVmem + if startVmem <= 3*1024 { + maxAllowVmem = 3 * 1024 + } + if guest.VmemSize+addMemMb > maxAllowVmem { + return true + } + return false +} diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index c4400ed4e1c..248387b7608 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -425,10 +425,8 @@ func (self *SKVMGuestDriver) RequestAssociateEip(ctx context.Context, userCred m return nil } -func (self *SKVMGuestDriver) NeedStopForChangeSpec(ctx context.Context, guest *models.SGuest, cpuChanged, memChanged bool) bool { - return guest.GetMetadata(ctx, "hotplug_cpu_mem", nil) != "enable" || apis.IsARM(guest.OsArch) - // (memChanged && guest.GetMetadata(ctx, "__hugepage", nil) == "native") || - // apis.IsARM(guest.OsArch) +func (self *SKVMGuestDriver) NeedStopForChangeSpec(ctx context.Context, guest *models.SGuest, addCpu int, addMemMb int) bool { + return guest.GetMetadata(ctx, api.VM_METADATA_HOTPLUG_CPU_MEM, nil) != "enable" || apis.IsARM(guest.OsArch) && addMemMb > 0 } func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, cpuSockets, vmemSize int64) error { @@ -866,7 +864,7 @@ func (self *SKVMGuestDriver) RequestCancelLiveMigrate(ctx context.Context, guest } func (self *SKVMGuestDriver) ValidateDetachNetwork(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest) error { - if guest.Status == api.VM_RUNNING && guest.GetMetadata(ctx, "hot_remove_nic", nil) != "enable" { + if guest.Status == api.VM_RUNNING && guest.GetMetadata(ctx, api.VM_METADATA_HOT_REMOVE_NIC, nil) != "enable" { return httperrors.NewBadRequestError("Guest %s can't hot remove nic", guest.GetName()) } return nil diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 81f5ff61c3c..d6b35e7b15a 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -2762,7 +2762,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T confs.Set("cpu_sockets", jsonutils.NewInt(int64(*input.CpuSockets))) } - if self.Status == api.VM_RUNNING && (cpuChanged || memChanged || cpuSocketsChanged) && self.GetDriver().NeedStopForChangeSpec(ctx, self, cpuChanged, memChanged) { + if self.Status == api.VM_RUNNING && (cpuChanged || memChanged || cpuSocketsChanged) && self.GetDriver().NeedStopForChangeSpec(ctx, self, addCpu, addMem) { return nil, httperrors.NewInvalidStatusError("cannot change CPU/Memory spec in status %s", self.Status) } diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index c5063b5db6f..0dec8764fbf 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -186,7 +186,7 @@ type IGuestDriver interface { IsSupportPublicIp() bool ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error - NeedStopForChangeSpec(ctx context.Context, guest *SGuest, cpuChanged, memChanged bool) bool + NeedStopForChangeSpec(ctx context.Context, guest *SGuest, addCpu int, addMemMb int) bool OnGuestChangeCpuMemFailed(ctx context.Context, guest *SGuest, data *jsonutils.JSONDict, task taskman.ITask) error IsSupportGuestClone() bool diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 5ee2db35fe0..d7c7ceafe66 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -58,6 +58,10 @@ func (self *GuestStartTask) RequestStart(ctx context.Context, guest *models.SGue func (task *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { guest := obj.(*models.SGuest) + // save start mem and cpu + guest.SetMetadata(ctx, api.VM_METADATA_START_VCPU_COUNT, guest.VcpuCount, task.UserCred) + guest.SetMetadata(ctx, api.VM_METADATA_START_VMEM_MB, guest.VmemSize, task.UserCred) + // sync Vpc Topology isVpc, err := guest.IsOneCloudVpcNetwork() if err != nil { log.Errorf("IsOneCloudVpcNetwork fail: %s", err) @@ -68,6 +72,7 @@ func (task *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandal log.Errorf("vpcagent.VpcAgent.DoSync fail %s", err) } } + // log db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(ctx), task.UserCred) logclient.AddActionLogWithStartable(task, guest, logclient.ACT_VM_START, guest.GetShortDesc(ctx), task.UserCred, true) task.taskComplete(ctx, guest) diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index fd4ce506e40..fd92dc5d115 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -759,8 +759,8 @@ func (s *SKVMGuestInstance) onImportGuestMonitorConnected(ctx context.Context) { log.Infof("Guest %s qemu version %s", s.Id, version) s.QemuVersion = version meta := jsonutils.NewDict() - meta.Set("hotplug_cpu_mem", jsonutils.NewString("disable")) - meta.Set("hot_remove_nic", jsonutils.NewString("disable")) + meta.Set(api.VM_METADATA_HOTPLUG_CPU_MEM, jsonutils.NewString("disable")) + meta.Set(api.VM_METADATA_HOT_REMOVE_NIC, jsonutils.NewString("disable")) meta.Set("__qemu_version", jsonutils.NewString(s.GetQemuVersionStr())) s.SyncMetadata(meta) s.SyncStatus("") @@ -2602,8 +2602,8 @@ func (s *SKVMGuestInstance) OnResumeSyncMetadataInfo() { meta.Set("__qemu_version", jsonutils.NewString(s.GetQemuVersionStr())) meta.Set("__vnc_port", jsonutils.NewInt(int64(s.GetVncPort()))) meta.Set("__enable_cgroup_cpuset", jsonutils.JSONTrue) - meta.Set("hotplug_cpu_mem", jsonutils.NewString("enable")) - meta.Set("hot_remove_nic", jsonutils.NewString("enable")) + meta.Set(api.VM_METADATA_HOTPLUG_CPU_MEM, jsonutils.NewString("enable")) + meta.Set(api.VM_METADATA_HOT_REMOVE_NIC, jsonutils.NewString("enable")) if len(s.VncPassword) > 0 { meta.Set("__vnc_password", jsonutils.NewString(s.VncPassword)) }