]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
src: add new APIs for marking a domain to autostart once
authorDaniel P. Berrangé <berrange@redhat.com>
Fri, 20 Dec 2024 10:55:30 +0000 (10:55 +0000)
committerDaniel P. Berrangé <berrange@redhat.com>
Thu, 20 Mar 2025 14:55:17 +0000 (14:55 +0000)
When a domain is marked for autostart, it will be started on every
subsequent host OS boot. There may be times when it is desirable to
mark a domain to be autostarted, on the next boot only.

Thus we add virDomainSetAutostartOnce / virDomainGetAutostartOnce.

An alternative would have been to overload the existing
virDomainSetAutostart method, to accept values '1' or '2' for
the autostart flag. This was not done because it is expected
that language bindings will have mapped the current autostart
flag to a boolean, and thus turning it into an enum would create
a compatibility problem.

A further alternative would have been to create a new method
virDomainSetAutostartFlags, with a VIR_DOMAIN_AUTOSTART_ONCE
flag defined. This was not done because it is felt desirable
to clearly separate the two flags. Setting the "once" flag
should not interfere with existing autostart setting, whether
it is enabled or disabled currently.

The 'virsh autostart' command, however, is still overloaded
by just adding a --once flag, while current state is added
to 'virsh dominfo'.

No ability to filter by 'autostart once' status is added to
the domain list APIs. The most common use of autostart once
will be to automatically set it on host shutdown, and it be
cleared on host startup. Thus there would rarely be scenarios
in which a running app will need to filter on this new flag.

Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
include/libvirt/libvirt-domain.h
src/driver-hypervisor.h
src/libvirt-domain.c
src/libvirt_public.syms
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
src/rpc/gendispatch.pl
tools/virsh-domain-monitor.c
tools/virsh-domain.c

index 8c86bd8f9480d5b84e955b5f667509db9c0e2be0..c4e768f26fbd2520152c9522041286557755c114 100644 (file)
@@ -2429,6 +2429,10 @@ int                     virDomainGetAutostart   (virDomainPtr domain,
                                                  int *autostart);
 int                     virDomainSetAutostart   (virDomainPtr domain,
                                                  int autostart);
