fix(region): change config stop options check (#25285)

This commit is contained in:
屈轩
2026-08-06 17:32:29 +08:00
committed by GitHub
parent 6e6e9a87d2
commit 2da0c3ae2f
8 changed files with 81 additions and 45 deletions
+22 -2
View File
@@ -890,8 +890,9 @@ type ServerChangeConfigInput struct {
// 内存大小, 1024M, 1G
VmemSize string `json:"vmem_size"`
// 是否强制关机
// 虚拟机不支持开机调整配置, 则需要指定此参数为true, 强制关机后, 再调整配置, 再启动虚拟机
// 是否允许强制关机
// 仅当虚拟机不支持开机调整配置, 或开机状态下降配(降低CPU/内存), 或ARM架构时时生效: 需指定为true以允许强制关机后再调整配置并启动;
// 若已支持开机变配, 即使传入该参数也不会强制关机
ForceStop bool `json:"force_stop"`
// 调整完配置后是否自动启动
@@ -1512,6 +1513,8 @@ type ServerChangeConfigSettings struct {
AutoStart bool `json:"auto_start"`
GuestOnline bool `json:"guest_online"`
// 需要强制关机后再调整配置(仅不支持在线变配/降配时为true), 并在完成后自动启动
ForceStop bool `json:"force_stop"`
// 设置虚拟网卡的流量上限
SetTrafficLimits []ServerNicTrafficLimit `json:"set_traffic_limits"`
@@ -1525,6 +1528,10 @@ func (conf ServerChangeConfigSettings) CpuChanged() bool {
return conf.VcpuCount != conf.Old.VcpuCount
}
func (conf ServerChangeConfigSettings) CpuReduced() bool {
return conf.VcpuCount < conf.Old.VcpuCount
}
func (conf ServerChangeConfigSettings) AddedCpu() int {
addCpu := conf.VcpuCount - conf.Old.VcpuCount
if addCpu < 0 {
@@ -1537,6 +1544,10 @@ func (conf ServerChangeConfigSettings) ExtraCpuChanged() bool {
return conf.ExtraCpuCount != conf.Old.ExtraCpuCount
}
func (conf ServerChangeConfigSettings) ExtraCpuReduced() bool {
return conf.ExtraCpuCount < conf.Old.ExtraCpuCount
}
func (conf ServerChangeConfigSettings) AddedExtraCpu() int {
addCpu := conf.ExtraCpuCount - conf.Old.ExtraCpuCount
if addCpu < 0 {
@@ -1549,6 +1560,10 @@ func (conf ServerChangeConfigSettings) MemChanged() bool {
return conf.VmemSize != conf.Old.VmemSize
}
func (conf ServerChangeConfigSettings) MemReduced() bool {
return conf.VmemSize < conf.Old.VmemSize
}
func (conf ServerChangeConfigSettings) InstanceTypeChanged() bool {
return len(conf.InstanceType) > 0 && conf.InstanceType != conf.Old.InstanceType
}
@@ -1561,6 +1576,11 @@ func (conf ServerChangeConfigSettings) AddedMem() int {
return addMem
}
// ConfigReduced 是否为降配(降低CPU/内存)
func (conf ServerChangeConfigSettings) ConfigReduced() bool {
return conf.CpuReduced() || conf.MemReduced() || conf.ExtraCpuReduced()
}
func (conf ServerChangeConfigSettings) AddedDisk() int {
var size int
for _, resize := range conf.Resize {
+4
View File
@@ -87,6 +87,10 @@ func (self *SBaremetalGuestDriver) GetMaxSecurityGroupCount() int {
return 0
}
func (self *SBaremetalGuestDriver) AllowReconfigGuest() bool {
return false
}
func (self *SBaremetalGuestDriver) GetMaxVCpuCount() int {
return 1024
}
+4
View File
@@ -91,6 +91,10 @@ func (self *SBingoCloudGuestDriver) GetDeployStatus() ([]string, error) {
return []string{api.VM_READY, api.VM_RUNNING}, nil
}
func (self *SBingoCloudGuestDriver) AllowReconfigGuest() bool {
return false
}
func (self *SBingoCloudGuestDriver) GetDefaultSysDiskBackend() string {
return ""
}
+1 -1
View File
@@ -272,7 +272,7 @@ func (self *SCNwareGuestDriver) GetInstanceCapability() cloudprovider.SInstanceC
}
func (self *SCNwareGuestDriver) AllowReconfigGuest() bool {
return true
return false
}
func (self *SCNwareGuestDriver) IsSupportEip() bool {
@@ -1187,35 +1187,6 @@ func (drv *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Con
instanceType = sku.Name
}
drv, err := guest.GetDriver()
if err != nil {
return nil, errors.Wrapf(err, "GetDriver")
}
runningOk, err := drv.IsChangeInstanceTypeWhileRunningSupported(guest)
if err != nil {
return nil, errors.Wrapf(err, "IsChangeInstanceTypeWhileRunningSupported")
}
needStart := false
if !runningOk {
status := iVM.GetStatus()
if status == api.VM_RUNNING {
err = iVM.StopVM(ctx, &cloudprovider.ServerStopOptions{
IsForce: true,
})
if err != nil {
return nil, errors.Wrapf(err, "StopVM")
}
err = cloudprovider.WaitStatus(iVM, api.VM_READY, time.Second*5, time.Minute*10)
if err != nil {
return nil, errors.Wrapf(err, "WaitStatus")
}
needStart = true
}
}
config := &cloudprovider.SManagedVMChangeConfig{
Cpu: int(vcpuCount),
CpuSocket: int(cpuSockets),
@@ -1261,17 +1232,6 @@ func (drv *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Con
}
}
if needStart {
err = iVM.StartVM(ctx)
if err != nil {
return nil, errors.Wrapf(err, "StartVM")
}
err = cloudprovider.WaitStatus(iVM, api.VM_RUNNING, time.Second*5, time.Minute*10)
if err != nil {
return nil, errors.Wrapf(err, "WaitStatus")
}
}
return nil, nil
})
+4
View File
@@ -69,6 +69,10 @@ func (self *SRemoteFileGuestDriver) GetComputeQuotaKeys(scope rbacscope.TRbacSco
return keys
}
func (self *SRemoteFileGuestDriver) AllowReconfigGuest() bool {
return false
}
func (self *SRemoteFileGuestDriver) GetDefaultSysDiskBackend() string {
return api.STORAGE_LOCAL
}
+20 -2
View File
@@ -3543,6 +3543,16 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
if !utils.IsInStringArray(self.Status, []string{api.VM_RUNNING, api.VM_READY}) {
return nil, httperrors.NewInvalidStatusError("Cannot change config in status %s", self.Status)
}
if self.RescueMode {
return nil, httperrors.NewInvalidStatusError("Cannot change config in rescue mode")
}
// 停止计费模式下, 不允许调整配置
if len(self.ExternalId) > 0 && self.ShutdownMode == api.VM_SHUTDOWN_MODE_STOP_CHARGING && self.Status == api.VM_READY {
return nil, httperrors.NewInvalidStatusError("Cannot change config in ready status when shutdown mode is stop charging")
}
driver, err := self.GetDriver()
if err != nil {
return nil, err
@@ -3570,12 +3580,20 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
if err != nil {
return nil, err
}
if !runningOk && !input.ForceStop {
// 仅在不支持开机变配, 或开机降配时需要强制关机,或ARM架构时需要强制关机; force_stop 表示允许关机, 而非一定关机
needForceStop := !runningOk || confs.ConfigReduced() || apis.IsARM(self.OsArch)
if needForceStop && !input.ForceStop {
return nil, httperrors.NewInvalidStatusError("Cannot change config in %s for %s, requires force_stop to change config", self.Status, self.GetHypervisor())
}
if needForceStop {
// 走离线变配路径, 变配完成后自动启动
confs.ForceStop = true
confs.GuestOnline = false
confs.AutoStart = true
}
}
if self.PowerStates == api.VM_POWER_STATES_ON && (confs.CpuChanged() || confs.MemChanged()) {
if self.PowerStates == api.VM_POWER_STATES_ON && (confs.CpuChanged() || confs.MemChanged()) && !confs.ForceStop {
confs, err = driver.ValidateGuestHotChangeConfigInput(ctx, self, confs)
if err != nil {
return nil, httperrors.NewInvalidStatusError("cannot change CPU/Memory spec in power status %s: %s", self.PowerStates, err)
@@ -235,6 +235,15 @@ func (task *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob
}
if confs.CpuChanged() || confs.MemChanged() || (drv.DoScheduleSKUFilter() && confs.InstanceTypeChanged()) {
// Status is already VM_CHANGE_FLAVOR; ForceStop means guest was running and needs offline change.
if confs.ForceStop {
task.SetStage("OnGuestStopForChangeConfigComplete", nil)
err = guest.StartGuestStopTask(ctx, task.UserCred, 60, true, false, task.GetTaskId())
if err != nil {
task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
}
return
}
task.SetStage("OnGuestChangeCpuMemSpecComplete", nil)
task.startGuestChangeCpuMemSpec(ctx, guest, confs.InstanceType, confs.VcpuCount, confs.CpuSockets, confs.VmemSize)
} else {
@@ -242,6 +251,23 @@ func (task *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob
}
}
func (task *GuestChangeConfigTask) OnGuestStopForChangeConfigComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
confs, err := task.getChangeConfigSetting()
if err != nil {
task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
return
}
task.SetStage("OnGuestChangeCpuMemSpecComplete", nil)
task.startGuestChangeCpuMemSpec(ctx, guest, confs.InstanceType, confs.VcpuCount, confs.CpuSockets, confs.VmemSize)
}
func (task *GuestChangeConfigTask) OnGuestStopForChangeConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
task.markStageFailed(ctx, obj.(*models.SGuest), data)
}
func (task *GuestChangeConfigTask) startGuestChangeCpuMemSpec(ctx context.Context, guest *models.SGuest, instanceType string, vcpuCount, cpuSockets int, vmemSize int) {
drv, err := guest.GetDriver()
if err != nil {