]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
hypervisor: custom shutdown actions for transient vs persistent VMs
authorDaniel P. Berrangé <berrange@redhat.com>
Fri, 20 Dec 2024 13:56:19 +0000 (13:56 +0000)
committerDaniel P. Berrangé <berrange@redhat.com>
Thu, 20 Mar 2025 14:55:17 +0000 (14:55 +0000)
It may be desirable to treat transient VMs differently from persistent
VMs. For example, while performing managed save on persistent VMs makes
sense, the same not usually true of transient VMs, since by their
nature they will have no config to restore from.

This also lets us fix a long standing problem with incorrectly
attempting to perform managed save on transient VMs.

Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/hypervisor/domain_driver.c
src/hypervisor/domain_driver.h
src/libvirt_private.syms
src/qemu/qemu_driver.c

index 971d23539c62498c7c09c88fff802309006b642b..940a44c4c9869377ebcc986a8a84e47df2bdde90 100644 (file)
 
 VIR_LOG_INIT("hypervisor.domain_driver");
 
+VIR_ENUM_IMPL(virDomainDriverAutoShutdownScope,
+              VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_LAST,
+              "none",
+              "persistent",
+              "transient",
+              "all");
+
 char *
 virDomainDriverGenerateRootHash(const char *drivername,
                                 const char *root)
@@ -722,9 +729,13 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
     int numDomains = 0;
     size_t i;
     virDomainPtr *domains = NULL;
+    g_autofree bool *transient = NULL;
 