+int                     virDomainGetAutostartOnce(virDomainPtr domain,
+                                                  int *autostart);
+int                     virDomainSetAutostartOnce(virDomainPtr domain,
+                                                  int autostart);
 
 /**
  * virVcpuState:
index 4ce8da078dbd3bb6916ed0da4efe4d69af8188c4..c05c71b9fe007a7362b3c382cb07ae6667421361 100644 (file)
@@ -478,6 +478,14 @@ typedef int
 (*virDrvDomainSetAutostart)(virDomainPtr domain,
                             int autostart);
 
+typedef int
+(*virDrvDomainGetAutostartOnce)(virDomainPtr domain,
+                                int *autostart);
+
+typedef int
+(*virDrvDomainSetAutostartOnce)(virDomainPtr domain,
+                                int autostart);
+
 typedef char *
 (*virDrvDomainGetSchedulerType)(virDomainPtr domain,
                                 int *nparams);
@@ -1564,6 +1572,8 @@ struct _virHypervisorDriver {
     virDrvDomainDetachDeviceAlias domainDetachDeviceAlias;
     virDrvDomainGetAutostart domainGetAutostart;
     virDrvDomainSetAutostart domainSetAutostart;
+    virDrvDomainGetAutostartOnce domainGetAutostartOnce;
+    virDrvDomainSetAutostartOnce domainSetAutostartOnce;
     virDrvDomainGetSchedulerType domainGetSchedulerType;
     virDrvDomainGetSchedulerParameters domainGetSchedulerParameters;
     virDrvDomainGetSchedulerParametersFlags domainGetSchedulerParametersFlags;
index b23a3489c5e61e84d692645eb4b9ce90bd13eefa..4e78c687d5c4dd19b9a0cc35d47a26f862720e3c 100644 (file)
@@ -7344,6 +7344,93 @@ virDomainSetAutostart(virDomainPtr domain,
 }
 
 
+/**
+ * virDomainGetAutostartOnce:
+ * @domain: a domain object
+ * @autostart: the value returned
+ *
+ * Provides a boolean value indicating whether the domain
+ * is configured to be automatically started the next time
+ * the host machine boots only.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ *
+ * Since: 11.2.0
+ */
+int
+virDomainGetAutostartOnce(virDomainPtr domain,
+                          int *autostart)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "autostart=%p", autostart);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(autostart, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetAutostartOnce) {
+        int ret;
+        ret = conn->driver->domainGetAutostartOnce(domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetAutostartOnce:
+ * @domain: a domain object
+ * @autostart: whether the domain should be automatically started 0 or 1
+ *
+ * Configure the domain to be automatically started
+ * the next time the host machine boots only.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ *
+ * Since: 11.2.0
+ */
+int
+virDomainSetAutostartOnce(virDomainPtr domain,
+                          int autostart)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "autostart=%d", autostart);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainSetAutostartOnce) {
+        int ret;
+        ret = conn->driver->domainSetAutostartOnce(domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
 /**
  * virDomainInjectNMI:
  * @domain: pointer to domain object, or NULL for Domain0
index 7a3492d9d7e36df9d84c30cdb93379929c66535d..103f8e6f53ff5463cbab1b39c71095ce42d1aae9 100644 (file)
@@ -948,4 +948,10 @@ LIBVIRT_10.2.0 {
         virDomainGraphicsReload;
 } LIBVIRT_10.1.0;
 
+LIBVIRT_11.2.0 {
+    global:
+        virDomainGetAutostartOnce;
+        virDomainSetAutostartOnce;
+} LIBVIRT_10.2.0;
+
 # .... define new API here using predicted next version number ....
index 307f9ca9450b966988d47ecfd65065f1b59c315e..c39b8cf67614806eb607080d819960ad2f7dbc96 100644 (file)
@@ -7672,6 +7672,8 @@ static virHypervisorDriver hypervisor_driver = {
     .domainDetachDeviceAlias = remoteDomainDetachDeviceAlias, /* 4.4.0 */
     .domainGetAutostart = remoteDomainGetAutostart, /* 0.3.0 */
     .domainSetAutostart = remoteDomainSetAutostart, /* 0.3.0 */
+    .domainGetAutostartOnce = remoteDomainGetAutostartOnce, /* 11.2.0 */
+    .domainSetAutostartOnce = remoteDomainSetAutostartOnce, /* 11.2.0 */
     .domainGetSchedulerType = remoteDomainGetSchedulerType, /* 0.3.0 */
     .domainGetSchedulerParameters = remoteDomainGetSchedulerParameters, /* 0.3.0 */
     .domainGetSchedulerParametersFlags = remoteDomainGetSchedulerParametersFlags, /* 0.9.2 */
index 41c045ff784f02e0c7c2ae27b99c95cf59e1fc14..4f873cb4cfbde0e1ce9de902a35d05aeb27f9fd2 100644 (file)
@@ -3973,6 +3973,20 @@ struct remote_domain_fd_associate_args {
     remote_nonnull_string name;
     unsigned int flags;
 };
+
+struct remote_domain_get_autostart_once_args {
+    remote_nonnull_domain dom;
+};
+
+struct remote_domain_get_autostart_once_ret {
+    int autostart;
+};
+
+struct remote_domain_set_autostart_once_args {
+    remote_nonnull_domain dom;
+    int autostart;
+};
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -7048,5 +7062,19 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:write
      */
-    REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448
+    REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448,
+
+    /**
+     * @generate: both
+     * @priority: high
+     * @acl: domain:read
+     */
+    REMOTE_PROC_DOMAIN_GET_AUTOSTART_ONCE = 449,
+
+    /**
+     * @generate: both
+     * @priority: high
+     * @acl: domain:write
+     */
+    REMOTE_PROC_DOMAIN_SET_AUTOSTART_ONCE = 450
 };
index ed7e2fbcb0d8b9148b19ef9ae88e138efadbb8ba..2541347c22ed58ec6b4b82499e1b29ead75249a0 100644 (file)
@@ -3306,6 +3306,16 @@ struct remote_domain_fd_associate_args {
         remote_nonnull_string      name;
         u_int                      flags;
 };
+struct remote_domain_get_autostart_once_args {
+        remote_nonnull_domain      dom;
+};
+struct remote_domain_get_autostart_once_ret {
+        int                        autostart;
+};
+struct remote_domain_set_autostart_once_args {
+        remote_nonnull_domain      dom;
+        int                        autostart;
+};
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3755,4 +3765,6 @@ enum remote_procedure {
         REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446,
         REMOTE_PROC_NODE_DEVICE_UPDATE = 447,
         REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448,
+        REMOTE_PROC_DOMAIN_GET_AUTOSTART_ONCE = 449,
+        REMOTE_PROC_DOMAIN_SET_AUTOSTART_ONCE = 450,
 };
index 724a6aed6e33d4c1fc64164aff223e44da4d9405..f9fae39fb1d612dc9a2227aa5e7be4154fc14725 100755 (executable)
@@ -839,7 +839,7 @@ elsif ($mode eq "server") {
                     push(@ret_list, "ret->$1 = $1;");
                     $single_ret_var = $1;
 
-                    if ($call->{ProcName} =~ m/GetAutostart$/) {
+                    if ($call->{ProcName} =~ m/GetAutostart(Once)?$/) {
                         $single_ret_by_ref = 1;
                     } else {
                         $single_ret_by_ref = 0;
@@ -1650,7 +1650,7 @@ elsif ($mode eq "client") {
                 } elsif ($ret_member =~ m/^int (\S+);/) {
                     my $arg_name = $1;
 
-                    if ($call->{ProcName} =~ m/GetAutostart$/) {
+                    if ($call->{ProcName} =~ m/GetAutostart(Once)?$/) {
                         push(@args_list, "int *$arg_name");
                         push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;");
                         push(@ret_list, "rv = 0;");
index fa1c05ac77c9fbd88ed6dbacb7f51cb5d74bca41..f4274f2721e95032d4167db6676b95b62388537a 100644 (file)
@@ -1236,6 +1236,13 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd)
         vshPrint(ctl, "%-15s %s\n", _("Autostart:"),
                  autostart ? _("enable") : _("disable"));
     }
+    /* Check and display whether the domain autostarts next boot or not */
+    if (!virDomainGetAutostartOnce(dom, &autostart)) {
+        vshPrint(ctl, "%-15s %s\n", _("Autostart Once:"),
+                 autostart ? _("enable") : _("disable"));
+    } else {
+        vshResetLibvirtError();
+    }
 
     has_managed_save = virDomainHasManagedSaveImage(dom, 0);
     if (has_managed_save < 0)
index 7624cb90fe7604e552128516586aa12e8f0c894c..ae068eec4372ce4a6f6ad9dd84f478e104930f29 100644 (file)
@@ -1157,6 +1157,10 @@ static const vshCmdOptDef opts_autostart[] = {
      .type = VSH_OT_BOOL,
      .help = N_("disable autostarting")
     },
+    {.name = "once",
+     .type = VSH_OT_BOOL,
+     .help = N_("control next boot state")
+    },
     {.name = NULL}
 };
 
@@ -1166,24 +1170,41 @@ cmdAutostart(vshControl *ctl, const vshCmd *cmd)
     g_autoptr(virshDomain) dom = NULL;
     const char *name;
     int autostart;
+    int once;
 
     if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
         return false;
 
     autostart = !vshCommandOptBool(cmd, "disable");
+    once = vshCommandOptBool(cmd, "once");
+
+    if (once) {
+        if (virDomainSetAutostartOnce(dom, autostart) < 0) {
+            if (autostart)
+                vshError(ctl, _("Failed to mark domain '%1$s' as autostarted on next boot"), name);
+            else
+                vshError(ctl, _("Failed to unmark domain '%1$s' as autostarted on next boot"), name);
+            return false;
+        }
 
-    if (virDomainSetAutostart(dom, autostart) < 0) {
         if (autostart)
-            vshError(ctl, _("Failed to mark domain '%1$s' as autostarted"), name);
+            vshPrintExtra(ctl, _("Domain '%1$s' marked as autostarted on next boot\n"), name);
         else
-            vshError(ctl, _("Failed to unmark domain '%1$s' as autostarted"), name);
-        return false;
-    }
+            vshPrintExtra(ctl, _("Domain '%1$s' unmarked as autostarted on next boot\n"), name);
+    } else {
+        if (virDomainSetAutostart(dom, autostart) < 0) {
+            if (autostart)
+                vshError(ctl, _("Failed to mark domain '%1$s' as autostarted"), name);
+            else
+                vshError(ctl, _("Failed to unmark domain '%1$s' as autostarted"), name);
+            return false;
+        }
 
-    if (autostart)
-        vshPrintExtra(ctl, _("Domain '%1$s' marked as autostarted\n"), name);
-    else
-        vshPrintExtra(ctl, _("Domain '%1$s' unmarked as autostarted\n"), name);
+        if (autostart)
+            vshPrintExtra(ctl, _("Domain '%1$s' marked as autostarted\n"), name);
+        else
+            vshPrintExtra(ctl, _("Domain '%1$s' unmarked as autostarted\n"), name);
+    }
 
     return true;
 }