diff --git a/pkg/apis/compute/guest_metadata.go b/pkg/apis/compute/guest_metadata.go index 586de770a78..3f047a2ab27 100644 --- a/pkg/apis/compute/guest_metadata.go +++ b/pkg/apis/compute/guest_metadata.go @@ -24,6 +24,8 @@ const ( DISK_CLONE_TASK_ID = "__disk_clone_task_id" SSH_PORT = "__ssh_port" + + DAEMON_GUEST_MANUAL_STOP = "daemon_guest_manual_stop" ) const BASE_INSTANCE_SNAPSHOT_ID = "__base_instance_snapshot_id" diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index c9937771ad9..031fd2bd822 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -273,6 +273,12 @@ func (self *SKVMGuestDriver) RequestStopOnHost(ctx context.Context, guest *model body.Set("is_force", jsonutils.JSONTrue) } body.Add(jsonutils.NewInt(timeout), "timeout") + if guest.IsDaemon.IsTrue() { + val := guest.GetMetadata(ctx, api.DAEMON_GUEST_MANUAL_STOP, task.GetUserCred()) + if len(val) > 0 { + body.Set("daemon_guest_manual_stop", jsonutils.JSONTrue) + } + } header := self.getTaskRequestHeader(task) diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 1d18e418615..6d615905a6b 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1272,6 +1272,9 @@ func (self *SGuest) PerformStart( } } if self.isAllDisksReady() { + if self.IsDaemon.IsTrue() { + self.SetMetadata(ctx, api.DAEMON_GUEST_MANUAL_STOP, "", userCred) + } kwargs := jsonutils.Marshal(input).(*jsonutils.JSONDict) driver, err := self.GetDriver() if err != nil { @@ -4037,6 +4040,9 @@ func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCr // 关机 func (self *SGuest) PerformStop(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerStopInput) (jsonutils.JSONObject, error) { + if self.IsDaemon.IsTrue() { + self.SetMetadata(ctx, api.DAEMON_GUEST_MANUAL_STOP, true, userCred) + } drv, err := self.GetDriver() if err != nil { return nil, errors.Wrap(err, "GetDriver") diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index b49657b3181..6fc6f5cbecd 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -237,12 +237,13 @@ func guestStart(ctx context.Context, userCred mcclient.TokenCredential, sid stri } func guestStop(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) { + daemonGuestManualStop := jsonutils.QueryBoolean(body, "daemon_guest_manual_stop", false) timeout, err := body.Int("timeout") if err != nil { timeout = 30 } forceStop := jsonutils.QueryBoolean(body, "is_force", false) - return nil, guestman.GetGuestManager().GuestStop(ctx, sid, timeout, forceStop) + return nil, guestman.GetGuestManager().GuestStop(ctx, sid, timeout, forceStop, daemonGuestManualStop) } func guestMonitor(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) { diff --git a/pkg/hostman/guestman/guestman.go b/pkg/hostman/guestman/guestman.go index 19d7229362b..d5ecf1a7f7b 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -62,6 +62,7 @@ import ( "yunion.io/x/onecloud/pkg/hostman/storageman/remotefile" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/util/cgrouputils" "yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset" @@ -503,6 +504,32 @@ func (m *SGuestManager) OnVerifyExistingGuestsSucc(servers []jsonutils.JSONObjec m.RemoveCandidateServer(server) } } + timeutils2.AddTimeout(60*time.Second, func() { m.checkDaemonGuestsIsRunning() }) +} + +func (m *SGuestManager) checkDaemonGuestsIsRunning() { + m.Servers.Range(func(k, v interface{}) bool { + guest := v.(*SKVMGuestInstance) + if !guest.IsDaemon() { + return true + } + if guest.IsRunning() || guest.IsSuspend() { + return true + } + + if guest.StartupTask != nil { + return true + } + if guest.isDaemonGuestManualStop() { + return true + } + if err := guest.StartGuest(context.Background(), auth.AdminCredential(), jsonutils.NewDict()); err != nil { + log.Errorf("checkDaemonGuestsIsRunning start guest %s failed: %s", guest.GetName(), err.Error()) + } + return true + }) + + timeutils2.AddTimeout(60*time.Second, func() { m.checkDaemonGuestsIsRunning() }) } func (m *SGuestManager) RemoveCandidateServer(server GuestRuntimeInstance) { @@ -1185,9 +1212,9 @@ func (m *SGuestManager) GuestStart(ctx context.Context, userCred mcclient.TokenC } } -func (m *SGuestManager) GuestStop(ctx context.Context, sid string, timeout int64, isForce bool) error { +func (m *SGuestManager) GuestStop(ctx context.Context, sid string, timeout int64, isForce, daemonGuestManualStop bool) error { if server, ok := m.GetServer(sid); ok { - if err := server.HandleStop(ctx, timeout, isForce); err != nil { + if err := server.HandleStop(ctx, timeout, isForce, daemonGuestManualStop); err != nil { return errors.Wrap(err, "Do stop") } } else { diff --git a/pkg/hostman/guestman/pci.go b/pkg/hostman/guestman/pci.go index bfa267a7a68..b77d298e7a8 100644 --- a/pkg/hostman/guestman/pci.go +++ b/pkg/hostman/guestman/pci.go @@ -344,7 +344,13 @@ func (s *SKVMGuestInstance) initIsolatedDevices(pciRoot, pciBridge *desc.PCICont manager := s.manager.GetHost().GetIsolatedDeviceManager() for i := 0; i < len(s.Desc.IsolatedDevices); i++ { - dev := manager.GetDeviceByAddr(s.Desc.IsolatedDevices[i].Addr) + dev := manager.GetDeviceByIdent(s.Desc.IsolatedDevices[i].VendorDeviceId, s.Desc.IsolatedDevices[i].Addr, s.Desc.IsolatedDevices[i].MdevId) + if dev == nil { + log.Errorf("failed find dev by %s %s %s", + s.Desc.IsolatedDevices[i].VendorDeviceId, s.Desc.IsolatedDevices[i].Addr, s.Desc.IsolatedDevices[i].MdevId) + continue + } + if s.Desc.IsolatedDevices[i].DevType == compute.USB_TYPE { s.Desc.IsolatedDevices[i].Usb = desc.NewUsbDevice("usb-host", dev.GetQemuId()) s.Desc.IsolatedDevices[i].Usb.Options = dev.GetPassthroughOptions() diff --git a/pkg/hostman/guestman/pod.go b/pkg/hostman/guestman/pod.go index 8f2f58a3357..ef45f80cc3e 100644 --- a/pkg/hostman/guestman/pod.go +++ b/pkg/hostman/guestman/pod.go @@ -606,7 +606,7 @@ func (s *sPodGuestInstance) HandleGuestStart(ctx context.Context, userCred mccli return nil, nil } -func (s *sPodGuestInstance) HandleStop(ctx context.Context, timeout int64, isForce bool) error { +func (s *sPodGuestInstance) HandleStop(ctx context.Context, timeout int64, isForce, daemonGuestManualStop bool) error { hostutils.DelayTask(ctx, func(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { err := s.stopPod(ctx, timeout) if err != nil { diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 1671e8c5ba3..5807b5d5933 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -758,6 +758,7 @@ func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params interfa } if err != nil { + log.Errorf("asyncScriptStart init desc failed %s", err) if ctx != nil && len(appctx.AppContextTaskId(ctx)) >= 0 { hostutils.TaskFailed(ctx, fmt.Sprintf("Async start server failed: %s", err)) } @@ -1988,11 +1989,15 @@ func (s *SKVMGuestInstance) StartGuest(ctx context.Context, userCred mcclient.To return nil } -func (s *SKVMGuestInstance) HandleStop(ctx context.Context, timeout int64, isForce bool) error { +func (s *SKVMGuestInstance) HandleStop(ctx context.Context, timeout int64, isForce, daemonGuestManualStop bool) error { params := &SGuestStopParams{ IsForce: isForce, Timeout: timeout, } + if daemonGuestManualStop { + s.Desc.Metadata[api.DAEMON_GUEST_MANUAL_STOP] = "true" + SaveLiveDesc(s, s.Desc) + } hostutils.DelayTaskWithoutReqctx(ctx, s.ExecStopTask, params) return nil } diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index 9d847ccdbb3..cd4594097d9 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -270,6 +270,10 @@ func (s *SKVMGuestInstance) isDisableAutoMergeSnapshots() bool { return s.Desc.Metadata[api.VM_METADATA_DISABLE_AUTO_MERGE_SNAPSHOT] == "true" } +func (s *SKVMGuestInstance) isDaemonGuestManualStop() bool { + return s.Desc.Metadata[api.DAEMON_GUEST_MANUAL_STOP] == "true" +} + func (s *SKVMGuestInstance) getMachine() string { machine := s.Desc.Machine if machine == "" { @@ -1162,7 +1166,12 @@ func (s *SKVMGuestInstance) startMemCleaner() error { func (s *SKVMGuestInstance) gpusHasVga() bool { for i := 0; i < len(s.Desc.IsolatedDevices); i++ { - if s.Desc.IsolatedDevices[i].GpuType == api.GPU_VGA { + manager := s.manager.GetHost().GetIsolatedDeviceManager() + dev := manager.GetDeviceByAddr(s.Desc.IsolatedDevices[i].Addr) + if dev == nil { + continue + } + if dev.GetDeviceType() == api.GPU_VGA { return true } } @@ -1173,6 +1182,9 @@ func (s *SKVMGuestInstance) hasGPU() bool { manager := s.manager.GetHost().GetIsolatedDeviceManager() for i := 0; i < len(s.Desc.IsolatedDevices); i++ { dev := manager.GetDeviceByAddr(s.Desc.IsolatedDevices[i].Addr) + if dev == nil { + continue + } if dev.GetDeviceType() == api.GPU_TYPE { return true } diff --git a/pkg/hostman/guestman/runtime.go b/pkg/hostman/guestman/runtime.go index e6af41464a1..4e543af9df8 100644 --- a/pkg/hostman/guestman/runtime.go +++ b/pkg/hostman/guestman/runtime.go @@ -72,7 +72,7 @@ type GuestRuntimeInstance interface { PostUploadStatus(resp *computeapi.HostUploadGuestStatusInput, reason string) HandleGuestStart(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject) (jsonutils.JSONObject, error) - HandleStop(ctx context.Context, timeout int64, isForce bool) error + HandleStop(ctx context.Context, timeout int64, isForce, daemonGuestManualStop bool) error LoadDesc() error PostLoad(m *SGuestManager) error