Parallels Cloud Server is a cloud-ready virtualization solution that allows users to simultaneously run multiple virtual machines and containers on the same physical server. More information can be found here: http://www.parallels.com/products/pcs/ Also beta version of Parallels Cloud Server can be downloaded there. Signed-off-by: Dmitry Guryanov <dguryanov@xxxxxxxxxxxxx> --- Changes in v10: * change URI to parallels:///session * don't fail if prlctl command isn't available * remove domainEventState from _parallelsConn configure.ac | 61 ++++++--- docs/drvparallels.html.in | 28 ++++ include/libvirt/virterror.h | 1 + libvirt.spec.in | 9 +- mingw-libvirt.spec.in | 6 + po/POTFILES.in | 1 + src/Makefile.am | 13 ++ src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 1 + src/driver.h | 1 + src/libvirt.c | 9 ++ src/parallels/parallels_driver.c | 275 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_driver.h | 28 ++++ src/util/virterror.c | 3 +- 14 files changed, 417 insertions(+), 22 deletions(-) create mode 100644 docs/drvparallels.html.in create mode 100644 src/parallels/parallels_driver.c create mode 100644 src/parallels/parallels_driver.h diff --git a/configure.ac b/configure.ac index 3cc7b3c..400ac3b 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,8 @@ AC_ARG_WITH([esx], AC_HELP_STRING([--with-esx], [add ESX support @<:@default=check@:>@]),[],[with_esx=check]) AC_ARG_WITH([hyperv], AC_HELP_STRING([--with-hyperv], [add Hyper-V support @<:@default=check@:>@]),[],[with_hyperv=check]) +AC_ARG_WITH([parallels], + AC_HELP_STRING([--with-parallels], [add Parallels Cloud Server support @<:@default=check@:>@]),[],[with_parallels=check]) AC_ARG_WITH([test], AC_HELP_STRING([--with-test], [add test driver support @<:@default=yes@:>@]),[],[with_test=yes]) AC_ARG_WITH([remote], @@ -788,6 +790,26 @@ fi AM_CONDITIONAL([WITH_LXC], [test "$with_lxc" = "yes"]) dnl +dnl Checks for the Parallels driver +dnl + +if test "$with_parallels" = "check"; then + with_parallels=$with_linux + if test ! $host_cpu = 'x86_64'; then + with_parallels=no + fi +fi + +if test "$with_parallels" = "yes" && test "$with_linux" = "no"; then + AC_MSG_ERROR([The Parallels driver can be enabled on Linux only.]) +fi + +if test "$with_parallels" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_PARALLELS], 1, [whether Parallels driver is enabled]) +fi +AM_CONDITIONAL([WITH_PARALLELS], [test "$with_parallels" = "yes"]) + +dnl dnl check for shell that understands <> redirection without truncation, dnl needed by src/qemu/qemu_monitor_{text,json}.c. dnl @@ -2824,25 +2846,26 @@ AC_MSG_NOTICE([=====================]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Drivers]) AC_MSG_NOTICE([]) -AC_MSG_NOTICE([ Xen: $with_xen]) -AC_MSG_NOTICE([ QEMU: $with_qemu]) -AC_MSG_NOTICE([ UML: $with_uml]) -AC_MSG_NOTICE([ OpenVZ: $with_openvz]) -AC_MSG_NOTICE([ VMware: $with_vmware]) -AC_MSG_NOTICE([ VBox: $with_vbox]) -AC_MSG_NOTICE([ XenAPI: $with_xenapi]) -AC_MSG_NOTICE([xenlight: $with_libxl]) -AC_MSG_NOTICE([ LXC: $with_lxc]) -AC_MSG_NOTICE([ PHYP: $with_phyp]) -AC_MSG_NOTICE([ ESX: $with_esx]) -AC_MSG_NOTICE([ Hyper-V: $with_hyperv]) -AC_MSG_NOTICE([ Test: $with_test]) -AC_MSG_NOTICE([ Remote: $with_remote]) -AC_MSG_NOTICE([ Network: $with_network]) -AC_MSG_NOTICE([Libvirtd: $with_libvirtd]) -AC_MSG_NOTICE([ netcf: $with_netcf]) -AC_MSG_NOTICE([ macvtap: $with_macvtap]) -AC_MSG_NOTICE([virtport: $with_virtualport]) +AC_MSG_NOTICE([ Xen: $with_xen]) +AC_MSG_NOTICE([ QEMU: $with_qemu]) +AC_MSG_NOTICE([ UML: $with_uml]) +AC_MSG_NOTICE([ OpenVZ: $with_openvz]) +AC_MSG_NOTICE([ VMware: $with_vmware]) +AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) +AC_MSG_NOTICE([ xenlight: $with_libxl]) +AC_MSG_NOTICE([ LXC: $with_lxc]) +AC_MSG_NOTICE([ PHYP: $with_phyp]) +AC_MSG_NOTICE([ ESX: $with_esx]) +AC_MSG_NOTICE([ Hyper-V: $with_hyperv]) +AC_MSG_NOTICE([Parallels: $with_parallels]) +AC_MSG_NOTICE([ Test: $with_test]) +AC_MSG_NOTICE([ Remote: $with_remote]) +AC_MSG_NOTICE([ Network: $with_network]) +AC_MSG_NOTICE([ Libvirtd: $with_libvirtd]) +AC_MSG_NOTICE([ netcf: $with_netcf]) +AC_MSG_NOTICE([ macvtap: $with_macvtap]) +AC_MSG_NOTICE([ virtport: $with_virtualport]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Storage Drivers]) AC_MSG_NOTICE([]) diff --git a/docs/drvparallels.html.in b/docs/drvparallels.html.in new file mode 100644 index 0000000..40a0fe5 --- /dev/null +++ b/docs/drvparallels.html.in @@ -0,0 +1,28 @@ +<html><body> + <h1>Parallels Cloud Server driver</h1> + <ul id="toc"></ul> + <p> + The libvirt Parallels driver can manage Parallels Cloud Server starting from version 6.0. + </p> + + + <h2><a name="project">Project Links</a></h2> + <ul> + <li> + The <a href="http://www.parallels.com/products/server/baremetal/sp/">Parallels Cloud Server</a> Virtualization Solution. + </li> + </ul> + + + <h2><a name="uri">Connections to the Parallels Cloud Server driver</a></h2> + <p> + The libvirt Parallels driver is a single-instance privileged driver, with a driver name of 'parallels'. Some example connection URIs for the libvirt driver are: + </p> +<pre> +parallels:///default (local access) +parallels+unix:///default (local access) +parallels://example.com/default (remote access, TLS/x509) +parallels+tcp://example.com/default (remote access, SASl/Kerberos) +parallels+ssh://root@xxxxxxxxxxx/default (remote access, SSH tunnelled) +</pre> +</body></html> diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 02b4c57..ad8e101 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -109,6 +109,7 @@ typedef enum { VIR_FROM_URI = 45, /* Error from URI handling */ VIR_FROM_AUTH = 46, /* Error from auth handling */ VIR_FROM_DBUS = 47, /* Error from DBus */ + VIR_FROM_PARALLELS = 48, /* Error from Parallels */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/libvirt.spec.in b/libvirt.spec.in index cfcfc1c..c642f80 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -67,6 +67,7 @@ %define with_esx 0%{!?_without_esx:1} %define with_hyperv 0%{!?_without_hyperv:1} %define with_xenapi 0%{!?_without_xenapi:1} +%define with_parallels 0%{!?_without_parallels:1} # Then the secondary host drivers, which run inside libvirtd %define with_network 0%{!?_without_network:%{server_drivers}} @@ -136,6 +137,7 @@ %define with_xenapi 0 %define with_libxl 0 %define with_hyperv 0 +%define with_parallels 0 %endif # Fedora 17 / RHEL-7 are first where we use systemd. Although earlier @@ -1068,6 +1070,10 @@ of recent versions of Linux (and other OSes). %define _without_vmware --without-vmware %endif +%if ! %{with_parallels} +%define _without_parallels --without-parallels +%endif + %if ! %{with_polkit} %define _without_polkit --without-polkit %endif @@ -1210,6 +1216,7 @@ autoreconf -if %{?_without_esx} \ %{?_without_hyperv} \ %{?_without_vmware} \ + %{?_without_parallels} \ %{?_without_network} \ %{?_with_rhel5_api} \ %{?_without_storage_fs} \ @@ -1401,7 +1408,7 @@ fi /sbin/chkconfig --add libvirtd if [ "$1" -ge "1" ]; then - /sbin/service libvirtd condrestart > /dev/null 2>&1 + /sbin/service libvirtd condrestart > /dev/null 2>&1 fi %endif diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in index d2a8cf3..4695895 100644 --- a/mingw-libvirt.spec.in +++ b/mingw-libvirt.spec.in @@ -13,6 +13,7 @@ # missing libwsman, so can't build hyper-v %define with_hyperv 0%{!?_without_hyperv:0} %define with_xenapi 0%{!?_without_xenapi:1} +%define with_parallels 0%{!?_without_parallels:0} # RHEL ships ESX but not PowerHypervisor, HyperV, or libxenserver (xenapi) %if 0%{?rhel} @@ -125,6 +126,10 @@ MinGW Windows libvirt virtualization library, static version. %define _without_xenapi --without-xenapi %endif +%if ! %{with_parallels} +%define _without_parallels --without-parallels +%endif + %if 0%{?enable_autotools} autoreconf -if %endif @@ -148,6 +153,7 @@ autoreconf -if %{?_without_esx} \ %{?_without_hyperv} \ --without-vmware \ + --without-parallels \ --without-netcf \ --without-audit \ --without-dtrace diff --git a/po/POTFILES.in b/po/POTFILES.in index 2b0bae5..01c74cc 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -65,6 +65,7 @@ src/nwfilter/nwfilter_learnipaddr.c src/openvz/openvz_conf.c src/openvz/openvz_driver.c src/openvz/openvz_util.c +src/parallels/parallels_driver.c src/phyp/phyp_driver.c src/qemu/qemu_agent.c src/qemu/qemu_bridge_filter.c diff --git a/src/Makefile.am b/src/Makefile.am index da3d0cd..fe7a9b7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -566,6 +566,10 @@ HYPERV_DRIVER_EXTRA_DIST = \ hyperv/hyperv_wmi_generator.py \ $(HYPERV_DRIVER_GENERATED) +PARALLELS_DRIVER_SOURCES = \ + parallels/parallels_driver.h \ + parallels/parallels_driver.c + NETWORK_DRIVER_SOURCES = \ network/bridge_driver.h network/bridge_driver.c @@ -1004,6 +1008,14 @@ libvirt_driver_hyperv_la_LIBADD = $(OPENWSMAN_LIBS) libvirt_driver_hyperv_la_SOURCES = $(HYPERV_DRIVER_SOURCES) endif +if WITH_PARALLELS +noinst_LTLIBRARIES += libvirt_driver_parallels.la +libvirt_la_BUILT_LIBADD += libvirt_driver_parallels.la +libvirt_driver_parallels_la_CFLAGS = \ + -I$(top_srcdir)/src/conf $(AM_CFLAGS) +libvirt_driver_parallels_la_SOURCES = $(PARALLELS_DRIVER_SOURCES) +endif + if WITH_NETWORK noinst_LTLIBRARIES += libvirt_driver_network_impl.la libvirt_driver_network_la_SOURCES = @@ -1215,6 +1227,7 @@ EXTRA_DIST += \ $(ESX_DRIVER_EXTRA_DIST) \ $(HYPERV_DRIVER_SOURCES) \ $(HYPERV_DRIVER_EXTRA_DIST) \ + $(PARALLELS_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 143d92e..ad391d2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -93,7 +93,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST, "vmware", "hyperv", "vbox", - "phyp") + "phyp", + "parallels") VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST, "fd", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bc02caf..0db1693 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -160,6 +160,7 @@ enum virDomainVirtType { VIR_DOMAIN_VIRT_HYPERV, VIR_DOMAIN_VIRT_VBOX, VIR_DOMAIN_VIRT_PHYP, + VIR_DOMAIN_VIRT_PARALLELS, VIR_DOMAIN_VIRT_LAST, }; diff --git a/src/driver.h b/src/driver.h index 46d9846..aab9766 100644 --- a/src/driver.h +++ b/src/driver.h @@ -31,6 +31,7 @@ typedef enum { VIR_DRV_VMWARE = 13, VIR_DRV_LIBXL = 14, VIR_DRV_HYPERV = 15, + VIR_DRV_PARALLELS = 16, } virDrvNo; diff --git a/src/libvirt.c b/src/libvirt.c index 8e789be..3704633 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -84,6 +84,9 @@ #ifdef WITH_XENAPI # include "xenapi/xenapi_driver.h" #endif +#ifdef WITH_PARALLELS +# include "parallels/parallels_driver.h" +#endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -455,6 +458,9 @@ virInitialize(void) #ifdef WITH_XENAPI if (xenapiRegister() == -1) return -1; #endif +#ifdef WITH_PARALLELS + if (parallelsRegister() == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -1156,6 +1162,9 @@ do_open (const char *name, #ifndef WITH_XENAPI STRCASEEQ(ret->uri->scheme, "xenapi") || #endif +#ifndef WITH_PARALLELS + STRCASEEQ(ret->uri->scheme, "parallels") || +#endif false)) { virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED, __FILE__, __FUNCTION__, __LINE__, diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c new file mode 100644 index 0000000..20205e8 --- /dev/null +++ b/src/parallels/parallels_driver.c @@ -0,0 +1,275 @@ +/* + * parallels_driver.c: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2012 Parallels, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/poll.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/utsname.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/statvfs.h> + +#include "datatypes.h" +#include "virterror_internal.h" +#include "memory.h" +#include "util.h" +#include "logging.h" +#include "command.h" +#include "configmake.h" +#include "storage_file.h" +#include "storage_conf.h" +#include "nodeinfo.h" +#include "json.h" +#include "domain_conf.h" + +#include "parallels_driver.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +#define PRLCTL "prlctl" +#define PARALLELS_DEFAULT_ARCH "x86_64" + +struct _parallelsConn { + virMutex lock; + virDomainObjList domains; + virStoragePoolObjList pools; + virCapsPtr caps; +}; + +typedef struct _parallelsConn parallelsConn; +typedef struct _parallelsConn *parallelsConnPtr; + +static int parallelsClose(virConnectPtr conn); + +static void +parallelsDriverLock(parallelsConnPtr driver) +{ + virMutexLock(&driver->lock); +} + +static void +parallelsDriverUnlock(parallelsConnPtr driver) +{ + virMutexUnlock(&driver->lock); +} + +static int +parallelsDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED) +{ + return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; +} + +static virCapsPtr +parallelsBuildCapabilities(void) +{ + virCapsPtr caps; + virCapsGuestPtr guest; + struct utsname utsname; + uname(&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) + goto no_memory; + + if (nodeCapsInitNUMA(caps) < 0) + goto no_memory; + + virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { + 0x42, 0x1C, 0x00}); + + if ((guest = virCapabilitiesAddGuest(caps, "hvm", PARALLELS_DEFAULT_ARCH, + 64, "parallels", + NULL, 0, NULL)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "parallels", NULL, NULL, 0, NULL) == NULL) + goto no_memory; + + caps->defaultConsoleTargetType = parallelsDefaultConsoleType; + return caps; + + no_memory: + virReportOOMError(); + virCapabilitiesFree(caps); + return NULL; +} + +static char * +parallelsGetCapabilities(virConnectPtr conn) +{ + parallelsConnPtr privconn = conn->privateData; + char *xml; + + parallelsDriverLock(privconn); + if ((xml = virCapabilitiesFormatXML(privconn->caps)) == NULL) + virReportOOMError(); + parallelsDriverUnlock(privconn); + return xml; +} + +static int +parallelsOpenDefault(virConnectPtr conn) +{ + parallelsConnPtr privconn; + + if (VIR_ALLOC(privconn) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + if (virMutexInit(&privconn->lock) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + goto error; + } + + if (!(privconn->caps = parallelsBuildCapabilities())) + goto error; + + if (virDomainObjListInit(&privconn->domains) < 0) + goto error; + + conn->privateData = privconn; + + return VIR_DRV_OPEN_SUCCESS; + + error: + virDomainObjListDeinit(&privconn->domains); + virCapabilitiesFree(privconn->caps); + virStoragePoolObjListFree(&privconn->pools); + VIR_FREE(privconn); + return VIR_DRV_OPEN_ERROR; +} + +static virDrvOpenStatus +parallelsOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret; + parallelsConnPtr privconn; + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (!conn->uri) + return VIR_DRV_OPEN_DECLINED; + + if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "parallels")) + return VIR_DRV_OPEN_DECLINED; + + /* Remote driver should handle these. */ + if (conn->uri->server) + return VIR_DRV_OPEN_DECLINED; + + /* From this point on, the connection is for us. */ + if ( + conn->uri->path[0] == '\0' || + (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("parallelsOpen: supply a path or use " + "parallels:///session")); + return VIR_DRV_OPEN_ERROR; + } + + if (STREQ(conn->uri->path, "/session")) + ret = parallelsOpenDefault(conn); + else + return VIR_DRV_OPEN_DECLINED; + + if (ret != VIR_DRV_OPEN_SUCCESS) + return ret; + + privconn = conn->privateData; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int +parallelsClose(virConnectPtr conn) +{ + parallelsConnPtr privconn = conn->privateData; + + parallelsDriverLock(privconn); + virCapabilitiesFree(privconn->caps); + virDomainObjListDeinit(&privconn->domains); + conn->privateData = NULL; + + parallelsDriverUnlock(privconn); + virMutexDestroy(&privconn->lock); + + VIR_FREE(privconn); + return 0; +} + +static int +parallelsGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + /* TODO */ + *hvVer = 6; + return 0; +} + +static virDriver parallelsDriver = { + .no = VIR_DRV_PARALLELS, + .name = "Parallels", + .open = parallelsOpen, /* 0.10.0 */ + .close = parallelsClose, /* 0.10.0 */ + .version = parallelsGetVersion, /* 0.10.0 */ + .getHostname = virGetHostname, /* 0.10.0 */ + .nodeGetInfo = nodeGetInfo, /* 0.10.0 */ + .getCapabilities = parallelsGetCapabilities, /* 0.10.0 */ +}; + +/** + * parallelsRegister: + * + * Registers the parallels driver + */ +int +parallelsRegister(void) +{ + char *prlctl_path; + + prlctl_path = virFindFileInPath(PRLCTL); + if (!prlctl_path) { + VIR_DEBUG("%s", _("Can't find prlctl command in the PATH env")); + return 0; + } + + VIR_FREE(prlctl_path); + + if (virRegisterDriver(¶llelsDriver) < 0) + return -1; + + return 0; +} diff --git a/src/parallels/parallels_driver.h b/src/parallels/parallels_driver.h new file mode 100644 index 0000000..3e02c8f --- /dev/null +++ b/src/parallels/parallels_driver.h @@ -0,0 +1,28 @@ +/* + * parallels_driver.c: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2012 Parallels, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef PARALLELS_DRIVER_H +# define PARALLELS_DRIVER_H + +int parallelsRegister(void); + +#endif diff --git a/src/util/virterror.c b/src/util/virterror.c index 74adeed..a40cfe0 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -111,7 +111,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "URI Utils", /* 45 */ "Authentication Utils", - "DBus Utils" + "DBus Utils", + "Parallels Cloud Server" ) -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list