-    VIR_DEBUG("Run autoshutdown uri=%s trySave=%d tryShutdown=%d poweroff=%d waitShutdownSecs=%u",
-              cfg->uri, cfg->trySave, cfg->tryShutdown, cfg->poweroff,
+    VIR_DEBUG("Run autoshutdown uri=%s trySave=%s tryShutdown=%s poweroff=%s waitShutdownSecs=%u",
+              cfg->uri,
+              virDomainDriverAutoShutdownScopeTypeToString(cfg->trySave),
+              virDomainDriverAutoShutdownScopeTypeToString(cfg->tryShutdown),
+              virDomainDriverAutoShutdownScopeTypeToString(cfg->poweroff),
               cfg->waitShutdownSecs);
 
     /*
@@ -741,6 +752,25 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
     if (cfg->waitShutdownSecs <= 0)
         cfg->waitShutdownSecs = 30;
 
+    /* We expect the hypervisor driver to enforce this when loading
+     * their config file, but in case some bad setting gets through,
+     * disabling saving of transient VMs since it is a guaranteed
+     * error scenario...
+     */
+    if (cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_ALL ||
+        cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT) {
+        VIR_WARN("auto-shutdown: managed save not supported for transient VMs");
+        cfg->trySave = (cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_ALL ?
+                        VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT :
+                        VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE);
+    }
+
+    /* Short-circuit if all actions are disabled */
+    if (cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE &&
+        cfg->tryShutdown == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE &&
+        cfg->poweroff == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE)
+        return;
+
     if (!(conn = virConnectOpen(cfg->uri)))
         goto cleanup;
 
@@ -750,10 +780,22 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
         goto cleanup;
 
     VIR_DEBUG("Auto shutdown with %d running domains", numDomains);
-    if (cfg->trySave) {
+
+    transient = g_new0(bool, numDomains);
+    for (i = 0; i < numDomains; i++) {
+        if (virDomainIsPersistent(domains[i]) == 0)
+            transient[i] = true;
+    }
+
+    if (cfg->trySave != VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE) {
         g_autofree unsigned int *flags = g_new0(unsigned int, numDomains);
         for (i = 0; i < numDomains; i++) {
             int state;
+
+            if ((transient[i] && cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT) ||
+                (!transient[i] && cfg->trySave == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT))
+                continue;
+
             /*
              * Pause all VMs to make them stop dirtying pages,
              * so save is quicker. We remember if any VMs were
@@ -782,11 +824,16 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
         }
     }
 
-    if (cfg->tryShutdown) {
+    if (cfg->tryShutdown != VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE) {
         GTimer *timer = NULL;
         for (i = 0; i < numDomains; i++) {
             if (domains[i] == NULL)
                 continue;
+
+            if ((transient[i] && cfg->tryShutdown == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT) ||
+                (!transient[i] && cfg->tryShutdown == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT))
+                continue;
+
             if (virDomainShutdown(domains[i]) < 0) {
                 VIR_WARN("auto-shutdown: unable to request graceful shutdown of '%s': %s",
                          domains[i]->name,
@@ -802,6 +849,10 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
                 if (!domains[i])
                     continue;
 
+                if ((transient[i] && cfg->tryShutdown == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT) ||
+                    (!transient[i] && cfg->tryShutdown == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT))
+                    continue;
+
                 if (virDomainIsActive(domains[i]) == 1) {
                     anyRunning = true;
                 } else {
@@ -819,10 +870,15 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg)
         g_timer_destroy(timer);
     }
 
-    if (cfg->poweroff) {
+    if (cfg->poweroff != VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE) {
         for (i = 0; i < numDomains; i++) {
             if (domains[i] == NULL)
                 continue;
+
+            if ((transient[i] && cfg->poweroff == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT) ||
+                (!transient[i] && cfg->poweroff == VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT))
+                continue;
+
             /*
              * NB might fail if we gave up on waiting for
              * virDomainShutdown, but it then completed anyway,
index ff68517edd1a67ca3a04328b893a30cf8850e5ac..6e535ca4444149f136e2bdec47b84a7851605167 100644 (file)
@@ -24,6 +24,7 @@
 #include "virhostdev.h"
 #include "virpci.h"
 #include "virdomainobjlist.h"
+#include "virenum.h"
 
 char *
 virDomainDriverGenerateRootHash(const char *drivername,
@@ -91,11 +92,22 @@ typedef struct _virDomainDriverAutoStartConfig {
 void virDomainDriverAutoStart(virDomainObjList *domains,
                               virDomainDriverAutoStartConfig *cfg);
 
+typedef enum {
+    VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE,
+    VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT,
+    VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_TRANSIENT,
+    VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_ALL,
+
+    VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_LAST,
+} virDomainDriverAutoShutdownScope;
+
+VIR_ENUM_DECL(virDomainDriverAutoShutdownScope);
+
 typedef struct _virDomainDriverAutoShutdownConfig {
     const char *uri;
-    bool trySave;
-    bool tryShutdown;
-    bool poweroff;
+    virDomainDriverAutoShutdownScope trySave;
+    virDomainDriverAutoShutdownScope tryShutdown;
+    virDomainDriverAutoShutdownScope poweroff;
     unsigned int waitShutdownSecs; /* Seconds to wait for VM to shutdown
                                     * before moving onto next action.
                                     * If 0 a default is used (currently 30 secs)
index 4b888c63f1999739d84c8d7209fb718004b309d4..89ef01465e2cd57cfeedbbcae1a468fad1cf856e 100644 (file)
@@ -1650,6 +1650,8 @@ virDomainCgroupSetupVcpuBW;
 # hypervisor/domain_driver.h
 virDomainDriverAddIOThreadCheck;
 virDomainDriverAutoShutdown;
+virDomainDriverAutoShutdownScopeTypeFromString;
+virDomainDriverAutoShutdownScopeTypeToString;
 virDomainDriverAutoStart;
 virDomainDriverDelIOThreadCheck;
 virDomainDriverGenerateMachineName;
index 37d2061df16e37c553c064a490cd3f1976681b31..9d6523cfbca71192db1ddf8a45425c8767610dd5 100644 (file)
@@ -966,9 +966,9 @@ qemuStateStop(void)
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(qemu_driver);
     virDomainDriverAutoShutdownConfig ascfg = {
         .uri = cfg->uri,
-        .trySave = true,
-        .tryShutdown = false,
-        .poweroff = false,
+        .trySave = VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_PERSISTENT,
+        .tryShutdown =  VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE,
+        .poweroff = VIR_DOMAIN_DRIVER_AUTO_SHUTDOWN_SCOPE_NONE
     };
 
     if (!qemu_driver->privileged)