From 0b7ddf9e7788958f0ced0de03572af25754324c8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 5 Oct 2011 18:31:55 +0100 Subject: [PATCH] Add new virDomainShutdownFlags API Add a new API virDomainShutdownFlags and define: VIR_DOMAIN_SHUTDOWN_DEFAULT = 0, VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN = (1 << 0), VIR_DOMAIN_SHUTDOWN_GUEST_AGENT = (1 << 1), Also define some flags for the reboot API VIR_DOMAIN_REBOOT_DEFAULT = 0, VIR_DOMAIN_REBOOT_ACPI_POWER_BTN = (1 << 0), VIR_DOMAIN_REBOOT_GUEST_AGENT = (1 << 1), Although these two APIs currently have the same flags, using separate enums allows them to expand separately in the future. Add stub impls of the new API for all existing drivers --- include/libvirt/libvirt.h.in | 15 +++++++ src/driver.h | 5 +++ src/esx/esx_driver.c | 11 ++++- src/libvirt.c | 82 +++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 4 ++ src/libxl/libxl_driver.c | 12 +++++- src/openvz/openvz_driver.c | 1 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 8 +++- src/remote_protocol-structs | 5 +++ src/test/test_driver.c | 11 ++++- src/uml/uml_driver.c | 11 ++++- src/vbox/vbox_tmpl.c | 11 ++++- src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 14 +++++- src/xenapi/xenapi_driver.c | 12 +++++- 16 files changed, 194 insertions(+), 10 deletions(-) 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 */