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. Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- include/libvirt/libvirt-domain.h | 4 ++ src/driver-hypervisor.h | 10 ++++ src/libvirt-domain.c | 87 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 +++ src/remote/remote_driver.c | 2 + src/remote/remote_protocol.x | 30 ++++++++++- src/remote_protocol-structs | 12 +++++ src/rpc/gendispatch.pl | 4 +- tools/virsh-domain-monitor.c | 7 +++ tools/virsh-domain.c | 39 ++++++++++---- 10 files changed, 189 insertions(+), 12 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 8c86bd8f94..c4e768f26f 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -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: diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 4ce8da078d..c05c71b9fe 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -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; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index b23a3489c5..4e78c687d5 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -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 diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 7a3492d9d7..103f8e6f53 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -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 .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 307f9ca945..c39b8cf676 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -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 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 41c045ff78..4f873cb4cf 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -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 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 4d3dc2d249..6337a082ce 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -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, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 724a6aed6e..f9fae39fb1 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -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;"); diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index fa1c05ac77..f4274f2721 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -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) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 93c34c4971..4f2af7a078 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1158,6 +1158,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} }; @@ -1167,24 +1171,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; } -- 2.48.1