diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index e446f2ae6f..e2e24c559f 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -610,6 +610,9 @@ type ServerStopInput struct { // 是否强制关机 IsForce bool `json:"is_force"` + // 关机等待时间,如果是强制关机,则等待时间为0,如果不设置,默认为30秒 + TimeoutSecs int `json:"timeout_secs"` + // 是否关机停止计费, 若平台不支持停止计费,此参数无作用 // 目前仅阿里云,腾讯云此参数生效 StopCharging bool `json:"stop_charging"` diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index 538715f99f..95bb8d173b 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -358,7 +358,7 @@ func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context !guest.PendingDeleted && !overridePendingDelete && !purge { - return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, false, task.GetTaskId()) + return guest.StartGuestStopTask(ctx, task.GetUserCred(), 0, true, false, task.GetTaskId()) } if host != nil && !host.GetEnabled() && !purge { return errors.Errorf("fail to contact baremetal") diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index f864860a01..1fd3bd6dfa 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -285,7 +285,7 @@ func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Conte host, _ = guest.GetHost() } if host != nil && host.GetEnabled() && host.HostStatus == api.HOST_ONLINE { - return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, false, task.GetTaskId()) + return guest.StartGuestStopTask(ctx, task.GetUserCred(), 0, true, false, task.GetTaskId()) } if host != nil && !jsonutils.QueryBoolean(task.GetParams(), "purge", false) { return fmt.Errorf("fail to contact host") diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 6e7f265589..a06f52a25d 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1184,12 +1184,16 @@ func (self *SGuest) NotifyAdminServerEvent(ctx context.Context, event string, pr notifyclient.SystemNotifyWithCtx(ctx, priority, event, kwargs) } -func (self *SGuest) StartGuestStopTask(ctx context.Context, userCred mcclient.TokenCredential, isForce, stopCharging bool, parentTaskId string) error { +func (self *SGuest) StartGuestStopTask(ctx context.Context, userCred mcclient.TokenCredential, timeoutSecs int, isForce, stopCharging bool, parentTaskId string) error { if len(parentTaskId) == 0 { self.SetStatus(ctx, userCred, api.VM_START_STOP, "") } params := jsonutils.NewDict() - params.Add(jsonutils.NewBool(isForce), "is_force") + if isForce { + params.Add(jsonutils.NewBool(isForce), "is_force") + } else { + params.Add(jsonutils.NewInt(int64(timeoutSecs)), "timeout") + } params.Add(jsonutils.NewBool(stopCharging), "stop_charging") if len(parentTaskId) > 0 { params.Add(jsonutils.JSONTrue, "subtask") @@ -3188,7 +3192,7 @@ func (self *SGuest) PerformStop(ctx context.Context, userCred mcclient.TokenCred if err := self.ValidateEncryption(ctx, userCred); err != nil { return nil, errors.Wrap(httperrors.ErrForbidden, "encryption key not accessible") } - return nil, self.StartGuestStopTask(ctx, userCred, input.IsForce, input.StopCharging, "") + return nil, self.StartGuestStopTask(ctx, userCred, input.TimeoutSecs, input.IsForce, input.StopCharging, "") } return nil, httperrors.NewInvalidStatusError("Cannot stop server in status %s", self.Status) } diff --git a/pkg/compute/tasks/guest_deploy_task.go b/pkg/compute/tasks/guest_deploy_task.go index 72c04c216e..e42082034d 100644 --- a/pkg/compute/tasks/guest_deploy_task.go +++ b/pkg/compute/tasks/guest_deploy_task.go @@ -45,7 +45,7 @@ func (self *GuestDeployTask) OnInit(ctx context.Context, obj db.IStandaloneModel func (self *GuestDeployTask) OnGuestNetworkReady(ctx context.Context, guest *models.SGuest) { self.SetStage("OnDeployWaitServerStop", nil) if jsonutils.QueryBoolean(self.Params, "restart", false) { - guest.StartGuestStopTask(ctx, self.UserCred, false, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 60, false, false, self.GetTaskId()) } else { // Note: have to use LocalTaskRun, run to another place implement OnDeployWaitServerStop taskman.LocalTaskRun(self, func() (jsonutils.JSONObject, error) { diff --git a/pkg/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index aa19fd4ba8..f902fa13f3 100644 --- a/pkg/compute/tasks/guest_rebuild_root_task.go +++ b/pkg/compute/tasks/guest_rebuild_root_task.go @@ -44,7 +44,7 @@ func (self *GuestRebuildRootTask) OnInit(ctx context.Context, obj db.IStandalone guest := obj.(*models.SGuest) if jsonutils.QueryBoolean(self.Params, "need_stop", false) { self.SetStage("OnStopServerComplete", nil) - guest.StartGuestStopTask(ctx, self.UserCred, false, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 60, false, false, self.GetTaskId()) } else { self.StartRebuildRootDisk(ctx, guest) } diff --git a/pkg/compute/tasks/guest_rescue_task.go b/pkg/compute/tasks/guest_rescue_task.go index 32ab0054ae..4932d509f0 100644 --- a/pkg/compute/tasks/guest_rescue_task.go +++ b/pkg/compute/tasks/guest_rescue_task.go @@ -49,7 +49,7 @@ func (self *StartRescueTask) StopServer(ctx context.Context, guest *models.SGues db.OpsLog.LogEvent(guest, db.ACT_STOPPING, nil, self.UserCred) guest.SetStatus(ctx, self.UserCred, api.VM_STOPPING, "StopServer") self.SetStage("OnServerStopComplete", nil) - guest.StartGuestStopTask(ctx, self.UserCred, true, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 0, true, false, self.GetTaskId()) } func (self *StartRescueTask) OnServerStopComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -146,7 +146,7 @@ func (self *StopRescueTask) StopServer(ctx context.Context, guest *models.SGuest db.OpsLog.LogEvent(guest, db.ACT_STOPPING, nil, self.UserCred) guest.SetStatus(ctx, self.UserCred, api.VM_STOPPING, "StopServer") self.SetStage("OnServerStopComplete", nil) - guest.StartGuestStopTask(ctx, self.UserCred, true, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 0, true, false, self.GetTaskId()) } func (self *StopRescueTask) OnServerStopComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { diff --git a/pkg/compute/tasks/guest_reset_task.go b/pkg/compute/tasks/guest_reset_task.go index ee4b671526..b34bc7acab 100644 --- a/pkg/compute/tasks/guest_reset_task.go +++ b/pkg/compute/tasks/guest_reset_task.go @@ -57,7 +57,7 @@ func (self *GuestHardResetTask) OnInit(ctx context.Context, obj db.IStandaloneMo func (self *GuestHardResetTask) StopServer(ctx context.Context, guest *models.SGuest) { guest.SetStatus(ctx, self.UserCred, api.VM_STOPPING, "") self.SetStage("OnServerStopComplete", nil) - guest.StartGuestStopTask(ctx, self.UserCred, false, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 30, false, false, self.GetTaskId()) // logclient.AddActionLogWith(guest, logclient.ACT_VM_RESTART, `{"is_force": true}`, self.UserCred, true) } @@ -81,6 +81,6 @@ type GuestRestartTask struct { func (self *GuestRestartTask) StopServer(ctx context.Context, guest *models.SGuest) { self.SetStage("OnServerStopComplete", nil) isForce := jsonutils.QueryBoolean(self.Params, "is_force", false) - guest.StartGuestStopTask(ctx, self.UserCred, isForce, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.UserCred, 60, isForce, false, self.GetTaskId()) // logclient.AddActionLog(guest, logclient.ACT_VM_RESTART, `{"is_force": false}`, self.UserCred, true) } diff --git a/pkg/compute/tasks/guest_save_image_task.go b/pkg/compute/tasks/guest_save_image_task.go index 7eb3990540..49af38ebb2 100644 --- a/pkg/compute/tasks/guest_save_image_task.go +++ b/pkg/compute/tasks/guest_save_image_task.go @@ -41,7 +41,7 @@ func (self *GuestSaveImageTask) OnInit(ctx context.Context, obj db.IStandaloneMo restart := jsonutils.QueryBoolean(self.Params, "restart", false) if restart && guest.Status != api.VM_READY { self.SetStage("OnStopServerComplete", nil) - guest.StartGuestStopTask(ctx, self.GetUserCred(), false, false, self.GetTaskId()) + guest.StartGuestStopTask(ctx, self.GetUserCred(), 60, false, false, self.GetTaskId()) return } self.OnStopServerComplete(ctx, guest, nil) diff --git a/pkg/compute/tasks/guest_stop_task.go b/pkg/compute/tasks/guest_stop_task.go index 1af0530779..3b2ad7992c 100644 --- a/pkg/compute/tasks/guest_stop_task.go +++ b/pkg/compute/tasks/guest_stop_task.go @@ -89,7 +89,7 @@ type GuestStopAndFreezeTask struct { func (self *GuestStopAndFreezeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { guest := obj.(*models.SGuest) self.SetStage("OnStopGuest", nil) - err := guest.StartGuestStopTask(ctx, self.UserCred, false, false, self.GetTaskId()) + err := guest.StartGuestStopTask(ctx, self.UserCred, 60, false, false, self.GetTaskId()) if err != nil { self.OnStopGuestFailed(ctx, guest, jsonutils.NewString(err.Error())) } diff --git a/pkg/hostman/guestman/guesttasks.go b/pkg/hostman/guestman/guesttasks.go index 1c655c708b..55e62298fb 100644 --- a/pkg/hostman/guestman/guesttasks.go +++ b/pkg/hostman/guestman/guesttasks.go @@ -74,17 +74,17 @@ func NewGuestStopTask(guest *SKVMGuestInstance, ctx context.Context, timeout int func (s *SGuestStopTask) Start() { s.stopping = true + s.startPowerdown = time.Now() if s.IsRunning() && s.IsMonitorAlive() { s.Monitor.SimpleCommand("system_powerdown", s.onPowerdownGuest) - } else { - s.checkGuestRunning() } + s.checkGuestRunning() } func (s *SGuestStopTask) onPowerdownGuest(results string) { //s.ExitCleanup(true) - s.startPowerdown = time.Now() - s.checkGuestRunning() + log.Debugf("system_powerdown callback successfully") + // s.checkGuestRunning() } func (s *SGuestStopTask) checkGuestRunning() {