diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 958e5a6b73..5e6e488bc6 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1200,7 +1200,22 @@ virDomainPtr virDomainLookupByUUID (virConnectPtr conn, virDomainPtr virDomainLookupByUUIDString (virConnectPtr conn, const char *uuid); +typedef enum { + VIR_DOMAIN_SHUTDOWN_DEFAULT = 0, /* hypervisor choice */ + VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN = (1 << 0), /* Send ACPI event */ + VIR_DOMAIN_SHUTDOWN_GUEST_AGENT = (1 << 1), /* Use guest agent */ +} virDomainShutdownFlagValues; + int virDomainShutdown (virDomainPtr domain); +int virDomainShutdownFlags (virDomainPtr domain, + unsigned int flags); + +typedef enum { + VIR_DOMAIN_REBOOT_DEFAULT = 0, /* hypervisor choice */ + VIR_DOMAIN_REBOOT_ACPI_POWER_BTN = (1 << 0), /* Send ACPI event */ + VIR_DOMAIN_REBOOT_GUEST_AGENT = (1 << 1), /* Use guest agent */ +} virDomainRebootFlagValues; + int virDomainReboot (virDomainPtr domain, unsigned int flags); int virDomainReset (virDomainPtr domain, diff --git a/src/driver.h b/src/driver.h index 24636a43a2..6222bed166 100644 --- a/src/driver.h +++ b/src/driver.h @@ -793,6 +793,10 @@ typedef int virTypedParameterPtr params, int *nparams, unsigned int flags); +typedef int + (*virDrvDomainShutdownFlags)(virDomainPtr domain, + unsigned int flags); + /** * _virDriver: @@ -829,6 +833,7 @@ struct _virDriver { virDrvDomainSuspend domainSuspend; virDrvDomainResume domainResume; virDrvDomainShutdown domainShutdown; + virDrvDomainShutdownFlags domainShutdownFlags; virDrvDomainReboot domainReboot; virDrvDomainReset domainReset; virDrvDomainDestroy domainDestroy; diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 63cdba573c..f5e1cc73d4 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -1887,7 +1887,7 @@ esxDomainResume(virDomainPtr domain) static int -esxDomainShutdown(virDomainPtr domain) +esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags) { int result = -1; esxPrivate *priv = domain->conn->privateData; @@ -1895,6 +1895,8 @@ esxDomainShutdown(virDomainPtr domain) esxVI_String *propertyNameList = NULL; esxVI_VirtualMachinePowerState powerState; + virCheckFlags(0, -1); + if (esxVI_EnsureSession(priv->primary) < 0) { return -1; } @@ -1928,6 +1930,12 @@ esxDomainShutdown(virDomainPtr domain) } +static int +esxDomainShutdown(virDomainPtr domain) +{ + return esxDomainShutdownFlags(domain, 0); +} + static int esxDomainReboot(virDomainPtr domain, unsigned int flags) @@ -4953,6 +4961,7 @@ static virDriver esxDriver = { .domainSuspend = esxDomainSuspend, /* 0.7.0 */ .domainResume = esxDomainResume, /* 0.7.0 */ .domainShutdown = esxDomainShutdown, /* 0.7.0 */ + .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */ .domainReboot = esxDomainReboot, /* 0.7.0 */ .domainDestroy = esxDomainDestroy, /* 0.7.0 */ .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */ diff --git a/src/libvirt.c b/src/libvirt.c index 7b8adf7f18..96ad3d51df 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3105,15 +3105,88 @@ error: return -1; } +/** + * virDomainShutdownFlags: + * @domain: a domain object + * @flags: bitwise-OR of virDomainShutdownFlagValues + * + * Shutdown a domain, the domain object is still usable thereafter but + * the domain OS is being stopped. Note that the guest OS may ignore the + * request. For guests that react to a shutdown request, the differences + * from virDomainDestroy() are that the guest's disk storage will be in a + * stable state rather than having the (virtual) power cord pulled, and + * this command returns as soon as the shutdown request is issued rather + * than blocking until the guest is no longer running. + * + * If the domain is transient and has any snapshot metadata (see + * virDomainSnapshotNum()), then that metadata will automatically + * be deleted when the domain quits. + * + * If @flags is set to zero, then the hypervisor will choose the + * method of shutdown it considers best. To have greater control + * pass exactly one of the virDomainShutdownFlagValues. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainShutdownFlags(virDomainPtr domain, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + /* At most one of these two flags should be set. */ + if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) && + (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainShutdownFlags) { + int ret; + ret = conn->driver->domainShutdownFlags(domain, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + /** * virDomainReboot: * @domain: a domain object - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virDomainRebootFlagValues * * Reboot a domain, the domain object is still usable there after but * the domain OS is being stopped for a restart. * Note that the guest OS may ignore the request. * + * If @flags is set to zero, then the hypervisor will choose the + * method of shutdown it considers best. To have greater control + * pass exactly one of the virDomainRebootFlagValues. + * + * To use guest agent (VIR_DOMAIN_REBOOT_GUEST_AGENT) the domain XML + * must have configured. + * * Returns 0 in case of success and -1 in case of failure. */ int @@ -3135,6 +3208,13 @@ virDomainReboot(virDomainPtr domain, unsigned int flags) goto error; } + /* At most one of these two flags should be set. */ + if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) && + (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + conn = domain->conn; if (conn->driver->domainReboot) { diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 4ca7216573..e0cbdb448d 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -516,4 +516,8 @@ LIBVIRT_0.9.9 { virDomainSetNumaParameters; } LIBVIRT_0.9.8; +LIBVIRT_0.9.10 { + global: + virDomainShutdownFlags; +} LIBVIRT_0.9.9; # .... define new API here using predicted next version number .... diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index f7f45c70b7..41366e4643 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -1412,13 +1412,15 @@ cleanup: } static int -libxlDomainShutdown(virDomainPtr dom) +libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags) { libxlDriverPrivatePtr driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; libxlDomainObjPrivatePtr priv; + virCheckFlags(0, -1); + libxlDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (!vm) { @@ -1455,6 +1457,13 @@ cleanup: return ret; } +static int +libxlDomainShutdown(virDomainPtr dom) +{ + return libxlDomainShutdownFlags(dom, 0); +} + + static int libxlDomainReboot(virDomainPtr dom, unsigned int flags) { @@ -3857,6 +3866,7 @@ static virDriver libxlDriver = { .domainSuspend = libxlDomainSuspend, /* 0.9.0 */ .domainResume = libxlDomainResume, /* 0.9.0 */ .domainShutdown = libxlDomainShutdown, /* 0.9.0 */ + .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */ .domainReboot = libxlDomainReboot, /* 0.9.0 */ .domainDestroy = libxlDomainDestroy, /* 0.9.0 */ .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */ diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 03bf21a903..b848a888a9 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1693,6 +1693,7 @@ static virDriver openvzDriver = { .domainSuspend = openvzDomainSuspend, /* 0.8.3 */ .domainResume = openvzDomainResume, /* 0.8.3 */ .domainShutdown = openvzDomainShutdown, /* 0.3.1 */ + .domainShutdownFlags = openvzDomainShutdownFlags, /* 0.9.10 */ .domainReboot = openvzDomainReboot, /* 0.3.1 */ .domainDestroy = openvzDomainShutdown, /* 0.3.1 */ .domainDestroyFlags = openvzDomainShutdownFlags, /* 0.9.4 */ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e28840b981..f45a8feb40 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4617,6 +4617,7 @@ static virDriver remote_driver = { .domainSuspend = remoteDomainSuspend, /* 0.3.0 */ .domainResume = remoteDomainResume, /* 0.3.0 */ .domainShutdown = remoteDomainShutdown, /* 0.3.0 */ + .domainShutdownFlags = remoteDomainShutdownFlags, /* 0.9.10 */ .domainReboot = remoteDomainReboot, /* 0.3.0 */ .domainReset = remoteDomainReset, /* 0.9.7 */ .domainDestroy = remoteDomainDestroy, /* 0.3.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 514b0cc08c..6a20ae81d6 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2349,6 +2349,11 @@ struct remote_node_suspend_for_duration_args { unsigned int flags; }; +struct remote_domain_shutdown_flags_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + /*----- Protocol. -----*/ @@ -2654,7 +2659,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_NUMA_PARAMETERS = 254, /* autogen autogen */ REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS = 255, /* skipgen skipgen */ REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256, /* autogen autogen */ - REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258 /* autogen autogen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 275831556d..430d8e4a6c 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1832,6 +1832,10 @@ struct remote_node_suspend_for_duration_args { uint64_t duration; u_int flags; }; +struct remote_domain_shutdown_flags_args { + remote_nonnull_domain dom; + u_int flags; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2090,4 +2094,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS = 255, REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256, REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257, + REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258, }; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index c0b2ca668d..55b889b148 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -1542,13 +1542,16 @@ cleanup: return ret; } -static int testShutdownDomain (virDomainPtr domain) +static int testShutdownDomainFlags(virDomainPtr domain, + unsigned int flags) { testConnPtr privconn = domain->conn->privateData; virDomainObjPtr privdom; virDomainEventPtr event = NULL; int ret = -1; + virCheckFlags(0, -1); + testDriverLock(privconn); privdom = virDomainFindByName(&privconn->domains, domain->name); @@ -1585,6 +1588,11 @@ cleanup: return ret; } +static int testShutdownDomain (virDomainPtr domain) +{ + return testShutdownDomainFlags(domain, 0); +} + /* Similar behaviour as shutdown */ static int testRebootDomain (virDomainPtr domain, unsigned int action ATTRIBUTE_UNUSED) @@ -5523,6 +5531,7 @@ static virDriver testDriver = { .domainSuspend = testPauseDomain, /* 0.1.1 */ .domainResume = testResumeDomain, /* 0.1.1 */ .domainShutdown = testShutdownDomain, /* 0.1.1 */ + .domainShutdownFlags = testShutdownDomainFlags, /* 0.9.10 */ .domainReboot = testRebootDomain, /* 0.1.1 */ .domainDestroy = testDestroyDomain, /* 0.1.1 */ .domainGetOSType = testGetOSType, /* 0.1.9 */ diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 671216e15c..a4cf9452a7 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1513,12 +1513,15 @@ cleanup: } -static int umlDomainShutdown(virDomainPtr dom) { +static int umlDomainShutdownFlags(virDomainPtr dom, + unsigned int flags) { struct uml_driver *driver = dom->conn->privateData; virDomainObjPtr vm; char *info = NULL; int ret = -1; + virCheckFlags(0, -1); + umlDriverLock(driver); vm = virDomainFindByID(&driver->domains, dom->id); umlDriverUnlock(driver); @@ -1544,6 +1547,11 @@ cleanup: return ret; } +static int +umlDomainShutdown(virDomainPtr dom) +{ + return umlDomainShutdownFlags(dom, 0); +} static int umlDomainDestroyFlags(virDomainPtr dom, @@ -2533,6 +2541,7 @@ static virDriver umlDriver = { .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */ .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */ .domainShutdown = umlDomainShutdown, /* 0.5.0 */ + .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */ .domainDestroy = umlDomainDestroy, /* 0.5.0 */ .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */ .domainGetOSType = umlDomainGetOSType, /* 0.5.0 */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 22712d578b..d72043274b 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -1606,7 +1606,8 @@ cleanup: return ret; } -static int vboxDomainShutdown(virDomainPtr dom) { +static int vboxDomainShutdownFlags(virDomainPtr dom, + unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); IMachine *machine = NULL; vboxIID iid = VBOX_IID_INITIALIZER; @@ -1615,6 +1616,8 @@ static int vboxDomainShutdown(virDomainPtr dom) { PRBool isAccessible = PR_FALSE; nsresult rc; + virCheckFlags(0, -1); + vboxIIDFromUUID(&iid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); if (NS_FAILED(rc)) { @@ -1656,6 +1659,11 @@ cleanup: return ret; } +static int vboxDomainShutdown(virDomainPtr dom) { + return vboxDomainShutdownFlags(dom, 0); +} + + static int vboxDomainReboot(virDomainPtr dom, unsigned int flags) { VBOX_OBJECT_CHECK(dom->conn, int, -1); @@ -9112,6 +9120,7 @@ virDriver NAME(Driver) = { .domainSuspend = vboxDomainSuspend, /* 0.6.3 */ .domainResume = vboxDomainResume, /* 0.6.3 */ .domainShutdown = vboxDomainShutdown, /* 0.6.3 */ + .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */ .domainReboot = vboxDomainReboot, /* 0.6.3 */ .domainDestroy = vboxDomainDestroy, /* 0.6.3 */ .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */ diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index a9873ba1a7..56e9d2d704 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -980,6 +980,7 @@ static virDriver vmwareDriver = { .domainSuspend = vmwareDomainSuspend, /* 0.8.7 */ .domainResume = vmwareDomainResume, /* 0.8.7 */ .domainShutdown = vmwareDomainShutdown, /* 0.8.7 */ + .domainShutdownFlags = vmwareDomainShutdownFlags, /* 0.9.10 */ .domainReboot = vmwareDomainReboot, /* 0.8.7 */ .domainDestroy = vmwareDomainShutdown, /* 0.8.7 */ .domainDestroyFlags = vmwareDomainShutdownFlags, /* 0.9.4 */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 520ec03a84..12d7eb0655 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -851,20 +851,29 @@ xenUnifiedDomainResume (virDomainPtr dom) } static int -xenUnifiedDomainShutdown (virDomainPtr dom) +xenUnifiedDomainShutdownFlags(virDomainPtr dom, + unsigned int flags) { GET_PRIVATE(dom->conn); int i; + virCheckFlags(0, -1); + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) if (priv->opened[i] && drivers[i]->xenDomainShutdown && - drivers[i]->xenDomainShutdown (dom) == 0) + drivers[i]->xenDomainShutdown(dom) == 0) return 0; return -1; } +static int +xenUnifiedDomainShutdown(virDomainPtr dom) +{ + return xenUnifiedDomainShutdownFlags(dom, 0); +} + static int xenUnifiedDomainReboot (virDomainPtr dom, unsigned int flags) { @@ -2187,6 +2196,7 @@ static virDriver xenUnifiedDriver = { .domainSuspend = xenUnifiedDomainSuspend, /* 0.0.3 */ .domainResume = xenUnifiedDomainResume, /* 0.0.3 */ .domainShutdown = xenUnifiedDomainShutdown, /* 0.0.3 */ + .domainShutdownFlags = xenUnifiedDomainShutdownFlags, /* 0.9.10 */ .domainReboot = xenUnifiedDomainReboot, /* 0.1.0 */ .domainDestroy = xenUnifiedDomainDestroy, /* 0.0.3 */ .domainDestroyFlags = xenUnifiedDomainDestroyFlags, /* 0.9.4 */ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 78137d48a0..68017bcae9 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -783,12 +783,15 @@ xenapiDomainResume (virDomainPtr dom) * Returns 0 on success or -1 in case of error */ static int -xenapiDomainShutdown (virDomainPtr dom) +xenapiDomainShutdownFlags(virDomainPtr dom, unsigned int flags) { /* vm.clean_shutdown */ xen_vm vm; xen_vm_set *vms; xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + + virCheckFlags(0, -1); + if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) { if (vms->size != 1) { xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, @@ -811,6 +814,12 @@ xenapiDomainShutdown (virDomainPtr dom) return -1; } +static int +xenapiDomainShutdown(virDomainPtr dom) +{ + return xenapiDomainShutdownFlags(dom, 0); +} + /* * xenapiDomainReboot * @@ -1928,6 +1937,7 @@ static virDriver xenapiDriver = { .domainSuspend = xenapiDomainSuspend, /* 0.8.0 */ .domainResume = xenapiDomainResume, /* 0.8.0 */ .domainShutdown = xenapiDomainShutdown, /* 0.8.0 */ + .domainShutdownFlags = xenapiDomainShutdownFlags, /* 0.9.10 */ .domainReboot = xenapiDomainReboot, /* 0.8.0 */ .domainDestroy = xenapiDomainDestroy, /* 0.8.0 */ .domainDestroyFlags = xenapiDomainDestroyFlags, /* 0.9.4 */