From fd81683d0a907c42b29a7364b96b605e0e4d0d9f Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Mon, 10 Aug 2026 20:49:33 +0800 Subject: [PATCH 1/2] fix(host): add check dev is nil on guest get dev by addr --- pkg/hostman/guestman/pci.go | 8 +++++++- pkg/hostman/guestman/qemu-kvm.go | 1 + pkg/hostman/guestman/qemu-kvmhelper.go | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/hostman/guestman/pci.go b/pkg/hostman/guestman/pci.go index d6ee4e31c68..c581003c694 100644 --- a/pkg/hostman/guestman/pci.go +++ b/pkg/hostman/guestman/pci.go @@ -343,7 +343,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 == api.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/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index a2dcd483475..372980b346e 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -851,6 +851,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)) } diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index d2c88a39240..ced55fb1582 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -856,6 +856,9 @@ func (s *SKVMGuestInstance) gpusHasVga() 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_VGA_TYPE { return true } @@ -867,6 +870,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_VGA_TYPE || dev.GetDeviceType() == api.GPU_HPC_TYPE { return true } From 7837b7da6bc4eb1338f67a0412d814080ceb0ae1 Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Wed, 12 Aug 2026 15:41:40 +0800 Subject: [PATCH 2/2] fix(region,host): daemon guest add running check --- pkg/apis/compute/guest_metadata.go | 2 ++ pkg/compute/guestdrivers/kvm.go | 6 ++++ pkg/compute/models/guest_actions.go | 7 ++++ .../guestman/guesthandlers/guesthandler.go | 3 +- pkg/hostman/guestman/guestman.go | 33 ++++++++++++++++++- pkg/hostman/guestman/qemu-kvmhelper.go | 4 +++ 6 files changed, 53 insertions(+), 2 deletions(-) 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 584ff5ef1ab..26cff16c7aa 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -253,6 +253,12 @@ func (self *SKVMGuestDriver) RequestStopOnHost(ctx context.Context, guest *model timeout = 0 } 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 31e4b628a93..1835efcdf53 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1106,6 +1106,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) err := self.GetDriver().PerformStart(ctx, userCred, self, kwargs, "") return nil, err @@ -3330,6 +3333,10 @@ 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) + } + // XXX if is force, force stop guest if input.IsForce || utils.IsInStringArray(self.Status, []string{api.VM_RUNNING, api.VM_STOP_FAILED}) { if err := self.ValidateEncryption(ctx, userCred); err != nil { diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 5104e3dac88..26a1ba7b4ad 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -231,11 +231,12 @@ 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 } - return nil, guestman.GetGuestManager().GuestStop(ctx, sid, timeout) + return nil, guestman.GetGuestManager().GuestStop(ctx, sid, timeout, 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 d2d6c8dacb6..dc93d5a6b66 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -56,6 +56,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" @@ -320,6 +321,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 *SKVMGuestInstance) { @@ -963,8 +990,12 @@ func (m *SGuestManager) GuestStart(ctx context.Context, userCred mcclient.TokenC } } -func (m *SGuestManager) GuestStop(ctx context.Context, sid string, timeout int64) error { +func (m *SGuestManager) GuestStop(ctx context.Context, sid string, timeout int64, daemonGuestManualStop bool) error { if guest, ok := m.GetServer(sid); ok { + if daemonGuestManualStop { + guest.Desc.Metadata[compute.DAEMON_GUEST_MANUAL_STOP] = "true" + guest.SaveLiveDesc(guest.Desc) + } hostutils.DelayTaskWithoutReqctx(ctx, guest.ExecStopTask, timeout) return nil } else { diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index ced55fb1582..5f2cca4dc58 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -237,6 +237,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 == "" {