From: Maxim Nestratov Date: Wed, 10 Jun 2015 07:50:00 +0000 (+0300) Subject: parallels: rename all parallels files and driver directory to vz X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=e6d180f07fb06af9088eb13fa418a4a36f4a3614;p=libvirt.git parallels: rename all parallels files and driver directory to vz This patch moves all src/parallels/parallels* files to vz/vz* and fixes build accordingly. No functional changes. Signed-off-by: Maxim Nestratov --- diff --git a/po/POTFILES.in b/po/POTFILES.in index 189e2cc2f4..1d5917d10c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -106,12 +106,12 @@ 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/parallels/parallels_network.c -src/parallels/parallels_sdk.c -src/parallels/parallels_utils.c -src/parallels/parallels_utils.h -src/parallels/parallels_storage.c +src/vz/vz_driver.c +src/vz/vz_network.c +src/vz/vz_sdk.c +src/vz/vz_utils.c +src/vz/vz_utils.h +src/vz/vz_storage.c src/phyp/phyp_driver.c src/qemu/qemu_agent.c src/qemu/qemu_blockjob.c diff --git a/src/Makefile.am b/src/Makefile.am index 1e1b841ca9..47b6d61b2f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -558,7 +558,7 @@ DRIVER_SOURCE_FILES = \ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ $(NWFILTER_DRIVER_SOURCES) \ $(OPENVZ_DRIVER_SOURCES) \ - $(PARALLELS_DRIVER_SOURCES) \ + $(VZ_DRIVER_SOURCES) \ $(PHYP_DRIVER_SOURCES) \ $(QEMU_DRIVER_SOURCES) \ $(REMOTE_DRIVER_SOURCES) \ @@ -826,15 +826,15 @@ HYPERV_DRIVER_EXTRA_DIST = \ hyperv/hyperv_wmi_generator.py \ $(HYPERV_DRIVER_GENERATED) -PARALLELS_DRIVER_SOURCES = \ - parallels/parallels_driver.h \ - parallels/parallels_driver.c \ - parallels/parallels_utils.c \ - parallels/parallels_utils.h \ - parallels/parallels_storage.c \ - parallels/parallels_network.c \ - parallels/parallels_sdk.h \ - parallels/parallels_sdk.c +VZ_DRIVER_SOURCES = \ + vz/vz_driver.h \ + vz/vz_driver.c \ + vz/vz_utils.c \ + vz/vz_utils.h \ + vz/vz_storage.c \ + vz/vz_network.c \ + vz/vz_sdk.h \ + vz/vz_sdk.c BHYVE_DRIVER_SOURCES = \ bhyve/bhyve_capabilities.c \ @@ -1415,13 +1415,13 @@ libvirt_driver_hyperv_la_SOURCES = $(HYPERV_DRIVER_SOURCES) endif WITH_HYPERV if WITH_PARALLELS -noinst_LTLIBRARIES += libvirt_driver_parallels.la -libvirt_la_BUILT_LIBADD += libvirt_driver_parallels.la -libvirt_driver_parallels_la_CFLAGS = \ +noinst_LTLIBRARIES += libvirt_driver_vz.la +libvirt_la_BUILT_LIBADD += libvirt_driver_vz.la +libvirt_driver_vz_la_CFLAGS = \ -I$(srcdir)/conf $(AM_CFLAGS) \ $(PARALLELS_SDK_CFLAGS) $(LIBNL_CFLAGS) -libvirt_driver_parallels_la_LIBADD = $(PARALLELS_SDK_LIBS) $(LIBNL_LIBS) -libvirt_driver_parallels_la_SOURCES = $(PARALLELS_DRIVER_SOURCES) +libvirt_driver_vz_la_LIBADD = $(PARALLELS_SDK_LIBS) $(LIBNL_LIBS) +libvirt_driver_vz_la_SOURCES = $(VZ_DRIVER_SOURCES) endif WITH_PARALLELS if WITH_BHYVE @@ -1787,7 +1787,7 @@ EXTRA_DIST += \ $(ESX_DRIVER_EXTRA_DIST) \ $(HYPERV_DRIVER_SOURCES) \ $(HYPERV_DRIVER_EXTRA_DIST) \ - $(PARALLELS_DRIVER_SOURCES) \ + $(VZ_DRIVER_SOURCES) \ $(BHYVE_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ diff --git a/src/libvirt.c b/src/libvirt.c index f1e8d3f885..4204446ebb 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -93,7 +93,7 @@ # include "xenapi/xenapi_driver.h" #endif #ifdef WITH_PARALLELS -# include "parallels/parallels_driver.h" +# include "vz/vz_driver.h" #endif #ifdef WITH_BHYVE # include "bhyve/bhyve_driver.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c deleted file mode 100644 index 8edddc409c..0000000000 --- a/src/parallels/parallels_driver.c +++ /dev/null @@ -1,1418 +0,0 @@ -/* - * parallels_driver.c: core driver functions for managing - * Parallels Cloud Server hosts - * - * Copyright (C) 2014-2015 Red Hat, Inc. - * 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 - * . - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "datatypes.h" -#include "virerror.h" -#include "viralloc.h" -#include "virlog.h" -#include "vircommand.h" -#include "configmake.h" -#include "virfile.h" -#include "virstoragefile.h" -#include "nodeinfo.h" -#include "virstring.h" -#include "cpu/cpu.h" -#include "virtypedparam.h" - -#include "parallels_driver.h" -#include "parallels_utils.h" -#include "parallels_sdk.h" - -#define VIR_FROM_THIS VIR_FROM_PARALLELS - -VIR_LOG_INIT("parallels.parallels_driver"); - -#define PRLCTL "prlctl" -#define PRLSRVCTL "prlsrvctl" - -static int vzConnectClose(virConnectPtr conn); - -void -vzDriverLock(vzConnPtr driver) -{ - virMutexLock(&driver->lock); -} - -void -vzDriverUnlock(vzConnPtr driver) -{ - virMutexUnlock(&driver->lock); -} - -static virCapsPtr -vzBuildCapabilities(void) -{ - virCapsPtr caps = NULL; - virCPUDefPtr cpu = NULL; - virCPUDataPtr data = NULL; - virCapsGuestPtr guest; - virNodeInfo nodeinfo; - - if ((caps = virCapabilitiesNew(virArchFromHost(), - false, false)) == NULL) - return NULL; - - if (nodeCapsInitNUMA(caps) < 0) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, - VIR_ARCH_X86_64, - "parallels", - NULL, 0, NULL)) == NULL) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, - VIR_ARCH_I686, - "parallels", - NULL, 0, NULL)) == NULL) - goto error; - - - if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_PARALLELS, - NULL, NULL, 0, NULL) == NULL) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, - VIR_ARCH_X86_64, - "parallels", - NULL, 0, NULL)) == NULL) - goto error; - - if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_PARALLELS, - NULL, NULL, 0, NULL) == NULL) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, - VIR_ARCH_X86_64, - "vz", - NULL, 0, NULL)) == NULL) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, - VIR_ARCH_I686, - "vz", - NULL, 0, NULL)) == NULL) - goto error; - - - if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VZ, - NULL, NULL, 0, NULL) == NULL) - goto error; - - if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, - VIR_ARCH_X86_64, - "vz", - NULL, 0, NULL)) == NULL) - goto error; - - if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VZ, - NULL, NULL, 0, NULL) == NULL) - goto error; - - if (nodeGetInfo(&nodeinfo)) - goto error; - - if (VIR_ALLOC(cpu) < 0) - goto error; - - cpu->arch = caps->host.arch; - cpu->type = VIR_CPU_TYPE_HOST; - cpu->sockets = nodeinfo.sockets; - cpu->cores = nodeinfo.cores; - cpu->threads = nodeinfo.threads; - - caps->host.cpu = cpu; - - if (!(data = cpuNodeData(cpu->arch)) - || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { - goto cleanup; - } - - cleanup: - cpuDataFree(data); - return caps; - - error: - virObjectUnref(caps); - goto cleanup; -} - -static char * -vzConnectGetCapabilities(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - char *xml; - - vzDriverLock(privconn); - xml = virCapabilitiesFormatXML(privconn->caps); - vzDriverUnlock(privconn); - return xml; -} - -static int -vzDomainDefPostParse(virDomainDefPtr def, - virCapsPtr caps ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - /* memory hotplug tunables are not supported by this driver */ - if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0) - return -1; - - return 0; -} - -static int -vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, - const virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - int ret = -1; - - if (dev->type == VIR_DOMAIN_DEVICE_NET && - (dev->data.net->type == VIR_DOMAIN_NET_TYPE_NETWORK || - dev->data.net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) && - !dev->data.net->model && - def->os.type == VIR_DOMAIN_OSTYPE_HVM && - VIR_STRDUP(dev->data.net->model, "e1000") < 0) - goto cleanup; - - ret = 0; - cleanup: - return ret; -} - - -virDomainDefParserConfig vzDomainDefParserConfig = { - .macPrefix = {0x42, 0x1C, 0x00}, - .devicesPostParseCallback = vzDomainDeviceDefPostParse, - .domainPostParseCallback = vzDomainDefPostParse, -}; - - -static int -vzOpenDefault(virConnectPtr conn) -{ - vzConnPtr privconn; - - if (VIR_ALLOC(privconn) < 0) - return VIR_DRV_OPEN_ERROR; - if (virMutexInit(&privconn->lock) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot initialize mutex")); - goto err_free; - } - - privconn->drivername = conn->driver->name; - - if (prlsdkInit()) { - VIR_DEBUG("%s", _("Can't initialize Parallels SDK")); - goto err_free; - } - - if (prlsdkConnect(privconn) < 0) - goto err_free; - - if (!(privconn->caps = vzBuildCapabilities())) - goto error; - - if (!(privconn->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig, - NULL, NULL))) - goto error; - - if (!(privconn->domains = virDomainObjListNew())) - goto error; - - if (!(privconn->domainEventState = virObjectEventStateNew())) - goto error; - - if (prlsdkSubscribeToPCSEvents(privconn)) - goto error; - - conn->privateData = privconn; - - if (prlsdkLoadDomains(privconn)) - goto error; - - return VIR_DRV_OPEN_SUCCESS; - - error: - virObjectUnref(privconn->domains); - virObjectUnref(privconn->caps); - virStoragePoolObjListFree(&privconn->pools); - virObjectEventStateFree(privconn->domainEventState); - prlsdkDisconnect(privconn); - prlsdkDeinit(); - err_free: - VIR_FREE(privconn); - return VIR_DRV_OPEN_ERROR; -} - -static virDrvOpenStatus -vzConnectOpen(virConnectPtr conn, - virConnectAuthPtr auth ATTRIBUTE_UNUSED, - unsigned int flags) -{ - int ret; - - virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - - if (!conn->uri) - return VIR_DRV_OPEN_DECLINED; - - if (!conn->uri->scheme) - return VIR_DRV_OPEN_DECLINED; - - if (STRNEQ(conn->uri->scheme, "vz") && - STRNEQ(conn->uri->scheme, "parallels")) - return VIR_DRV_OPEN_DECLINED; - - if (STREQ(conn->uri->scheme, "vz") && STRNEQ(conn->driver->name, "vz")) - return VIR_DRV_OPEN_DECLINED; - - if (STREQ(conn->uri->scheme, "parallels") && STRNEQ(conn->driver->name, "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 (!STREQ_NULLABLE(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected Virtuozzo URI path '%s', try vz:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - - if ((ret = vzOpenDefault(conn)) != VIR_DRV_OPEN_SUCCESS || - (ret = vzStorageOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS || - (ret = vzNetworkOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS) { - vzConnectClose(conn); - return ret; - } - - return VIR_DRV_OPEN_SUCCESS; -} - -static int -vzConnectClose(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - - if (!privconn) - return 0; - - vzNetworkClose(conn); - vzStorageClose(conn); - - vzDriverLock(privconn); - prlsdkUnsubscribeFromPCSEvents(privconn); - virObjectUnref(privconn->caps); - virObjectUnref(privconn->xmlopt); - virObjectUnref(privconn->domains); - virObjectEventStateFree(privconn->domainEventState); - prlsdkDisconnect(privconn); - conn->privateData = NULL; - prlsdkDeinit(); - - vzDriverUnlock(privconn); - virMutexDestroy(&privconn->lock); - - VIR_FREE(privconn); - return 0; -} - -static int -vzConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) -{ - char *output, *sVer, *tmp; - const char *searchStr = "prlsrvctl version "; - int ret = -1; - - output = vzGetOutput(PRLSRVCTL, "--help", NULL); - - if (!output) { - vzParseError(); - goto cleanup; - } - - if (!(sVer = strstr(output, searchStr))) { - vzParseError(); - goto cleanup; - } - - sVer = sVer + strlen(searchStr); - - /* parallels server has versions number like 6.0.17977.782218, - * so libvirt can handle only first two numbers. */ - if (!(tmp = strchr(sVer, '.'))) { - vzParseError(); - goto cleanup; - } - - if (!(tmp = strchr(tmp + 1, '.'))) { - vzParseError(); - goto cleanup; - } - - tmp[0] = '\0'; - if (virParseVersionString(sVer, hvVer, true) < 0) { - vzParseError(); - goto cleanup; - } - - ret = 0; - - cleanup: - VIR_FREE(output); - return ret; -} - - -static char *vzConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - return virGetHostname(); -} - - -static int -vzConnectListDomains(virConnectPtr conn, int *ids, int maxids) -{ - vzConnPtr privconn = conn->privateData; - int n; - - vzDriverLock(privconn); - n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids, - NULL, NULL); - vzDriverUnlock(privconn); - - return n; -} - -static int -vzConnectNumOfDomains(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - int count; - - vzDriverLock(privconn); - count = virDomainObjListNumOfDomains(privconn->domains, true, - NULL, NULL); - vzDriverUnlock(privconn); - - return count; -} - -static int -vzConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) -{ - vzConnPtr privconn = conn->privateData; - int n; - - vzDriverLock(privconn); - memset(names, 0, sizeof(*names) * maxnames); - n = virDomainObjListGetInactiveNames(privconn->domains, names, - maxnames, NULL, NULL); - vzDriverUnlock(privconn); - - return n; -} - -static int -vzConnectNumOfDefinedDomains(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - int count; - - vzDriverLock(privconn); - count = virDomainObjListNumOfDomains(privconn->domains, false, - NULL, NULL); - vzDriverUnlock(privconn); - - return count; -} - -static int -vzConnectListAllDomains(virConnectPtr conn, - virDomainPtr **domains, - unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - int ret = -1; - - virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); - vzDriverLock(privconn); - ret = virDomainObjListExport(privconn->domains, conn, domains, - NULL, flags); - vzDriverUnlock(privconn); - - return ret; -} - -static virDomainPtr -vzDomainLookupByID(virConnectPtr conn, int id) -{ - vzConnPtr privconn = conn->privateData; - virDomainPtr ret = NULL; - virDomainObjPtr dom; - - vzDriverLock(privconn); - dom = virDomainObjListFindByID(privconn->domains, id); - vzDriverUnlock(privconn); - - if (dom == NULL) { - virReportError(VIR_ERR_NO_DOMAIN, NULL); - goto cleanup; - } - - ret = virGetDomain(conn, dom->def->name, dom->def->uuid); - if (ret) - ret->id = dom->def->id; - - cleanup: - if (dom) - virObjectUnlock(dom); - return ret; -} - -static virDomainPtr -vzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) -{ - vzConnPtr privconn = conn->privateData; - virDomainPtr ret = NULL; - virDomainObjPtr dom; - - vzDriverLock(privconn); - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - vzDriverUnlock(privconn); - - if (dom == NULL) { - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(uuid, uuidstr); - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s'"), uuidstr); - goto cleanup; - } - - ret = virGetDomain(conn, dom->def->name, dom->def->uuid); - if (ret) - ret->id = dom->def->id; - - cleanup: - if (dom) - virObjectUnlock(dom); - return ret; -} - -static virDomainPtr -vzDomainLookupByName(virConnectPtr conn, const char *name) -{ - vzConnPtr privconn = conn->privateData; - virDomainPtr ret = NULL; - virDomainObjPtr dom; - - vzDriverLock(privconn); - dom = virDomainObjListFindByName(privconn->domains, name); - vzDriverUnlock(privconn); - - if (dom == NULL) { - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching name '%s'"), name); - goto cleanup; - } - - ret = virGetDomain(conn, dom->def->name, dom->def->uuid); - if (ret) - ret->id = dom->def->id; - - cleanup: - virDomainObjEndAPI(&dom); - return ret; -} - -static int -vzDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) -{ - virDomainObjPtr privdom; - int ret = -1; - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - info->state = virDomainObjGetState(privdom, NULL); - info->memory = privdom->def->mem.cur_balloon; - info->maxMem = virDomainDefGetMemoryActual(privdom->def); - info->nrVirtCpu = privdom->def->vcpus; - info->cpuTime = 0; - ret = 0; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static char * -vzDomainGetOSType(virDomainPtr domain) -{ - virDomainObjPtr privdom; - - char *ret = NULL; - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - ignore_value(VIR_STRDUP(ret, virDomainOSTypeToString(privdom->def->os.type))); - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static int -vzDomainIsPersistent(virDomainPtr domain) -{ - virDomainObjPtr privdom; - int ret = -1; - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - ret = 1; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static int -vzDomainGetState(virDomainPtr domain, - int *state, int *reason, unsigned int flags) -{ - virDomainObjPtr privdom; - int ret = -1; - virCheckFlags(0, -1); - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - *state = virDomainObjGetState(privdom, reason); - ret = 0; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static char * -vzDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) -{ - virDomainDefPtr def; - virDomainObjPtr privdom; - char *ret = NULL; - - /* Flags checked by virDomainDefFormat */ - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - def = (flags & VIR_DOMAIN_XML_INACTIVE) && - privdom->newDef ? privdom->newDef : privdom->def; - - ret = virDomainDefFormat(def, flags); - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static int -vzDomainGetAutostart(virDomainPtr domain, int *autostart) -{ - virDomainObjPtr privdom; - int ret = -1; - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - *autostart = privdom->autostart; - ret = 0; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - -static virDomainPtr -vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - virDomainPtr retdom = NULL; - virDomainDefPtr def; - virDomainObjPtr olddom = NULL; - unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE; - - virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL); - - if (flags & VIR_DOMAIN_DEFINE_VALIDATE) - parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE; - - vzDriverLock(privconn); - if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, - parse_flags)) == NULL) - goto cleanup; - - olddom = virDomainObjListFindByUUID(privconn->domains, def->uuid); - if (olddom == NULL) { - virResetLastError(); - if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { - if (prlsdkCreateVm(conn, def)) - goto cleanup; - } else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) { - if (prlsdkCreateCt(conn, def)) - goto cleanup; - } else { - virReportError(VIR_ERR_INVALID_ARG, - _("Unsupported OS type: %s"), - virDomainOSTypeToString(def->os.type)); - goto cleanup; - } - - olddom = prlsdkAddDomain(privconn, def->uuid); - if (!olddom) - goto cleanup; - } else { - int state, reason; - - state = virDomainObjGetState(olddom, &reason); - - if (state == VIR_DOMAIN_SHUTOFF && - reason == VIR_DOMAIN_SHUTOFF_SAVED) { - - /* PCS doesn't store domain config in managed save state file. - * It's forbidden to change config for VMs in this state. - * It's possible to change config for containers, but after - * restoring domain will have that new config, not a config, - * which domain had at the moment of virDomainManagedSave. - * - * So forbid this operation, if config is changed. If it's - * not changed - just do nothing. */ - - if (!virDomainDefCheckABIStability(olddom->def, def)) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Can't change domain configuration " - "in managed save state")); - goto cleanup; - } - } else { - if (prlsdkApplyConfig(conn, olddom, def)) - goto cleanup; - - if (prlsdkUpdateDomain(privconn, olddom)) - goto cleanup; - } - } - - retdom = virGetDomain(conn, def->name, def->uuid); - if (retdom) - retdom->id = def->id; - - cleanup: - if (olddom) - virObjectUnlock(olddom); - virDomainDefFree(def); - vzDriverUnlock(privconn); - return retdom; -} - -static virDomainPtr -vzDomainDefineXML(virConnectPtr conn, const char *xml) -{ - return vzDomainDefineXMLFlags(conn, xml, 0); -} - - -static int -vzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, - virNodeInfoPtr nodeinfo) -{ - return nodeGetInfo(nodeinfo); -} - -static int vzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - /* Encryption is not relevant / applicable to way we talk to PCS */ - return 0; -} - -static int vzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - /* We run CLI tools directly so this is secure */ - return 1; -} - -static int vzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - return 1; -} - - -static char * -vzConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, - const char **xmlCPUs, - unsigned int ncpus, - unsigned int flags) -{ - virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL); - - return cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags); -} - - -static int -vzDomainGetVcpus(virDomainPtr domain, - virVcpuInfoPtr info, - int maxinfo, - unsigned char *cpumaps, - int maplen) -{ - virDomainObjPtr privdom = NULL; - size_t i; - int v, maxcpu, hostcpus; - int ret = -1; - - if (!(privdom = vzDomObjFromDomain(domain))) - goto cleanup; - - if (!virDomainObjIsActive(privdom)) { - virReportError(VIR_ERR_OPERATION_INVALID, - "%s", - _("cannot list vcpu pinning for an inactive domain")); - goto cleanup; - } - - if ((hostcpus = nodeGetCPUCount()) < 0) - goto cleanup; - - maxcpu = maplen * 8; - if (maxcpu > hostcpus) - maxcpu = hostcpus; - - if (maxinfo >= 1) { - if (info != NULL) { - memset(info, 0, sizeof(*info) * maxinfo); - for (i = 0; i < maxinfo; i++) { - info[i].number = i; - info[i].state = VIR_VCPU_RUNNING; - } - } - if (cpumaps != NULL) { - unsigned char *tmpmap = NULL; - int tmpmapLen = 0; - - memset(cpumaps, 0, maplen * maxinfo); - virBitmapToData(privdom->def->cpumask, &tmpmap, &tmpmapLen); - if (tmpmapLen > maplen) - tmpmapLen = maplen; - - for (v = 0; v < maxinfo; v++) { - unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v); - memcpy(cpumap, tmpmap, tmpmapLen); - } - VIR_FREE(tmpmap); - } - } - ret = maxinfo; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - return ret; -} - - -static int -vzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED, - unsigned char **cpumap, - unsigned int *online, - unsigned int flags) -{ - return nodeGetCPUMap(cpumap, online, flags); -} - -static int -vzConnectDomainEventRegisterAny(virConnectPtr conn, - virDomainPtr domain, - int eventID, - virConnectDomainEventGenericCallback callback, - void *opaque, - virFreeCallback freecb) -{ - int ret = -1; - vzConnPtr privconn = conn->privateData; - if (virDomainEventStateRegisterID(conn, - privconn->domainEventState, - domain, eventID, - callback, opaque, freecb, &ret) < 0) - ret = -1; - return ret; -} - -static int -vzConnectDomainEventDeregisterAny(virConnectPtr conn, - int callbackID) -{ - vzConnPtr privconn = conn->privateData; - int ret = -1; - - if (virObjectEventStateDeregisterID(conn, - privconn->domainEventState, - callbackID) < 0) - goto cleanup; - - ret = 0; - - cleanup: - return ret; -} - -static int vzDomainSuspend(virDomainPtr domain) -{ - return prlsdkDomainChangeState(domain, prlsdkPause); -} - -static int vzDomainResume(virDomainPtr domain) -{ - return prlsdkDomainChangeState(domain, prlsdkResume); -} - -static int vzDomainCreate(virDomainPtr domain) -{ - return prlsdkDomainChangeState(domain, prlsdkStart); -} - -static int vzDomainDestroy(virDomainPtr domain) -{ - return prlsdkDomainChangeState(domain, prlsdkKill); -} - -static int vzDomainShutdown(virDomainPtr domain) -{ - return prlsdkDomainChangeState(domain, prlsdkStop); -} - -static int vzDomainIsActive(virDomainPtr domain) -{ - virDomainObjPtr dom = NULL; - int ret = -1; - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - ret = virDomainObjIsActive(dom); - virObjectUnlock(dom); - - return ret; -} - -static int -vzDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) -{ - /* we don't support any create flags */ - virCheckFlags(0, -1); - - return vzDomainCreate(domain); -} - -static int -vzDomainUndefineFlags(virDomainPtr domain, - unsigned int flags) -{ - vzConnPtr privconn = domain->conn->privateData; - virDomainObjPtr dom = NULL; - int ret; - - virCheckFlags(0, -1); - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - ret = prlsdkUnregisterDomain(privconn, dom); - if (ret) - virObjectUnlock(dom); - - return ret; -} - -static int -vzDomainUndefine(virDomainPtr domain) -{ - return vzDomainUndefineFlags(domain, 0); -} - -static int -vzDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags) -{ - virDomainObjPtr dom = NULL; - int state, reason; - int ret = 0; - - virCheckFlags(0, -1); - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - state = virDomainObjGetState(dom, &reason); - if (state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED) - ret = 1; - virObjectUnlock(dom); - - return ret; -} - -static int -vzDomainManagedSave(virDomainPtr domain, unsigned int flags) -{ - vzConnPtr privconn = domain->conn->privateData; - virDomainObjPtr dom = NULL; - int state, reason; - int ret = -1; - - virCheckFlags(VIR_DOMAIN_SAVE_RUNNING | - VIR_DOMAIN_SAVE_PAUSED, -1); - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - state = virDomainObjGetState(dom, &reason); - - if (state == VIR_DOMAIN_RUNNING && (flags & VIR_DOMAIN_SAVE_PAUSED)) { - ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkPause); - if (ret) - goto cleanup; - } - - ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkSuspend); - - cleanup: - virObjectUnlock(dom); - return ret; -} - -static int -vzDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags) -{ - virDomainObjPtr dom = NULL; - int state, reason; - int ret = -1; - - virCheckFlags(0, -1); - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - state = virDomainObjGetState(dom, &reason); - - if (!(state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED)) - goto cleanup; - - ret = prlsdkDomainManagedSaveRemove(dom); - - cleanup: - virObjectUnlock(dom); - return ret; -} - -static int vzDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, - unsigned int flags) -{ - int ret = -1; - vzConnPtr privconn = dom->conn->privateData; - virDomainDeviceDefPtr dev = NULL; - virDomainObjPtr privdom = NULL; - bool domactive = false; - - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, -1); - - if (!(privdom = vzDomObjFromDomain(dom))) - return -1; - - if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("device attach needs VIR_DOMAIN_AFFECT_CONFIG " - "flag to be set")); - goto cleanup; - } - - domactive = virDomainObjIsActive(privdom); - if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot do live update a device on " - "inactive domain")); - goto cleanup; - } - if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("Updates on a running domain need " - "VIR_DOMAIN_AFFECT_LIVE flag")); - } - - dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps, - privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE); - if (dev == NULL) - goto cleanup; - - switch (dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - ret = prlsdkAttachVolume(privdom, dev->data.disk); - if (ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("disk attach failed")); - goto cleanup; - } - break; - default: - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("device type '%s' cannot be attached"), - virDomainDeviceTypeToString(dev->type)); - break; - } - - ret = 0; - cleanup: - virObjectUnlock(privdom); - return ret; -} - -static int vzDomainAttachDevice(virDomainPtr dom, const char *xml) -{ - return vzDomainAttachDeviceFlags(dom, xml, - VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE); -} - -static int vzDomainDetachDeviceFlags(virDomainPtr dom, const char *xml, - unsigned int flags) -{ - int ret = -1; - vzConnPtr privconn = dom->conn->privateData; - virDomainDeviceDefPtr dev = NULL; - virDomainObjPtr privdom = NULL; - bool domactive = false; - - virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | - VIR_DOMAIN_AFFECT_CONFIG, -1); - - privdom = vzDomObjFromDomain(dom); - if (privdom == NULL) - return -1; - - if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("device detach needs VIR_DOMAIN_AFFECT_CONFIG " - "flag to be set")); - goto cleanup; - } - - domactive = virDomainObjIsActive(privdom); - if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot do live update a device on " - "inactive domain")); - goto cleanup; - } - if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("Updates on a running domain need " - "VIR_DOMAIN_AFFECT_LIVE flag")); - } - - dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps, - privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE); - if (dev == NULL) - goto cleanup; - - switch (dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - ret = prlsdkDetachVolume(privdom, dev->data.disk); - if (ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("disk detach failed")); - goto cleanup; - } - break; - default: - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("device type '%s' cannot be detached"), - virDomainDeviceTypeToString(dev->type)); - break; - } - - ret = 0; - cleanup: - virObjectUnlock(privdom); - return ret; -} - -static int vzDomainDetachDevice(virDomainPtr dom, const char *xml) -{ - return vzDomainDetachDeviceFlags(dom, xml, - VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE); -} - -static unsigned long long -vzDomainGetMaxMemory(virDomainPtr domain) -{ - virDomainObjPtr dom = NULL; - int ret = -1; - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - ret = dom->def->mem.max_balloon; - virObjectUnlock(dom); - return ret; -} - -static int -vzDomainBlockStats(virDomainPtr domain, const char *path, - virDomainBlockStatsPtr stats) -{ - virDomainObjPtr dom = NULL; - int ret = -1; - size_t i; - int idx; - - if (!(dom = vzDomObjFromDomainRef(domain))) - return -1; - - if (*path) { - if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) { - virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path); - goto cleanup; - } - if (prlsdkGetBlockStats(dom, dom->def->disks[idx], stats) < 0) - goto cleanup; - } else { - virDomainBlockStatsStruct s; - -#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME) \ - stats->VAR = 0; - - PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS) - -#undef PARALLELS_ZERO_STATS - - for (i = 0; i < dom->def->ndisks; i++) { - if (prlsdkGetBlockStats(dom, dom->def->disks[i], &s) < 0) - goto cleanup; - -#define PARALLELS_SUM_STATS(VAR, TYPE, NAME) \ - if (s.VAR != -1) \ - stats->VAR += s.VAR; - - PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_SUM_STATS) - -#undef PARALLELS_SUM_STATS - } - } - stats->errs = -1; - ret = 0; - - cleanup: - if (dom) - virDomainObjEndAPI(&dom); - - return ret; -} - -static int -vzDomainBlockStatsFlags(virDomainPtr domain, - const char *path, - virTypedParameterPtr params, - int *nparams, - unsigned int flags) -{ - virDomainBlockStatsStruct stats; - int ret = -1; - size_t i; - - virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); - /* We don't return strings, and thus trivially support this flag. */ - flags &= ~VIR_TYPED_PARAM_STRING_OKAY; - - if (vzDomainBlockStats(domain, path, &stats) < 0) - goto cleanup; - - if (*nparams == 0) { -#define PARALLELS_COUNT_STATS(VAR, TYPE, NAME) \ - if ((stats.VAR) != -1) \ - ++*nparams; - - PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_COUNT_STATS) - -#undef PARALLELS_COUNT_STATS - ret = 0; - goto cleanup; - } - - i = 0; -#define PARALLELS_BLOCK_STATS_ASSIGN_PARAM(VAR, TYPE, NAME) \ - if (i < *nparams && (stats.VAR) != -1) { \ - if (virTypedParameterAssign(params + i, TYPE, \ - VIR_TYPED_PARAM_LLONG, (stats.VAR)) < 0) \ - goto cleanup; \ - i++; \ - } - - PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_BLOCK_STATS_ASSIGN_PARAM) - -#undef PARALLELS_BLOCK_STATS_ASSIGN_PARAM - - *nparams = i; - ret = 0; - - cleanup: - return ret; -} - - -static virHypervisorDriver vzDriver = { - .name = "vz", - .connectOpen = vzConnectOpen, /* 0.10.0 */ - .connectClose = vzConnectClose, /* 0.10.0 */ - .connectGetVersion = vzConnectGetVersion, /* 0.10.0 */ - .connectGetHostname = vzConnectGetHostname, /* 0.10.0 */ - .nodeGetInfo = vzNodeGetInfo, /* 0.10.0 */ - .connectGetCapabilities = vzConnectGetCapabilities, /* 0.10.0 */ - .connectBaselineCPU = vzConnectBaselineCPU, /* 1.2.6 */ - .connectListDomains = vzConnectListDomains, /* 0.10.0 */ - .connectNumOfDomains = vzConnectNumOfDomains, /* 0.10.0 */ - .connectListDefinedDomains = vzConnectListDefinedDomains, /* 0.10.0 */ - .connectNumOfDefinedDomains = vzConnectNumOfDefinedDomains, /* 0.10.0 */ - .connectListAllDomains = vzConnectListAllDomains, /* 0.10.0 */ - .domainLookupByID = vzDomainLookupByID, /* 0.10.0 */ - .domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */ - .domainLookupByName = vzDomainLookupByName, /* 0.10.0 */ - .domainGetOSType = vzDomainGetOSType, /* 0.10.0 */ - .domainGetInfo = vzDomainGetInfo, /* 0.10.0 */ - .domainGetState = vzDomainGetState, /* 0.10.0 */ - .domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */ - .domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */ - .domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */ - .domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */ - .domainSuspend = vzDomainSuspend, /* 0.10.0 */ - .domainResume = vzDomainResume, /* 0.10.0 */ - .domainDestroy = vzDomainDestroy, /* 0.10.0 */ - .domainShutdown = vzDomainShutdown, /* 0.10.0 */ - .domainCreate = vzDomainCreate, /* 0.10.0 */ - .domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */ - .domainDefineXML = vzDomainDefineXML, /* 0.10.0 */ - .domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ - .domainUndefine = vzDomainUndefine, /* 1.2.10 */ - .domainUndefineFlags = vzDomainUndefineFlags, /* 1.2.10 */ - .domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */ - .domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */ - .domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */ - .domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */ - .domainIsActive = vzDomainIsActive, /* 1.2.10 */ - .connectDomainEventRegisterAny = vzConnectDomainEventRegisterAny, /* 1.2.10 */ - .connectDomainEventDeregisterAny = vzConnectDomainEventDeregisterAny, /* 1.2.10 */ - .nodeGetCPUMap = vzNodeGetCPUMap, /* 1.2.8 */ - .connectIsEncrypted = vzConnectIsEncrypted, /* 1.2.5 */ - .connectIsSecure = vzConnectIsSecure, /* 1.2.5 */ - .connectIsAlive = vzConnectIsAlive, /* 1.2.5 */ - .domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */ - .domainManagedSave = vzDomainManagedSave, /* 1.2.14 */ - .domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */ - .domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */ - .domainBlockStats = vzDomainBlockStats, /* 1.3.0 */ - .domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.3.0 */ -}; - -static virConnectDriver vzConnectDriver = { - .hypervisorDriver = &vzDriver, - .storageDriver = &vzStorageDriver, - .networkDriver = &vzNetworkDriver, -}; - -/* Parallels domain type backward compatibility*/ -static virHypervisorDriver parallelsDriver; -static virConnectDriver parallelsConnectDriver; - -/** - * vzRegister: - * - * Registers the vz driver - */ -int -vzRegister(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); - - /* Backward compatibility with Parallels domain type */ - parallelsDriver = vzDriver; - parallelsDriver.name = "Parallels"; - parallelsConnectDriver = vzConnectDriver; - parallelsConnectDriver.hypervisorDriver = ¶llelsDriver; - if (virRegisterConnectDriver(¶llelsConnectDriver, false) < 0) - return -1; - - if (virRegisterConnectDriver(&vzConnectDriver, false) < 0) - return -1; - - return 0; -} diff --git a/src/parallels/parallels_driver.h b/src/parallels/parallels_driver.h deleted file mode 100644 index 173764b67a..0000000000 --- a/src/parallels/parallels_driver.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * parallels_driver.h: 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 - * . - * - */ - -#ifndef PARALLELS_DRIVER_H -# define PARALLELS_DRIVER_H - -int vzRegister(void); - -#endif diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c deleted file mode 100644 index 6e1870763f..0000000000 --- a/src/parallels/parallels_network.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * parallels_network.c: core privconn functions for managing - * Parallels Cloud Server hosts - * - * Copyright (C) 2013-2014 Red Hat, Inc. - * 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 - * . - * - */ - -#include - -#include "datatypes.h" -#include "dirname.h" -#include "viralloc.h" -#include "virerror.h" -#include "virfile.h" -#include "virnetdev.h" -#include "md5.h" -#include "parallels_utils.h" -#include "virstring.h" - -#define VIR_FROM_THIS VIR_FROM_PARALLELS -#define PARALLELS_ROUTED_NETWORK_UUID "eb593dd1-6846-45b0-84a0-de0729286982" - -#define vzParseError() \ - virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ - __FUNCTION__, __LINE__, _("Can't parse prlctl output")) - -static int vzGetBridgedNetInfo(virNetworkDefPtr def, virJSONValuePtr jobj) -{ - const char *ifname; - char *bridgeLink = NULL; - char *bridgePath = NULL; - char *bridgeAddressPath = NULL; - char *bridgeAddress = NULL; - int len = 0; - int ret = -1; - - if (!(ifname = virJSONValueObjectGetString(jobj, "Bound To"))) { - vzParseError(); - goto cleanup; - } - - if (virAsprintf(&bridgeLink, SYSFS_NET_DIR "%s/brport/bridge", ifname) < 0) - goto cleanup; - - if (virFileResolveLink(bridgeLink, &bridgePath) < 0) { - virReportSystemError(errno, _("cannot read link '%s'"), bridgeLink); - goto cleanup; - } - - if (VIR_STRDUP(def->bridge, last_component(bridgePath)) < 0) - goto cleanup; - - if (virAsprintf(&bridgeAddressPath, SYSFS_NET_DIR "%s/brport/bridge/address", - ifname) < 0) - goto cleanup; - - if ((len = virFileReadAll(bridgeAddressPath, 18, &bridgeAddress)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Error reading file '%s'"), bridgeAddressPath); - - goto cleanup; - } - - if (len < VIR_MAC_STRING_BUFLEN) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Error reading MAC from '%s'"), bridgeAddressPath); - } - - bridgeAddress[VIR_MAC_STRING_BUFLEN - 1] = '\0'; - if (virMacAddrParse(bridgeAddress, &def->mac) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Can't parse MAC '%s'"), bridgeAddress); - goto cleanup; - } - def->mac_specified = 1; - - ret = 0; - - cleanup: - VIR_FREE(bridgeLink); - VIR_FREE(bridgePath); - VIR_FREE(bridgeAddress); - VIR_FREE(bridgeAddressPath); - return ret; -} - -static int vzGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) -{ - const char *tmp; - virJSONValuePtr jobj = NULL, jobj2; - int ret = -1; - - if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) - goto cleanup; - - jobj = vzParseOutput("prlsrvctl", "net", "info", "-j", name, NULL); - - if (!jobj) { - vzParseError(); - goto cleanup; - } - - if (!(jobj2 = virJSONValueObjectGet(jobj, "Parallels adapter"))) { - vzParseError(); - goto cleanup; - } - - if (VIR_STRDUP(def->ips[0].family, "ipv4") < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj2, "IP address"))) { - vzParseError(); - goto cleanup; - } - - if (virSocketAddrParseIPv4(&def->ips[0].address, tmp) < 0) { - vzParseError(); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj2, "Subnet mask"))) { - vzParseError(); - goto cleanup; - } - - if (virSocketAddrParseIPv4(&def->ips[0].netmask, tmp) < 0) { - vzParseError(); - goto cleanup; - } - - if (!(jobj2 = virJSONValueObjectGet(jobj, "DHCPv4 server"))) { - vzParseError(); - goto cleanup; - } - - if (VIR_EXPAND_N(def->ips[0].ranges, def->ips[0].nranges, 1) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope start address"))) { - vzParseError(); - goto cleanup; - } - - if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].start, tmp) < 0) { - vzParseError(); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope end address"))) { - vzParseError(); - goto cleanup; - } - - if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].end, tmp) < 0) { - vzParseError(); - goto cleanup; - } - - ret = 0; - cleanup: - virJSONValueFree(jobj); - return ret; -} - -static int -vzLoadNetwork(vzConnPtr privconn, virJSONValuePtr jobj) -{ - int ret = -1; - virNetworkObjPtr net = NULL; - virNetworkDefPtr def; - const char *tmp; - /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ - unsigned char md5[MD5_DIGEST_SIZE]; - - if (VIR_ALLOC(def) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Network ID"))) { - vzParseError(); - goto cleanup; - } - - if (VIR_STRDUP(def->name, tmp) < 0) - goto cleanup; - - /* Network names are unique in Parallels Cloud Server, so we can make - * a UUID from it */ - md5_buffer(tmp, strlen(tmp), md5); - memcpy(def->uuid, md5, VIR_UUID_BUFLEN); - def->uuid_specified = 1; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { - vzParseError(); - goto cleanup; - } - - if (STREQ(tmp, PARALLELS_BRIDGED_NETWORK_TYPE)) { - def->forward.type = VIR_NETWORK_FORWARD_BRIDGE; - - if (vzGetBridgedNetInfo(def, jobj) < 0) { - - /* Only mandatory networks are required to be configured completely */ - if (STRNEQ(def->name, PARALLELS_REQUIRED_BRIDGED_NETWORK)) - ret = 0; - - goto cleanup; - } - } else if (STREQ(tmp, PARALLELS_HOSTONLY_NETWORK_TYPE)) { - def->forward.type = VIR_NETWORK_FORWARD_NONE; - - if (vzGetHostOnlyNetInfo(def, def->name) < 0) { - - /* Only mandatory networks are required to be configured completely */ - if (STRNEQ(def->name, PARALLELS_REQUIRED_HOSTONLY_NETWORK)) - ret = 0; - - goto cleanup; - } - } else { - vzParseError(); - goto cleanup; - } - - if (!(net = virNetworkAssignDef(privconn->networks, def, 0))) - goto cleanup; - def = NULL; - net->active = 1; - net->autostart = 1; - ret = 0; - - cleanup: - virNetworkObjEndAPI(&net); - virNetworkDefFree(def); - return ret; -} - -static int -vzAddRoutedNetwork(vzConnPtr privconn) -{ - virNetworkObjPtr net = NULL; - virNetworkDefPtr def; - - if (VIR_ALLOC(def) < 0) - goto cleanup; - - def->forward.type = VIR_NETWORK_FORWARD_ROUTE; - - if (VIR_STRDUP(def->name, PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) - goto cleanup; - - if (virUUIDParse(PARALLELS_ROUTED_NETWORK_UUID, def->uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Can't parse UUID")); - goto cleanup; - } - def->uuid_specified = 1; - - if (!(net = virNetworkAssignDef(privconn->networks, def, 0))) - goto cleanup; - - net->active = 1; - net->autostart = 1; - virNetworkObjEndAPI(&net); - - return 0; - - cleanup: - virNetworkDefFree(def); - return -1; -} - -static int vzLoadNetworks(vzConnPtr privconn) -{ - virJSONValuePtr jobj, jobj2; - int ret = -1; - int count; - size_t i; - - jobj = vzParseOutput("prlsrvctl", "net", "list", "-j", NULL); - - if (!jobj) { - vzParseError(); - goto cleanup; - } - - count = virJSONValueArraySize(jobj); - if (count < 0) { - vzParseError(); - goto cleanup; - } - - for (i = 0; i < count; i++) { - jobj2 = virJSONValueArrayGet(jobj, i); - if (!jobj2) { - vzParseError(); - goto cleanup; - } - - if (vzLoadNetwork(privconn, jobj2) < 0) - goto cleanup; - } - - if (vzAddRoutedNetwork(privconn) < 0) - goto cleanup; - - ret = 0; - - cleanup: - virJSONValueFree(jobj); - return ret; -} - -virDrvOpenStatus -vzNetworkOpen(virConnectPtr conn, - unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - - virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - - if (STRNEQ(conn->driver->name, "vz") && - STRNEQ(conn->driver->name, "Parallels")) - return VIR_DRV_OPEN_DECLINED; - - if (!(privconn->networks = virNetworkObjListNew())) - goto error; - - if (vzLoadNetworks(conn->privateData) < 0) - goto error; - - return VIR_DRV_OPEN_SUCCESS; - error: - virObjectUnref(privconn->networks); - privconn->networks = NULL; - return VIR_DRV_OPEN_ERROR; -} - -int vzNetworkClose(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - - if (!privconn) - return 0; - - virObjectUnref(privconn->networks); - return 0; -} - -static int vzConnectNumOfNetworks(virConnectPtr conn) -{ - int nactive; - vzConnPtr privconn = conn->privateData; - - nactive = virNetworkObjListNumOfNetworks(privconn->networks, - true, NULL, conn); - return nactive; -} - -static int vzConnectListNetworks(virConnectPtr conn, - char **const names, - int nnames) -{ - vzConnPtr privconn = conn->privateData; - int got; - - got = virNetworkObjListGetNames(privconn->networks, - true, names, nnames, NULL, conn); - return got; -} - -static int vzConnectNumOfDefinedNetworks(virConnectPtr conn) -{ - int ninactive; - vzConnPtr privconn = conn->privateData; - - ninactive = virNetworkObjListNumOfNetworks(privconn->networks, - false, NULL, conn); - return ninactive; -} - -static int vzConnectListDefinedNetworks(virConnectPtr conn, - char **const names, - int nnames) -{ - vzConnPtr privconn = conn->privateData; - int got; - - got = virNetworkObjListGetNames(privconn->networks, - false, names, nnames, NULL, conn); - return got; -} - -static int vzConnectListAllNetworks(virConnectPtr conn, - virNetworkPtr **nets, - unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - - virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); - - return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags); -} - -static virNetworkPtr vzNetworkLookupByUUID(virConnectPtr conn, - const unsigned char *uuid) -{ - vzConnPtr privconn = conn->privateData; - virNetworkObjPtr network; - virNetworkPtr ret = NULL; - - network = virNetworkObjFindByUUID(privconn->networks, uuid); - if (!network) { - virReportError(VIR_ERR_NO_NETWORK, - "%s", _("no network with matching uuid")); - goto cleanup; - } - - ret = virGetNetwork(conn, network->def->name, network->def->uuid); - - cleanup: - virNetworkObjEndAPI(&network); - return ret; -} - -static virNetworkPtr vzNetworkLookupByName(virConnectPtr conn, - const char *name) -{ - vzConnPtr privconn = conn->privateData; - virNetworkObjPtr network; - virNetworkPtr ret = NULL; - - network = virNetworkObjFindByName(privconn->networks, name); - if (!network) { - virReportError(VIR_ERR_NO_NETWORK, - _("no network with matching name '%s'"), name); - goto cleanup; - } - - ret = virGetNetwork(conn, network->def->name, network->def->uuid); - - cleanup: - virNetworkObjEndAPI(&network); - return ret; -} - -static char *vzNetworkGetXMLDesc(virNetworkPtr net, - unsigned int flags) -{ - vzConnPtr privconn = net->conn->privateData; - virNetworkObjPtr network; - char *ret = NULL; - - virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL); - - network = virNetworkObjFindByUUID(privconn->networks, net->uuid); - if (!network) { - virReportError(VIR_ERR_NO_NETWORK, - "%s", _("no network with matching uuid")); - goto cleanup; - } - - ret = virNetworkDefFormat(network->def, flags); - - cleanup: - virNetworkObjEndAPI(&network); - return ret; -} - -static int vzNetworkIsActive(virNetworkPtr net) -{ - vzConnPtr privconn = net->conn->privateData; - virNetworkObjPtr obj; - int ret = -1; - - obj = virNetworkObjFindByUUID(privconn->networks, net->uuid); - if (!obj) { - virReportError(VIR_ERR_NO_NETWORK, NULL); - goto cleanup; - } - ret = virNetworkObjIsActive(obj); - - cleanup: - virNetworkObjEndAPI(&obj); - return ret; -} - -static int vzNetworkIsPersistent(virNetworkPtr net) -{ - vzConnPtr privconn = net->conn->privateData; - virNetworkObjPtr obj; - int ret = -1; - - obj = virNetworkObjFindByUUID(privconn->networks, net->uuid); - if (!obj) { - virReportError(VIR_ERR_NO_NETWORK, NULL); - goto cleanup; - } - ret = obj->persistent; - - cleanup: - virNetworkObjEndAPI(&obj); - return ret; -} - -static int vzNetworkGetAutostart(virNetworkPtr net, - int *autostart) -{ - vzConnPtr privconn = net->conn->privateData; - virNetworkObjPtr network; - int ret = -1; - - network = virNetworkObjFindByUUID(privconn->networks, net->uuid); - if (!network) { - virReportError(VIR_ERR_NO_NETWORK, - "%s", _("no network with matching uuid")); - goto cleanup; - } - - *autostart = network->autostart; - ret = 0; - - cleanup: - virNetworkObjEndAPI(&network); - return ret; -} - -virNetworkDriver vzNetworkDriver = { - .name = "Parallels", - .connectNumOfNetworks = vzConnectNumOfNetworks, /* 1.0.1 */ - .connectListNetworks = vzConnectListNetworks, /* 1.0.1 */ - .connectNumOfDefinedNetworks = vzConnectNumOfDefinedNetworks, /* 1.0.1 */ - .connectListDefinedNetworks = vzConnectListDefinedNetworks, /* 1.0.1 */ - .connectListAllNetworks = vzConnectListAllNetworks, /* 1.0.1 */ - .networkLookupByUUID = vzNetworkLookupByUUID, /* 1.0.1 */ - .networkLookupByName = vzNetworkLookupByName, /* 1.0.1 */ - .networkGetXMLDesc = vzNetworkGetXMLDesc, /* 1.0.1 */ - .networkGetAutostart = vzNetworkGetAutostart, /* 1.0.1 */ - .networkIsActive = vzNetworkIsActive, /* 1.0.1 */ - .networkIsPersistent = vzNetworkIsPersistent, /* 1.0.1 */ -}; diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c deleted file mode 100644 index 4dafe7c43a..0000000000 --- a/src/parallels/parallels_sdk.c +++ /dev/null @@ -1,3660 +0,0 @@ -/* - * parallels_sdk.c: core driver functions for managing - * Parallels Cloud Server hosts - * - * Copyright (C) 2014 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 - * . - * - */ - -#include -#include - -#include "virerror.h" -#include "viralloc.h" -#include "virstring.h" -#include "nodeinfo.h" -#include "virlog.h" -#include "datatypes.h" -#include "domain_conf.h" -#include "virtime.h" - -#include "parallels_sdk.h" - -#define VIR_FROM_THIS VIR_FROM_PARALLELS -#define JOB_INFINIT_WAIT_TIMEOUT UINT_MAX - -VIR_LOG_INIT("parallels.sdk"); - -/* - * Log error description - */ -static void -logPrlErrorHelper(PRL_RESULT err, const char *filename, - const char *funcname, size_t linenr) -{ - char *msg1 = NULL, *msg2 = NULL; - PRL_UINT32 len = 0; - - /* Get required buffer length */ - PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, NULL, &len); - - if (VIR_ALLOC_N(msg1, len) < 0) - goto cleanup; - - /* get short error description */ - PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, msg1, &len); - - PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, NULL, &len); - - if (VIR_ALLOC_N(msg2, len) < 0) - goto cleanup; - - /* get long error description */ - PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, msg2, &len); - - virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR, - filename, funcname, linenr, - _("%s %s"), msg1, msg2); - - cleanup: - VIR_FREE(msg1); - VIR_FREE(msg2); -} - -#define logPrlError(code) \ - logPrlErrorHelper(code, __FILE__, \ - __FUNCTION__, __LINE__) - -#define prlsdkCheckRetGoto(ret, label) \ - do { \ - if (PRL_FAILED(ret)) { \ - logPrlError(ret); \ - goto label; \ - } \ - } while (0) - -static PRL_RESULT -logPrlEventErrorHelper(PRL_HANDLE event, const char *filename, - const char *funcname, size_t linenr) -{ - PRL_RESULT ret, retCode; - char *msg1 = NULL, *msg2 = NULL; - PRL_UINT32 len = 0; - int err = -1; - - if ((ret = PrlEvent_GetErrCode(event, &retCode))) { - logPrlError(ret); - return ret; - } - - PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, NULL, &len); - - if (VIR_ALLOC_N(msg1, len) < 0) - goto cleanup; - - PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, msg1, &len); - - PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, NULL, &len); - - if (VIR_ALLOC_N(msg2, len) < 0) - goto cleanup; - - PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, msg2, &len); - - virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR, - filename, funcname, linenr, - _("%s %s"), msg1, msg2); - err = 0; - - cleanup: - VIR_FREE(msg1); - VIR_FREE(msg2); - - return err; -} - -#define logPrlEventError(event) \ - logPrlEventErrorHelper(event, __FILE__, \ - __FUNCTION__, __LINE__) - -static PRL_RESULT -getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result, - const char *filename, const char *funcname, - size_t linenr) -{ - PRL_RESULT ret, retCode; - - if ((ret = PrlJob_Wait(job, timeout))) { - logPrlErrorHelper(ret, filename, funcname, linenr); - goto cleanup; - } - - if ((ret = PrlJob_GetRetCode(job, &retCode))) { - logPrlErrorHelper(ret, filename, funcname, linenr); - goto cleanup; - } - - if (retCode) { - PRL_HANDLE err_handle; - - /* Sometimes it's possible to get additional error info. */ - if ((ret = PrlJob_GetError(job, &err_handle))) { - logPrlErrorHelper(ret, filename, funcname, linenr); - goto cleanup; - } - - if (logPrlEventErrorHelper(err_handle, filename, funcname, linenr)) - logPrlErrorHelper(retCode, filename, funcname, linenr); - - PrlHandle_Free(err_handle); - ret = retCode; - } else { - ret = PrlJob_GetResult(job, result); - if (PRL_FAILED(ret)) { - logPrlErrorHelper(ret, filename, funcname, linenr); - PrlHandle_Free(*result); - *result = NULL; - goto cleanup; - } - - ret = PRL_ERR_SUCCESS; - } - - cleanup: - PrlHandle_Free(job); - return ret; -} - -#define getJobResult(job, result) \ - getJobResultHelper(job, JOB_INFINIT_WAIT_TIMEOUT, \ - result, __FILE__, __FUNCTION__, __LINE__) - -static PRL_RESULT -waitJobHelper(PRL_HANDLE job, unsigned int timeout, - const char *filename, const char *funcname, - size_t linenr) -{ - PRL_HANDLE result = PRL_INVALID_HANDLE; - PRL_RESULT ret; - - ret = getJobResultHelper(job, timeout, &result, - filename, funcname, linenr); - PrlHandle_Free(result); - return ret; -} - -#define waitJob(job) \ - waitJobHelper(job, JOB_INFINIT_WAIT_TIMEOUT, __FILE__, \ - __FUNCTION__, __LINE__) - - -int -prlsdkInit(void) -{ - PRL_RESULT ret; - - /* Disable console output */ - PrlApi_SwitchConsoleLogging(0); - - ret = PrlApi_InitEx(PARALLELS_API_VER, PAM_SERVER, 0, 0); - if (PRL_FAILED(ret)) { - logPrlError(ret); - return -1; - } - - return 0; -}; - -void -prlsdkDeinit(void) -{ - PrlApi_Deinit(); -}; - -int -prlsdkConnect(vzConnPtr privconn) -{ - PRL_RESULT ret; - PRL_HANDLE job = PRL_INVALID_HANDLE; - - ret = PrlSrv_Create(&privconn->server); - if (PRL_FAILED(ret)) { - logPrlError(ret); - return -1; - } - - job = PrlSrv_LoginLocalEx(privconn->server, NULL, 0, - PSL_HIGH_SECURITY, PACF_NON_INTERACTIVE_MODE); - - if (waitJob(job)) { - PrlHandle_Free(privconn->server); - return -1; - } - - return 0; -} - -void -prlsdkDisconnect(vzConnPtr privconn) -{ - PRL_HANDLE job; - - job = PrlSrv_Logoff(privconn->server); - waitJob(job); - - PrlHandle_Free(privconn->server); -} - -static int -prlsdkSdkDomainLookup(vzConnPtr privconn, - const char *id, - unsigned int flags, - PRL_HANDLE *sdkdom) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - PRL_HANDLE result = PRL_INVALID_HANDLE; - PRL_RESULT pret = PRL_ERR_UNINITIALIZED; - int ret = -1; - - job = PrlSrv_GetVmConfig(privconn->server, id, flags); - if (PRL_FAILED(getJobResult(job, &result))) - goto cleanup; - - pret = PrlResult_GetParamByIndex(result, 0, sdkdom); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - - cleanup: - PrlHandle_Free(result); - return ret; -} - -static void -prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr) -{ - virUUIDFormat(uuid, uuidstr + 1); - - uuidstr[0] = '{'; - uuidstr[VIR_UUID_STRING_BUFLEN] = '}'; - uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0'; -} - -static PRL_HANDLE -prlsdkSdkDomainLookupByUUID(vzConnPtr privconn, const unsigned char *uuid) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; - PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; - - prlsdkUUIDFormat(uuid, uuidstr); - - if (prlsdkSdkDomainLookup(privconn, uuidstr, - PGVC_SEARCH_BY_UUID, &sdkdom) < 0) { - virUUIDFormat(uuid, uuidstr); - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s'"), uuidstr); - return PRL_INVALID_HANDLE; - } - - return sdkdom; -} - -static int -prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid) -{ - char *tmp = NULL; - int ret = -1; - - virCheckNonNullArgGoto(uuidstr, error); - virCheckNonNullArgGoto(uuid, error); - - if (VIR_STRDUP(tmp, uuidstr) < 0) - goto error; - - tmp[strlen(tmp) - 1] = '\0'; - - /* trim curly braces */ - if (virUUIDParse(tmp + 1, uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("UUID in config file malformed")); - ret = -1; - goto error; - } - - ret = 0; - error: - VIR_FREE(tmp); - return ret; -} - -static int -prlsdkGetDomainIds(PRL_HANDLE sdkdom, - char **name, - unsigned char *uuid) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; - PRL_UINT32 len; - PRL_RESULT pret; - - len = 0; - /* get name length */ - pret = PrlVmCfg_GetName(sdkdom, NULL, &len); - prlsdkCheckRetGoto(pret, error); - - if (VIR_ALLOC_N(*name, len) < 0) - goto error; - - PrlVmCfg_GetName(sdkdom, *name, &len); - prlsdkCheckRetGoto(pret, error); - - len = sizeof(uuidstr); - PrlVmCfg_GetUuid(sdkdom, uuidstr, &len); - prlsdkCheckRetGoto(pret, error); - - if (prlsdkUUIDParse(uuidstr, uuid) < 0) - goto error; - - return 0; - - error: - VIR_FREE(*name); - return -1; -} - -static int -prlsdkGetDomainState(PRL_HANDLE sdkdom, VIRTUAL_MACHINE_STATE_PTR vmState) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - PRL_HANDLE result = PRL_INVALID_HANDLE; - PRL_HANDLE vmInfo = PRL_INVALID_HANDLE; - PRL_RESULT pret; - int ret = -1; - - job = PrlVm_GetState(sdkdom); - - if (PRL_FAILED(getJobResult(job, &result))) - goto cleanup; - - pret = PrlResult_GetParamByIndex(result, 0, &vmInfo); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmInfo_GetState(vmInfo, vmState); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - - cleanup: - PrlHandle_Free(vmInfo); - PrlHandle_Free(result); - return ret; -} - -static void -prlsdkDomObjFreePrivate(void *p) -{ - vzDomObjPtr pdom = p; - - if (!pdom) - return; - - PrlHandle_Free(pdom->sdkdom); - PrlHandle_Free(pdom->cache.stats); - virCondDestroy(&pdom->cache.cond); - VIR_FREE(pdom->uuid); - VIR_FREE(pdom->home); - VIR_FREE(p); -}; - -static int -prlsdkAddDomainVideoInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - virDomainVideoDefPtr video = NULL; - virDomainVideoAccelDefPtr accel = NULL; - PRL_RESULT ret; - PRL_UINT32 videoRam; - - /* video info */ - ret = PrlVmCfg_GetVideoRamSize(sdkdom, &videoRam); - prlsdkCheckRetGoto(ret, error); - - if (VIR_ALLOC(video) < 0) - goto error; - - if (VIR_ALLOC(accel) < 0) - goto error; - - if (VIR_APPEND_ELEMENT_COPY(def->videos, def->nvideos, video) < 0) - goto error; - - video->type = VIR_DOMAIN_VIDEO_TYPE_VGA; - video->vram = videoRam << 10; /* from mbibytes to kbibytes */ - video->heads = 1; - video->accel = accel; - - return 0; - - error: - VIR_FREE(accel); - virDomainVideoDefFree(video); - return -1; -} - -static int -prlsdkGetDiskInfo(PRL_HANDLE prldisk, - virDomainDiskDefPtr disk, - bool isCdrom, - bool isCt) -{ - char *buf = NULL; - PRL_UINT32 buflen = 0; - PRL_RESULT pret; - PRL_UINT32 emulatedType; - PRL_UINT32 ifType; - PRL_UINT32 pos; - virDomainDeviceDriveAddressPtr address; - int ret = -1; - - pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType); - prlsdkCheckRetGoto(pret, cleanup); - if (emulatedType == PDT_USE_IMAGE_FILE) { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); - if (isCdrom) - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); - else - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); - } else { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); - } - - if (isCdrom) { - disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - disk->src->readonly = true; - } else { - disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; - } - - pret = PrlVmDev_GetFriendlyName(prldisk, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(buf, buflen) < 0) - goto cleanup; - - pret = PrlVmDev_GetFriendlyName(prldisk, buf, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (virDomainDiskSetSource(disk, buf) < 0) - goto cleanup; - - /* Let physical devices added to CT look like SATA disks */ - if (isCt) { - ifType = PMS_SATA_DEVICE; - } else { - pret = PrlVmDev_GetIfaceType(prldisk, &ifType); - prlsdkCheckRetGoto(pret, cleanup); - } - - pret = PrlVmDev_GetStackIndex(prldisk, &pos); - prlsdkCheckRetGoto(pret, cleanup); - - address = &disk->info.addr.drive; - switch (ifType) { - case PMS_IDE_DEVICE: - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - disk->dst = virIndexToDiskName(pos, "hd"); - address->bus = pos / 2; - address->target = 0; - address->unit = pos % 2; - break; - case PMS_SCSI_DEVICE: - disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; - disk->dst = virIndexToDiskName(pos, "sd"); - address->bus = 0; - address->target = 0; - address->unit = pos; - break; - case PMS_SATA_DEVICE: - disk->bus = VIR_DOMAIN_DISK_BUS_SATA; - disk->dst = virIndexToDiskName(pos, "sd"); - address->bus = 0; - address->target = 0; - address->unit = pos; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown disk bus: %X"), ifType); - goto cleanup; - break; - } - - if (!disk->dst) - goto cleanup; - - disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; - - ret = 0; - - cleanup: - VIR_FREE(buf); - return ret; -} - -static int -prlsdkGetFSInfo(PRL_HANDLE prldisk, - virDomainFSDefPtr fs) -{ - char *buf = NULL; - PRL_UINT32 buflen = 0; - PRL_RESULT pret; - int ret = -1; - - fs->type = VIR_DOMAIN_FS_TYPE_FILE; - fs->fsdriver = VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP; - fs->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; - fs->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT; - fs->format = VIR_STORAGE_FILE_PLOOP; - - fs->readonly = false; - fs->symlinksResolved = false; - - pret = PrlVmDev_GetImagePath(prldisk, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(buf, buflen) < 0) - goto cleanup; - - pret = PrlVmDev_GetImagePath(prldisk, buf, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - fs->src = buf; - buf = NULL; - - pret = PrlVmDevHd_GetMountPoint(prldisk, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(buf, buflen) < 0) - goto cleanup; - - pret = PrlVmDevHd_GetMountPoint(prldisk, buf, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - fs->dst = buf; - buf = NULL; - - ret = 0; - - cleanup: - VIR_FREE(buf); - return ret; -} - -static int -prlsdkAddDomainHardDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - PRL_RESULT pret; - PRL_UINT32 hddCount; - PRL_UINT32 i; - PRL_HANDLE hdd = PRL_INVALID_HANDLE; - virDomainDiskDefPtr disk = NULL; - virDomainFSDefPtr fs = NULL; - - pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); - prlsdkCheckRetGoto(pret, error); - - for (i = 0; i < hddCount; ++i) { - - PRL_UINT32 emulatedType; - - pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); - prlsdkCheckRetGoto(pret, error); - - pret = PrlVmDev_GetEmulatedType(hdd, &emulatedType); - prlsdkCheckRetGoto(pret, error); - - if (PDT_USE_REAL_DEVICE != emulatedType && IS_CT(def)) { - - if (VIR_ALLOC(fs) < 0) - goto error; - - if (prlsdkGetFSInfo(hdd, fs) < 0) - goto error; - - if (virDomainFSInsert(def, fs) < 0) - goto error; - - fs = NULL; - PrlHandle_Free(hdd); - hdd = PRL_INVALID_HANDLE; - } else { - if (!(disk = virDomainDiskDefNew(NULL))) - goto error; - - if (prlsdkGetDiskInfo(hdd, disk, false, IS_CT(def)) < 0) - goto error; - - if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) - goto error; - - disk = NULL; - PrlHandle_Free(hdd); - hdd = PRL_INVALID_HANDLE; - } - } - - return 0; - - error: - PrlHandle_Free(hdd); - virDomainDiskDefFree(disk); - virDomainFSDefFree(fs); - return -1; -} - -static int -prlsdkAddDomainOpticalDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - PRL_RESULT pret; - PRL_UINT32 cdromsCount; - PRL_UINT32 i; - PRL_HANDLE cdrom = PRL_INVALID_HANDLE; - virDomainDiskDefPtr disk = NULL; - - pret = PrlVmCfg_GetOpticalDisksCount(sdkdom, &cdromsCount); - prlsdkCheckRetGoto(pret, error); - - for (i = 0; i < cdromsCount; ++i) { - pret = PrlVmCfg_GetOpticalDisk(sdkdom, i, &cdrom); - prlsdkCheckRetGoto(pret, error); - - if (!(disk = virDomainDiskDefNew(NULL))) - goto error; - - if (prlsdkGetDiskInfo(cdrom, disk, true, IS_CT(def)) < 0) - goto error; - - PrlHandle_Free(cdrom); - cdrom = PRL_INVALID_HANDLE; - - if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) - goto error; - } - - return 0; - - error: - PrlHandle_Free(cdrom); - virDomainDiskDefFree(disk); - return -1; -} - -static int -prlsdkGetNetInfo(PRL_HANDLE netAdapter, virDomainNetDefPtr net, bool isCt) -{ - char macstr[VIR_MAC_STRING_BUFLEN]; - PRL_UINT32 buflen; - PRL_UINT32 netAdapterIndex; - PRL_UINT32 emulatedType; - PRL_RESULT pret; - PRL_BOOL isConnected; - int ret = -1; - - net->type = VIR_DOMAIN_NET_TYPE_NETWORK; - - - /* use device name, shown by prlctl as target device - * for identifying network adapter in virDomainDefineXML */ - pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(net->ifname, buflen) < 0) - goto cleanup; - - pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, net->ifname, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_GetIndex(netAdapter, &netAdapterIndex); - prlsdkCheckRetGoto(pret, cleanup); - - if (isCt && netAdapterIndex == (PRL_UINT32) -1) { - /* venet devices don't have mac address and - * always up */ - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; - if (VIR_STRDUP(net->data.network.name, - PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) - goto cleanup; - return 0; - } - - buflen = ARRAY_CARDINALITY(macstr); - if (VIR_ALLOC_N(macstr, buflen)) - goto cleanup; - pret = PrlVmDevNet_GetMacAddressCanonical(netAdapter, macstr, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (virMacAddrParse(macstr, &net->mac) < 0) - goto cleanup; - - pret = PrlVmDev_GetEmulatedType(netAdapter, &emulatedType); - prlsdkCheckRetGoto(pret, cleanup); - - if (emulatedType == PNA_ROUTED) { - if (VIR_STRDUP(net->data.network.name, - PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) - goto cleanup; - } else { - pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(net->data.network.name, buflen) < 0) - goto cleanup; - - pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, - net->data.network.name, - &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - /* - * We use VIR_DOMAIN_NET_TYPE_NETWORK for all network adapters - * except those whose Virtual Network Id differ from Parallels - * predefined ones such as PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME - * and PARALLELS_DONAIN_ROUTED_NETWORK_NAME - */ - if (STRNEQ(net->data.network.name, PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME)) - net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; - - } - - if (!isCt) { - PRL_VM_NET_ADAPTER_TYPE type; - pret = PrlVmDevNet_GetAdapterType(netAdapter, &type); - prlsdkCheckRetGoto(pret, cleanup); - - switch (type) { - case PNT_RTL: - if (VIR_STRDUP(net->model, "rtl8139") < 0) - goto cleanup; - break; - case PNT_E1000: - if (VIR_STRDUP(net->model, "e1000") < 0) - goto cleanup; - break; - case PNT_VIRTIO: - if (VIR_STRDUP(net->model, "virtio") < 0) - goto cleanup; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown adapter type: %X"), type); - goto cleanup; - } - } - - pret = PrlVmDev_IsConnected(netAdapter, &isConnected); - prlsdkCheckRetGoto(pret, cleanup); - - if (isConnected) - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; - else - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; - - ret = 0; - cleanup: - return ret; -} - -static int -prlsdkAddDomainNetInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - virDomainNetDefPtr net = NULL; - PRL_RESULT ret; - PRL_HANDLE netAdapter; - PRL_UINT32 netAdaptersCount; - PRL_UINT32 i; - - ret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &netAdaptersCount); - prlsdkCheckRetGoto(ret, error); - for (i = 0; i < netAdaptersCount; ++i) { - ret = PrlVmCfg_GetNetAdapter(sdkdom, i, &netAdapter); - prlsdkCheckRetGoto(ret, error); - - if (VIR_ALLOC(net) < 0) - goto error; - - if (prlsdkGetNetInfo(netAdapter, net, IS_CT(def)) < 0) - goto error; - - PrlHandle_Free(netAdapter); - netAdapter = PRL_INVALID_HANDLE; - - if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0) - goto error; - } - - return 0; - - error: - PrlHandle_Free(netAdapter); - virDomainNetDefFree(net); - return -1; -} - -static int -prlsdkGetSerialInfo(PRL_HANDLE serialPort, virDomainChrDefPtr chr) -{ - PRL_RESULT pret; - PRL_UINT32 serialPortIndex; - PRL_UINT32 emulatedType; - char *friendlyName = NULL; - PRL_UINT32 buflen; - - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - chr->targetTypeAttr = false; - pret = PrlVmDev_GetIndex(serialPort, &serialPortIndex); - prlsdkCheckRetGoto(pret, error); - chr->target.port = serialPortIndex; - - pret = PrlVmDev_GetEmulatedType(serialPort, &emulatedType); - prlsdkCheckRetGoto(pret, error); - - pret = PrlVmDev_GetFriendlyName(serialPort, NULL, &buflen); - prlsdkCheckRetGoto(pret, error); - - if (VIR_ALLOC_N(friendlyName, buflen) < 0) - goto error; - - pret = PrlVmDev_GetFriendlyName(serialPort, friendlyName, &buflen); - prlsdkCheckRetGoto(pret, error); - - switch (emulatedType) { - case PDT_USE_OUTPUT_FILE: - chr->source.type = VIR_DOMAIN_CHR_TYPE_FILE; - chr->source.data.file.path = friendlyName; - break; - case PDT_USE_SERIAL_PORT_SOCKET_MODE: - chr->source.type = VIR_DOMAIN_CHR_TYPE_UNIX; - chr->source.data.nix.path = friendlyName; - break; - case PDT_USE_REAL_DEVICE: - chr->source.type = VIR_DOMAIN_CHR_TYPE_DEV; - chr->source.data.file.path = friendlyName; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown serial type: %X"), emulatedType); - goto error; - break; - } - - return 0; - error: - VIR_FREE(friendlyName); - return -1; -} - - -static int -prlsdkAddSerialInfo(PRL_HANDLE sdkdom, - virDomainChrDefPtr **serials, - size_t *nserials) -{ - PRL_RESULT ret; - PRL_HANDLE serialPort; - PRL_UINT32 serialPortsCount; - PRL_UINT32 i; - virDomainChrDefPtr chr = NULL; - - ret = PrlVmCfg_GetSerialPortsCount(sdkdom, &serialPortsCount); - prlsdkCheckRetGoto(ret, cleanup); - for (i = 0; i < serialPortsCount; ++i) { - ret = PrlVmCfg_GetSerialPort(sdkdom, i, &serialPort); - prlsdkCheckRetGoto(ret, cleanup); - - if (!(chr = virDomainChrDefNew())) - goto cleanup; - - if (prlsdkGetSerialInfo(serialPort, chr)) - goto cleanup; - - PrlHandle_Free(serialPort); - serialPort = PRL_INVALID_HANDLE; - - if (VIR_APPEND_ELEMENT(*serials, *nserials, chr) < 0) - goto cleanup; - } - - return 0; - - cleanup: - PrlHandle_Free(serialPort); - virDomainChrDefFree(chr); - return -1; -} - - -static int -prlsdkAddDomainHardware(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - if (!IS_CT(def)) - if (prlsdkAddDomainVideoInfo(sdkdom, def) < 0) - goto error; - - if (prlsdkAddDomainHardDisksInfo(sdkdom, def) < 0) - goto error; - - if (prlsdkAddDomainOpticalDisksInfo(sdkdom, def) < 0) - goto error; - - if (prlsdkAddDomainNetInfo(sdkdom, def) < 0) - goto error; - - if (prlsdkAddSerialInfo(sdkdom, - &def->serials, - &def->nserials) < 0) - goto error; - - return 0; - error: - return -1; -} - - -static int -prlsdkAddVNCInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - virDomainGraphicsDefPtr gr = NULL; - PRL_VM_REMOTE_DISPLAY_MODE vncMode; - PRL_UINT32 port; - PRL_UINT32 buflen = 0; - PRL_RESULT pret; - - pret = PrlVmCfg_GetVNCMode(sdkdom, &vncMode); - prlsdkCheckRetGoto(pret, error); - - if (vncMode == PRD_DISABLED) - return 0; - - if (VIR_ALLOC(gr) < 0) - goto error; - - pret = PrlVmCfg_GetVNCPort(sdkdom, &port); - prlsdkCheckRetGoto(pret, error); - - gr->data.vnc.autoport = (vncMode == PRD_AUTO); - gr->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; - gr->data.vnc.port = port; - gr->data.vnc.keymap = NULL; - gr->data.vnc.socket = NULL; - gr->data.vnc.auth.passwd = NULL; - gr->data.vnc.auth.expires = false; - gr->data.vnc.auth.connected = 0; - - if (VIR_ALLOC(gr->listens) < 0) - goto error; - - gr->nListens = 1; - - pret = PrlVmCfg_GetVNCHostName(sdkdom, NULL, &buflen); - prlsdkCheckRetGoto(pret, error); - - if (VIR_ALLOC_N(gr->listens[0].address, buflen) < 0) - goto error; - - pret = PrlVmCfg_GetVNCHostName(sdkdom, gr->listens[0].address, &buflen); - prlsdkCheckRetGoto(pret, error); - - gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; - - if (VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr) < 0) - goto error; - - if (IS_CT(def)) { - virDomainVideoDefPtr video; - if (VIR_ALLOC(video) < 0) - goto error; - video->type = virDomainVideoDefaultType(def); - if (video->type < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot determine default video type")); - VIR_FREE(video); - goto error; - } - video->vram = virDomainVideoDefaultRAM(def, video->type); - video->heads = 1; - if (VIR_ALLOC_N(def->videos, 1) < 0) { - virDomainVideoDefFree(video); - goto error; - } - def->videos[def->nvideos++] = video; - } - return 0; - - error: - virDomainGraphicsDefFree(gr); - return -1; -} - -static int -prlsdkConvertDomainState(VIRTUAL_MACHINE_STATE domainState, - PRL_UINT32 envId, - virDomainObjPtr dom) -{ - switch (domainState) { - case VMS_STOPPED: - case VMS_MOUNTED: - virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, - VIR_DOMAIN_SHUTOFF_SHUTDOWN); - dom->def->id = -1; - break; - case VMS_STARTING: - case VMS_COMPACTING: - case VMS_RESETTING: - case VMS_PAUSING: - case VMS_RECONNECTING: - case VMS_RUNNING: - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_BOOTED); - dom->def->id = envId; - break; - case VMS_PAUSED: - virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, - VIR_DOMAIN_PAUSED_USER); - dom->def->id = envId; - break; - case VMS_SUSPENDED: - case VMS_DELETING_STATE: - case VMS_SUSPENDING_SYNC: - virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, - VIR_DOMAIN_SHUTOFF_SAVED); - dom->def->id = -1; - break; - case VMS_STOPPING: - virDomainObjSetState(dom, VIR_DOMAIN_SHUTDOWN, - VIR_DOMAIN_SHUTDOWN_USER); - dom->def->id = envId; - break; - case VMS_SNAPSHOTING: - virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, - VIR_DOMAIN_PAUSED_SNAPSHOT); - dom->def->id = envId; - break; - case VMS_MIGRATING: - virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, - VIR_DOMAIN_PAUSED_MIGRATION); - dom->def->id = envId; - break; - case VMS_SUSPENDING: - virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, - VIR_DOMAIN_PAUSED_SAVE); - dom->def->id = envId; - break; - case VMS_RESTORING: - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_RESTORED); - dom->def->id = envId; - break; - case VMS_CONTINUING: - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_UNPAUSED); - dom->def->id = envId; - break; - case VMS_RESUMING: - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_RESTORED); - dom->def->id = envId; - break; - case VMS_UNKNOWN: - virDomainObjSetState(dom, VIR_DOMAIN_NOSTATE, - VIR_DOMAIN_NOSTATE_UNKNOWN); - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown domain state: %X"), domainState); - return -1; - break; - } - - return 0; -} - -static int -prlsdkConvertCpuInfo(PRL_HANDLE sdkdom, - virDomainDefPtr def) -{ - char *buf; - PRL_UINT32 buflen = 0; - int hostcpus; - PRL_UINT32 cpuCount; - PRL_RESULT pret; - int ret = -1; - - if ((hostcpus = nodeGetCPUCount()) < 0) - goto cleanup; - - /* get number of CPUs */ - pret = PrlVmCfg_GetCpuCount(sdkdom, &cpuCount); - prlsdkCheckRetGoto(pret, cleanup); - - if (cpuCount > hostcpus) - cpuCount = hostcpus; - - def->vcpus = cpuCount; - def->maxvcpus = cpuCount; - - pret = PrlVmCfg_GetCpuMask(sdkdom, NULL, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(buf, buflen) < 0) - goto cleanup; - - pret = PrlVmCfg_GetCpuMask(sdkdom, buf, &buflen); - - if (strlen(buf) == 0) { - if (!(def->cpumask = virBitmapNew(hostcpus))) - goto cleanup; - virBitmapSetAll(def->cpumask); - } else { - if (virBitmapParse(buf, 0, &def->cpumask, hostcpus) < 0) - goto cleanup; - } - - ret = 0; - cleanup: - VIR_FREE(buf); - return ret; -} - -static int -prlsdkConvertDomainType(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - PRL_VM_TYPE domainType; - PRL_RESULT pret; - - pret = PrlVmCfg_GetVmType(sdkdom, &domainType); - prlsdkCheckRetGoto(pret, error); - - switch (domainType) { - case PVT_VM: - def->os.type = VIR_DOMAIN_OSTYPE_HVM; - break; - case PVT_CT: - def->os.type = VIR_DOMAIN_OSTYPE_EXE; - if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) - return -1; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown domain type: %X"), domainType); - return -1; - } - - return 0; - - error: - return -1; -} - -static int -prlsdkConvertCpuMode(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - PRL_RESULT pret; - PRL_CPU_MODE cpuMode; - - pret = PrlVmCfg_GetCpuMode(sdkdom, &cpuMode); - prlsdkCheckRetGoto(pret, error); - - switch (cpuMode) { - case PCM_CPU_MODE_32: - def->os.arch = VIR_ARCH_I686; - break; - case PCM_CPU_MODE_64: - def->os.arch = VIR_ARCH_X86_64; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU mode: %X"), cpuMode); - return -1; - } - - return 0; - error: - return -1; -} - -/* - * This function retrieves information about domain. - * If the domains is already in the domains list - * privconn->domains, then locked 'olddom' must be - * provided. If the domains must be added to the list, - * olddom must be NULL. - * - * The function return a pointer to a locked virDomainObj. - */ -static virDomainObjPtr -prlsdkLoadDomain(vzConnPtr privconn, - PRL_HANDLE sdkdom, - virDomainObjPtr olddom) -{ - virDomainObjPtr dom = NULL; - virDomainDefPtr def = NULL; - vzDomObjPtr pdom = NULL; - VIRTUAL_MACHINE_STATE domainState; - - PRL_UINT32 buflen = 0; - PRL_RESULT pret; - PRL_UINT32 ram; - PRL_UINT32 envId; - PRL_VM_AUTOSTART_OPTION autostart; - - virCheckNonNullArgGoto(privconn, error); - virCheckNonNullArgGoto(sdkdom, error); - - if (!(def = virDomainDefNew())) - goto error; - - if (!olddom) { - if (VIR_ALLOC(pdom) < 0) - goto error; - } else { - pdom = olddom->privateData; - } - - if (STREQ(privconn->drivername, "vz")) - def->virtType = VIR_DOMAIN_VIRT_VZ; - else - def->virtType = VIR_DOMAIN_VIRT_PARALLELS; - - def->id = -1; - - /* we will remove this field in the near future, so let's set it - * to NULL temporarily */ - pdom->uuid = NULL; - - pdom->cache.stats = PRL_INVALID_HANDLE; - pdom->cache.count = -1; - if (virCondInit(&pdom->cache.cond) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize condition")); - goto error; - } - - if (prlsdkGetDomainIds(sdkdom, &def->name, def->uuid) < 0) - goto error; - - def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; - def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; - def->onCrash = VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY; - - /* get RAM parameters */ - pret = PrlVmCfg_GetRamSize(sdkdom, &ram); - prlsdkCheckRetGoto(pret, error); - virDomainDefSetMemoryInitial(def, ram << 10); /* RAM size obtained in Mbytes, - convert to Kbytes */ - def->mem.cur_balloon = ram << 10; - - if (prlsdkConvertCpuInfo(sdkdom, def) < 0) - goto error; - - if (prlsdkConvertCpuMode(sdkdom, def) < 0) - goto error; - - if (prlsdkConvertDomainType(sdkdom, def) < 0) - goto error; - - if (prlsdkAddDomainHardware(sdkdom, def) < 0) - goto error; - - if (prlsdkAddVNCInfo(sdkdom, def) < 0) - goto error; - - pret = PrlVmCfg_GetEnvId(sdkdom, &envId); - prlsdkCheckRetGoto(pret, error); - pdom->id = envId; - - buflen = 0; - pret = PrlVmCfg_GetHomePath(sdkdom, NULL, &buflen); - prlsdkCheckRetGoto(pret, error); - - VIR_FREE(pdom->home); - if (VIR_ALLOC_N(pdom->home, buflen) < 0) - goto error; - - pret = PrlVmCfg_GetHomePath(sdkdom, pdom->home, &buflen); - prlsdkCheckRetGoto(pret, error); - - /* For VMs pdom->home is actually /directory/config.pvs */ - if (!IS_CT(def)) { - /* Get rid of /config.pvs in path string */ - char *s = strrchr(pdom->home, '/'); - if (s) - *s = '\0'; - } - - pret = PrlVmCfg_GetAutoStart(sdkdom, &autostart); - prlsdkCheckRetGoto(pret, error); - - if (prlsdkGetDomainState(sdkdom, &domainState) < 0) - goto error; - - if (virDomainDefAddImplicitControllers(def) < 0) - goto error; - - if (def->ngraphics > 0) { - int bus = IS_CT(def) ? VIR_DOMAIN_INPUT_BUS_PARALLELS: - VIR_DOMAIN_INPUT_BUS_PS2; - - if (virDomainDefMaybeAddInput(def, - VIR_DOMAIN_INPUT_TYPE_MOUSE, - bus) < 0) - goto error; - - if (virDomainDefMaybeAddInput(def, - VIR_DOMAIN_INPUT_TYPE_KBD, - bus) < 0) - goto error; - } - - if (olddom) { - /* assign new virDomainDef without any checks */ - /* we can't use virDomainObjAssignDef, because it checks - * for state and domain name */ - dom = olddom; - virDomainDefFree(dom->def); - dom->def = def; - } else { - if (!(dom = virDomainObjListAdd(privconn->domains, def, - privconn->xmlopt, - 0, NULL))) - goto error; - } - /* dom is locked here */ - - dom->privateData = pdom; - dom->privateDataFreeFunc = prlsdkDomObjFreePrivate; - dom->persistent = 1; - - switch (autostart) { - case PAO_VM_START_ON_LOAD: - dom->autostart = 1; - break; - case PAO_VM_START_MANUAL: - dom->autostart = 0; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown autostart mode: %X"), autostart); - goto error; - } - - if (prlsdkConvertDomainState(domainState, envId, dom) < 0) - goto error; - - if (!pdom->sdkdom) { - pret = PrlHandle_AddRef(sdkdom); - prlsdkCheckRetGoto(pret, error); - pdom->sdkdom = sdkdom; - } - - return dom; - error: - if (dom && !olddom) { - /* Domain isn't persistent means that we haven't yet set - * prlsdkDomObjFreePrivate and should call it manually - */ - if (!dom->persistent) - prlsdkDomObjFreePrivate(pdom); - - virDomainObjListRemove(privconn->domains, dom); - } - /* Delete newly allocated def only if we haven't assigned it to domain - * Otherwise we will end up with domain having invalid def within it - */ - if (!dom) - virDomainDefFree(def); - - return NULL; -} - -int -prlsdkLoadDomains(vzConnPtr privconn) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - PRL_HANDLE result; - PRL_HANDLE sdkdom; - PRL_UINT32 paramsCount; - PRL_RESULT pret; - size_t i = 0; - virDomainObjPtr dom; - - job = PrlSrv_GetVmListEx(privconn->server, PVTF_VM | PVTF_CT); - - if (PRL_FAILED(getJobResult(job, &result))) - return -1; - - pret = PrlResult_GetParamsCount(result, ¶msCount); - prlsdkCheckRetGoto(pret, error); - - for (i = 0; i < paramsCount; i++) { - pret = PrlResult_GetParamByIndex(result, i, &sdkdom); - if (PRL_FAILED(pret)) { - logPrlError(pret); - PrlHandle_Free(sdkdom); - goto error; - } - - dom = prlsdkLoadDomain(privconn, sdkdom, NULL); - PrlHandle_Free(sdkdom); - - if (!dom) - goto error; - else - virObjectUnlock(dom); - } - - PrlHandle_Free(result); - return 0; - - error: - PrlHandle_Free(result); - return -1; -} - -virDomainObjPtr -prlsdkAddDomain(vzConnPtr privconn, const unsigned char *uuid) -{ - PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; - virDomainObjPtr dom; - - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - if (dom) { - /* domain is already in the list */ - return dom; - } - - sdkdom = prlsdkSdkDomainLookupByUUID(privconn, uuid); - if (sdkdom == PRL_INVALID_HANDLE) - return NULL; - - dom = prlsdkLoadDomain(privconn, sdkdom, NULL); - PrlHandle_Free(sdkdom); - return dom; -} - -int -prlsdkUpdateDomain(vzConnPtr privconn, virDomainObjPtr dom) -{ - PRL_HANDLE job; - virDomainObjPtr retdom = NULL; - vzDomObjPtr pdom = dom->privateData; - - job = PrlVm_RefreshConfig(pdom->sdkdom); - if (waitJob(job)) - return -1; - - retdom = prlsdkLoadDomain(privconn, pdom->sdkdom, dom); - return retdom ? 0 : -1; -} - -static int prlsdkSendEvent(vzConnPtr privconn, - virDomainObjPtr dom, - virDomainEventType lvEventType, - int lvEventTypeDetails) -{ - virObjectEventPtr event = NULL; - - event = virDomainEventLifecycleNewFromObj(dom, - lvEventType, - lvEventTypeDetails); - if (!event) - return -1; - - virObjectEventStateQueue(privconn->domainEventState, event); - return 0; -} - -static void -prlsdkNewStateToEvent(VIRTUAL_MACHINE_STATE domainState, - virDomainEventType *lvEventType, - int *lvEventTypeDetails) -{ - /* We skip all intermediate states here, because - * libvirt doesn't have correspoding event types for - * them */ - switch (domainState) { - case VMS_STOPPED: - case VMS_MOUNTED: - *lvEventType = VIR_DOMAIN_EVENT_STOPPED; - *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN; - break; - case VMS_RUNNING: - *lvEventType = VIR_DOMAIN_EVENT_STARTED; - *lvEventTypeDetails = VIR_DOMAIN_EVENT_STARTED_BOOTED; - break; - case VMS_PAUSED: - *lvEventType = VIR_DOMAIN_EVENT_SUSPENDED; - *lvEventTypeDetails = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED; - break; - case VMS_SUSPENDED: - *lvEventType = VIR_DOMAIN_EVENT_STOPPED; - *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SAVED; - break; - default: - VIR_DEBUG("Skip sending event about changing state to %X", - domainState); - break; - } -} - -static void -prlsdkHandleVmStateEvent(vzConnPtr privconn, - PRL_HANDLE prlEvent, - unsigned char *uuid) -{ - PRL_RESULT pret = PRL_ERR_FAILURE; - PRL_HANDLE eventParam = PRL_INVALID_HANDLE; - PRL_INT32 domainState; - virDomainObjPtr dom = NULL; - vzDomObjPtr pdom; - virDomainEventType lvEventType = 0; - int lvEventTypeDetails = 0; - - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - if (dom == NULL) - return; - - pret = PrlEvent_GetParamByName(prlEvent, "vminfo_vm_state", &eventParam); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlEvtPrm_ToInt32(eventParam, &domainState); - prlsdkCheckRetGoto(pret, cleanup); - - pdom = dom->privateData; - if (prlsdkConvertDomainState(domainState, pdom->id, dom) < 0) - goto cleanup; - - prlsdkNewStateToEvent(domainState, - &lvEventType, - &lvEventTypeDetails); - - prlsdkSendEvent(privconn, dom, lvEventType, lvEventTypeDetails); - - cleanup: - virObjectUnlock(dom); - return; -} - -static void -prlsdkHandleVmConfigEvent(vzConnPtr privconn, - unsigned char *uuid) -{ - virDomainObjPtr dom = NULL; - - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - if (dom == NULL) - return; - - if (prlsdkUpdateDomain(privconn, dom) < 0) - goto cleanup; - - prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, - VIR_DOMAIN_EVENT_DEFINED_UPDATED); - - cleanup: - virObjectUnlock(dom); - return; -} - -static void -prlsdkHandleVmAddedEvent(vzConnPtr privconn, - unsigned char *uuid) -{ - virDomainObjPtr dom = NULL; - - dom = prlsdkAddDomain(privconn, uuid); - if (dom == NULL) - return; - - prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, - VIR_DOMAIN_EVENT_DEFINED_ADDED); - - virObjectUnlock(dom); - return; -} - -static void -prlsdkHandleVmRemovedEvent(vzConnPtr privconn, - unsigned char *uuid) -{ - virDomainObjPtr dom = NULL; - - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - /* domain was removed from the list from the libvirt - * API function in current connection */ - if (dom == NULL) - return; - - prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, - VIR_DOMAIN_EVENT_UNDEFINED_REMOVED); - - virDomainObjListRemove(privconn->domains, dom); - return; -} - -#define PARALLELS_STATISTICS_DROP_COUNT 3 - -static PRL_RESULT -prlsdkHandlePerfEvent(vzConnPtr privconn, - PRL_HANDLE event, - unsigned char *uuid) -{ - virDomainObjPtr dom = NULL; - vzDomObjPtr privdom = NULL; - PRL_HANDLE job = PRL_INVALID_HANDLE; - - dom = virDomainObjListFindByUUID(privconn->domains, uuid); - if (dom == NULL) - goto cleanup; - privdom = dom->privateData; - - // delayed event after unsubscribe - if (privdom->cache.count == -1) - goto cleanup; - - PrlHandle_Free(privdom->cache.stats); - privdom->cache.stats = PRL_INVALID_HANDLE; - - if (privdom->cache.count > PARALLELS_STATISTICS_DROP_COUNT) { - job = PrlVm_UnsubscribeFromPerfStats(privdom->sdkdom); - if (PRL_FAILED(waitJob(job))) - goto cleanup; - // change state to unsubscribed - privdom->cache.count = -1; - } else { - ++privdom->cache.count; - privdom->cache.stats = event; - // thus we get own of event handle - event = PRL_INVALID_HANDLE; - virCondSignal(&privdom->cache.cond); - } - - cleanup: - PrlHandle_Free(event); - if (dom) - virObjectUnlock(dom); - - return PRL_ERR_SUCCESS; -} - -static void -prlsdkHandleVmEvent(vzConnPtr privconn, PRL_HANDLE prlEvent) -{ - PRL_RESULT pret = PRL_ERR_FAILURE; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; - unsigned char uuid[VIR_UUID_BUFLEN]; - PRL_UINT32 bufsize = ARRAY_CARDINALITY(uuidstr); - PRL_EVENT_TYPE prlEventType; - - pret = PrlEvent_GetType(prlEvent, &prlEventType); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlEvent_GetIssuerId(prlEvent, uuidstr, &bufsize); - prlsdkCheckRetGoto(pret, cleanup); - - if (prlsdkUUIDParse(uuidstr, uuid) < 0) - goto cleanup; - - switch (prlEventType) { - case PET_DSP_EVT_VM_STATE_CHANGED: - prlsdkHandleVmStateEvent(privconn, prlEvent, uuid); - break; - case PET_DSP_EVT_VM_CONFIG_CHANGED: - prlsdkHandleVmConfigEvent(privconn, uuid); - break; - case PET_DSP_EVT_VM_CREATED: - case PET_DSP_EVT_VM_ADDED: - prlsdkHandleVmAddedEvent(privconn, uuid); - break; - case PET_DSP_EVT_VM_DELETED: - case PET_DSP_EVT_VM_UNREGISTERED: - prlsdkHandleVmRemovedEvent(privconn, uuid); - break; - case PET_DSP_EVT_VM_PERFSTATS: - prlsdkHandlePerfEvent(privconn, prlEvent, uuid); - // above function takes own of event - prlEvent = PRL_INVALID_HANDLE; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Can't handle event of type %d"), prlEventType); - } - - cleanup: - PrlHandle_Free(prlEvent); - return; -} - -static PRL_RESULT -prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) -{ - vzConnPtr privconn = opaque; - PRL_RESULT pret = PRL_ERR_FAILURE; - PRL_HANDLE_TYPE handleType; - PRL_EVENT_ISSUER_TYPE prlIssuerType = PIE_UNKNOWN; - - pret = PrlHandle_GetType(prlEvent, &handleType); - prlsdkCheckRetGoto(pret, cleanup); - - /* Currently, there is no need to handle anything but events */ - if (handleType != PHT_EVENT) - goto cleanup; - - if (privconn == NULL) - goto cleanup; - - PrlEvent_GetIssuerType(prlEvent, &prlIssuerType); - prlsdkCheckRetGoto(pret, cleanup); - - switch (prlIssuerType) { - case PIE_VIRTUAL_MACHINE: - prlsdkHandleVmEvent(privconn, prlEvent); - // above function takes own of event - prlEvent = PRL_INVALID_HANDLE; - break; - default: - VIR_DEBUG("Skipping event of issuer type %d", prlIssuerType); - } - - cleanup: - PrlHandle_Free(prlEvent); - return PRL_ERR_SUCCESS; -} - - -int prlsdkSubscribeToPCSEvents(vzConnPtr privconn) -{ - PRL_RESULT pret = PRL_ERR_UNINITIALIZED; - - pret = PrlSrv_RegEventHandler(privconn->server, - prlsdkEventsHandler, - privconn); - prlsdkCheckRetGoto(pret, error); - return 0; - - error: - return -1; -} - -void prlsdkUnsubscribeFromPCSEvents(vzConnPtr privconn) -{ - PRL_RESULT ret = PRL_ERR_UNINITIALIZED; - ret = PrlSrv_UnregEventHandler(privconn->server, - prlsdkEventsHandler, - privconn); - if (PRL_FAILED(ret)) - logPrlError(ret); -} - -PRL_RESULT prlsdkStart(PRL_HANDLE sdkdom) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_StartEx(sdkdom, PSM_VM_START, 0); - return waitJob(job); -} - -static PRL_RESULT prlsdkStopEx(PRL_HANDLE sdkdom, PRL_UINT32 mode) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_StopEx(sdkdom, mode, 0); - return waitJob(job); -} - -PRL_RESULT prlsdkKill(PRL_HANDLE sdkdom) -{ - return prlsdkStopEx(sdkdom, PSM_KILL); -} - -PRL_RESULT prlsdkStop(PRL_HANDLE sdkdom) -{ - return prlsdkStopEx(sdkdom, PSM_SHUTDOWN); -} - -PRL_RESULT prlsdkPause(PRL_HANDLE sdkdom) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_Pause(sdkdom, false); - return waitJob(job); -} - -PRL_RESULT prlsdkResume(PRL_HANDLE sdkdom) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_Resume(sdkdom); - return waitJob(job); -} - -PRL_RESULT prlsdkSuspend(PRL_HANDLE sdkdom) -{ - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_Suspend(sdkdom); - return waitJob(job); -} - -int -prlsdkDomainChangeStateLocked(vzConnPtr privconn, - virDomainObjPtr dom, - prlsdkChangeStateFunc chstate) -{ - vzDomObjPtr pdom; - PRL_RESULT pret; - virErrorNumber virerr; - - pdom = dom->privateData; - pret = chstate(pdom->sdkdom); - if (PRL_FAILED(pret)) { - virResetLastError(); - - switch (pret) { - case PRL_ERR_DISP_VM_IS_NOT_STARTED: - case PRL_ERR_DISP_VM_IS_NOT_STOPPED: - virerr = VIR_ERR_OPERATION_INVALID; - break; - default: - virerr = VIR_ERR_OPERATION_FAILED; - } - - virReportError(virerr, "%s", _("Can't change domain state.")); - return -1; - } - - return prlsdkUpdateDomain(privconn, dom); -} - -int -prlsdkDomainChangeState(virDomainPtr domain, - prlsdkChangeStateFunc chstate) -{ - vzConnPtr privconn = domain->conn->privateData; - virDomainObjPtr dom; - int ret = -1; - - if (!(dom = vzDomObjFromDomain(domain))) - return -1; - - ret = prlsdkDomainChangeStateLocked(privconn, dom, chstate); - virObjectUnlock(dom); - return ret; -} - -static int -prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - size_t i; - PRL_VM_TYPE vmType; - PRL_RESULT pret; - virDomainNumatuneMemMode memMode; - - if (def->title) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("titles are not supported by vz driver")); - return -1; - } - - if (def->blkio.ndevices > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("blkio parameters are not supported " - "by vz driver")); - return -1; - } - - if (virDomainDefGetMemoryActual(def) != def->mem.cur_balloon) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing balloon parameters is not supported " - "by vz driver")); - return -1; - } - - if (virDomainDefGetMemoryActual(def) % (1 << 10) != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Memory size should be multiple of 1Mb.")); - return -1; - } - - if (def->mem.nhugepages || - virMemoryLimitIsSet(def->mem.hard_limit) || - virMemoryLimitIsSet(def->mem.soft_limit) || - def->mem.min_guarantee || - virMemoryLimitIsSet(def->mem.swap_hard_limit)) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Memory parameter is not supported " - "by vz driver")); - return -1; - } - - if (def->vcpus != def->maxvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("current vcpus must be equal to maxvcpus")); - return -1; - } - - if (def->placement_mode) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing cpu placement mode is not supported " - "by vz driver")); - return -1; - } - - if (def->cputune.shares || - def->cputune.sharesSpecified || - def->cputune.period || - def->cputune.quota) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("cputune is not supported by vz driver")); - return -1; - } - - if (def->cputune.vcpupin) { - for (i = 0; i < def->vcpus; i++) { - if (!virBitmapEqual(def->cpumask, - def->cputune.vcpupin[i]->cpumask)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("vcpupin cpumask differs from default cpumask")); - return -1; - } - } - } - - - /* - * Though we don't support NUMA configuration at the moment - * virDomainDefPtr always contain non zero NUMA configuration - * So, just make sure this configuration does't differ from auto generated. - */ - if ((virDomainNumatuneGetMode(def->numa, -1, &memMode) == 0 && - memMode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) || - virDomainNumatuneHasPerNodeBinding(def->numa)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("numa parameters are not supported " - "by vz driver")); - return -1; - } - - if (def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART || - def->onPoweroff != VIR_DOMAIN_LIFECYCLE_DESTROY || - def->onCrash != VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("on_reboot, on_poweroff and on_crash parameters " - "are not supported by vz driver")); - return -1; - } - - /* we fill only type and arch fields in vzLoadDomain for - * hvm type and also init for containers, so we can check that all - * other paramenters are null and boot devices config is default */ - - if (def->os.machine != NULL || def->os.bootmenu != 0 || - def->os.kernel != NULL || def->os.initrd != NULL || - def->os.cmdline != NULL || def->os.root != NULL || - def->os.loader != NULL || def->os.bootloader != NULL || - def->os.bootloaderArgs != NULL || def->os.smbios_mode != 0 || - def->os.bios.useserial != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by vz driver")); - return -1; - } - - pret = PrlVmCfg_GetVmType(sdkdom, &vmType); - if (PRL_FAILED(pret)) { - logPrlError(pret); - return -1; - } - - if (!(vmType == PVT_VM && !IS_CT(def)) && - !(vmType == PVT_CT && IS_CT(def))) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS type is not supported " - "by vz driver")); - return -1; - } - - if (!IS_CT(def)) { - if (def->os.nBootDevs != 1 || - def->os.bootDevs[0] != VIR_DOMAIN_BOOT_DISK || - def->os.init != NULL || def->os.initargv != NULL) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by vz driver")); - return -1; - } - } else { - if (def->os.nBootDevs != 0 || - !STREQ_NULLABLE(def->os.init, "/sbin/init") || - (def->os.initargv != NULL && def->os.initargv[0] != NULL)) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by vz driver")); - return -1; - } - } - - if (def->emulator) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing emulator is not supported " - "by vz driver")); - return -1; - } - - for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) { - if (def->features[i]) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing features is not supported " - "by vz driver")); - return -1; - } - } - - if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC || - def->clock.ntimers != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing clock parameters is not supported " - "by vz driver")); - return -1; - } - - if (!IS_CT(def) && def->nfss != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Filesystems in VMs are not supported " - "by vz driver")); - return -1; - } - - if (def->nsounds != 0 || def->nhostdevs != 0 || - def->nredirdevs != 0 || def->nsmartcards != 0 || - def->nparallels || def->nchannels != 0 || - def->nleases != 0 || def->nhubs != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing devices parameters is not supported " - "by vz driver")); - return -1; - } - - /* there may be one auto-input */ - if (def->ninputs != 0 && - (def->ninputs != 2 && - def->inputs[0]->type != VIR_DOMAIN_INPUT_TYPE_MOUSE && - def->inputs[0]->bus != VIR_DOMAIN_INPUT_BUS_PS2 && - def->inputs[1]->type != VIR_DOMAIN_INPUT_TYPE_KBD && - def->inputs[1]->bus != VIR_DOMAIN_INPUT_BUS_PS2)) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing input devices parameters is not supported " - "by vz driver")); - return -1; - } - - return 0; -} - -static int prlsdkClearDevices(PRL_HANDLE sdkdom) -{ - PRL_RESULT pret; - PRL_UINT32 n, i; - PRL_HANDLE devList; - PRL_HANDLE dev; - int ret = -1; - - pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_DISABLED); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmCfg_GetAllDevices(sdkdom, &devList); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlHndlList_GetItemsCount(devList, &n); - prlsdkCheckRetGoto(pret, cleanup); - - for (i = 0; i < n; i++) { - pret = PrlHndlList_GetItem(devList, i, &dev); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_Remove(dev); - PrlHandle_Free(dev); - } - - ret = 0; - cleanup: - PrlHandle_Free(devList); - return ret; -} - -static int -prlsdkRemoveBootDevices(PRL_HANDLE sdkdom) -{ - PRL_RESULT pret; - PRL_UINT32 i, devCount; - PRL_HANDLE dev = PRL_INVALID_HANDLE; - PRL_DEVICE_TYPE devType; - - pret = PrlVmCfg_GetBootDevCount(sdkdom, &devCount); - prlsdkCheckRetGoto(pret, error); - - for (i = 0; i < devCount; i++) { - - /* always get device by index 0, because device list resort after delete */ - pret = PrlVmCfg_GetBootDev(sdkdom, 0, &dev); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_GetType(dev, &devType); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_Remove(dev); - prlsdkCheckRetGoto(pret, error); - } - - return 0; - - error: - return -1; -} - -static int -prlsdkAddDeviceToBootList(PRL_HANDLE sdkdom, - PRL_UINT32 devIndex, - PRL_DEVICE_TYPE devType, - PRL_UINT32 bootSequence) -{ - PRL_RESULT pret; - PRL_HANDLE bootDev = PRL_INVALID_HANDLE; - - pret = PrlVmCfg_CreateBootDev(sdkdom, &bootDev); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_SetIndex(bootDev, devIndex); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_SetType(bootDev, devType); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_SetSequenceIndex(bootDev, bootSequence); - prlsdkCheckRetGoto(pret, error); - - pret = PrlBootDev_SetInUse(bootDev, PRL_TRUE); - prlsdkCheckRetGoto(pret, error); - - return 0; - - error: - if (bootDev != PRL_INVALID_HANDLE) - PrlBootDev_Remove(bootDev); - - return -1; -} - -static int prlsdkCheckGraphicsUnsupportedParams(virDomainDefPtr def) -{ - virDomainGraphicsDefPtr gr; - - if (def->ngraphics == 0) - return 0; - - if (def->ngraphics > 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver supports only " - "one VNC per domain.")); - return -1; - } - - gr = def->graphics[0]; - - if (gr->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver supports only " - "VNC graphics.")); - return -1; - } - - if (gr->data.vnc.websocket != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "websockets for VNC graphics.")); - return -1; - } - - if (gr->data.vnc.keymap != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "keymap setting for VNC graphics.")); - return -1; - } - - if (gr->data.vnc.sharePolicy == VIR_DOMAIN_GRAPHICS_VNC_SHARE_ALLOW_EXCLUSIVE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "exclusive share policy for VNC graphics.")); - return -1; - } - - if (gr->data.vnc.socket) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "VNC graphics over unix sockets.")); - return -1; - } - - if (gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL || - gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "given action in case of password change.")); - return -1; - } - - if (gr->data.vnc.auth.expires) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "setting password expire time.")); - return -1; - } - - if (gr->nListens > 1) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("vz driver doesn't support more than " - "one listening VNC server per domain")); - return -1; - } - - if (gr->nListens == 1 && - virDomainGraphicsListenGetType(gr, 0) != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("vz driver supports only address-based VNC listening")); - return -1; - } - - return 0; -} - -static int prlsdkCheckVideoUnsupportedParams(virDomainDefPtr def) -{ - virDomainVideoDefPtr v; - - if (IS_CT(def)) { - if (def->nvideos == 0) { - return 0; - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Video adapters are not supported " - "int containers.")); - return -1; - } - } else { - if (def->nvideos != 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver supports " - "only one video adapter.")); - return -1; - } - } - - v = def->videos[0]; - - if (v->type != VIR_DOMAIN_VIDEO_TYPE_VGA) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver supports " - "only VGA video adapters.")); - return -1; - } - - if (v->heads != 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "multihead video adapters.")); - return -1; - } - - if (v->accel != NULL && (v->accel->support2d || v->accel->support3d)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "setting video acceleration parameters.")); - return -1; - } - - return 0; -} - -static int prlsdkCheckSerialUnsupportedParams(virDomainChrDefPtr chr) -{ - if (chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified character device type is not supported " - "by vz driver.")); - return -1; - } - - if (chr->targetTypeAttr) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified character device target type is not " - "supported by vz driver.")); - return -1; - } - - if (chr->source.type != VIR_DOMAIN_CHR_TYPE_DEV && - chr->source.type != VIR_DOMAIN_CHR_TYPE_FILE && - chr->source.type != VIR_DOMAIN_CHR_TYPE_UNIX) { - - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified character device source type is not " - "supported by vz driver.")); - return -1; - } - - if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting device info for character devices is not " - "supported by vz driver.")); - return -1; - } - - if (chr->nseclabels > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting security labels is not " - "supported by vz driver.")); - return -1; - } - - return 0; -} - -static int prlsdkCheckNetUnsupportedParams(virDomainNetDefPtr net) -{ - if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK && - net->type != VIR_DOMAIN_NET_TYPE_BRIDGE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified network adapter type is not " - "supported by vz driver.")); - return -1; - } - - if (net->backend.tap || net->backend.vhost) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Interface backend parameters are not " - "supported by vz driver.")); - return -1; - } - - if (net->data.network.portgroup) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Virtual network portgroups are not " - "supported by vz driver.")); - return -1; - } - - if (net->tune.sndbuf_specified) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting interface sndbuf is not " - "supported by vz driver.")); - return -1; - } - - if (net->script) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting interface script is not " - "supported by vz driver.")); - return -1; - } - - if (net->ifname_guest) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting guest interface name is not " - "supported by vz driver.")); - return -1; - } - - if (net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting device info for network devices is not " - "supported by vz driver.")); - return -1; - } - - if (net->filter) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting network filter is not " - "supported by vz driver.")); - return -1; - } - - if (net->bandwidth) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting network bandwidth is not " - "supported by vz driver.")); - return -1; - } - - if (net->vlan.trunk) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting up vlans is not " - "supported by vz driver.")); - return -1; - } - - return 0; -} - -static int prlsdkCheckDiskUnsupportedParams(virDomainDiskDefPtr disk) -{ - if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK && - disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only hard disks and cdroms are supported " - "by vz driver.")); - return -1; - } - - if (disk->blockio.logical_block_size || - disk->blockio.physical_block_size) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk block sizes is not " - "supported by vz driver.")); - return -1; - } - - if (disk->blkdeviotune.total_bytes_sec || - disk->blkdeviotune.read_bytes_sec || - disk->blkdeviotune.write_bytes_sec || - disk->blkdeviotune.total_iops_sec || - disk->blkdeviotune.read_iops_sec || - disk->blkdeviotune.write_iops_sec) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk io limits is not " - "supported by vz driver yet.")); - return -1; - } - - if (disk->serial) { - VIR_INFO("%s", _("Setting disk serial number is not " - "supported by vz driver.")); - } - - if (disk->wwn) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk wwn id is not " - "supported by vz driver.")); - return -1; - } - - if (disk->vendor) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk vendor is not " - "supported by vz driver.")); - return -1; - } - - if (disk->product) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk product id is not " - "supported by vz driver.")); - return -1; - } - - if (disk->error_policy != VIR_DOMAIN_DISK_ERROR_POLICY_DEFAULT) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk error policy is not " - "supported by vz driver.")); - return -1; - } - - if (disk->iomode) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting disk io mode is not " - "supported by vz driver.")); - return -1; - } - - if (disk->copy_on_read) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Disk copy_on_read is not " - "supported by vz driver.")); - return -1; - } - - if (disk->startupPolicy != VIR_DOMAIN_STARTUP_POLICY_DEFAULT) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting up disk startup policy is not " - "supported by vz driver.")); - return -1; - } - - if (disk->transient) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Transient disks are not " - "supported by vz driver.")); - return -1; - } - - if (disk->discard) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting up disk discard parameter is not " - "supported by vz driver.")); - return -1; - } - - if (disk->iothread) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting up disk io thread # is not " - "supported by vz driver.")); - return -1; - } - - if (disk->src->type != VIR_STORAGE_TYPE_FILE && - disk->src->type != VIR_STORAGE_TYPE_BLOCK) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only disk and block storage types are " - "supported by vz driver.")); - return -1; - - } - - return 0; -} - -static int prlsdkCheckFSUnsupportedParams(virDomainFSDefPtr fs) -{ - if (fs->type != VIR_DOMAIN_FS_TYPE_FILE) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only file based filesystems are " - "supported by vz driver.")); - return -1; - } - - if (fs->fsdriver != VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only ploop fs driver is " - "supported by vz driver.")); - return -1; - } - - if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing fs access mode is not " - "supported by vz driver.")); - return -1; - } - - if (fs->wrpolicy != VIR_DOMAIN_FS_WRPOLICY_DEFAULT) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing fs write policy is not " - "supported by vz driver.")); - return -1; - } - - if (fs->format != VIR_STORAGE_FILE_PLOOP) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only ploop disk images are " - "supported by vz driver.")); - return -1; - } - - if (fs->readonly) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting readonly for filesystems is " - "supported by vz driver.")); - return -1; - } - - if (fs->space_hard_limit || fs->space_soft_limit) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting fs quotas is not " - "supported by vz driver.")); - return -1; - } - - return 0; -} - -static int prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom, virDomainDefPtr def) -{ - virDomainGraphicsDefPtr gr; - PRL_RESULT pret; - int ret = -1; - const char *listenAddr = NULL; - - if (prlsdkCheckGraphicsUnsupportedParams(def)) - return -1; - - if (def->ngraphics == 0) - return 0; - - gr = def->graphics[0]; - - if (gr->data.vnc.autoport) { - pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_AUTO); - prlsdkCheckRetGoto(pret, cleanup); - } else { - pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_MANUAL); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmCfg_SetVNCPort(sdkdom, gr->data.vnc.port); - prlsdkCheckRetGoto(pret, cleanup); - } - - if (gr->nListens == 1) { - listenAddr = virDomainGraphicsListenGetAddress(gr, 0); - if (!listenAddr) - goto cleanup; - pret = PrlVmCfg_SetVNCHostName(sdkdom, listenAddr); - prlsdkCheckRetGoto(pret, cleanup); - } - - ret = 0; - cleanup: - return ret; -} - -static int prlsdkApplyVideoParams(PRL_HANDLE sdkdom ATTRIBUTE_UNUSED, virDomainDefPtr def) -{ - PRL_RESULT pret; - - if (def->nvideos == 0) - return 0; - - if (IS_CT(def)) { - /* ignore video parameters */ - return 0; - } - - if (prlsdkCheckVideoUnsupportedParams(def)) - return -1; - - pret = PrlVmCfg_SetVideoRamSize(sdkdom, def->videos[0]->vram >> 10); - prlsdkCheckRetGoto(pret, error); - - return 0; - error: - return -1; -} - -static int prlsdkAddSerial(PRL_HANDLE sdkdom, virDomainChrDefPtr chr) -{ - PRL_RESULT pret; - PRL_HANDLE sdkchr = PRL_INVALID_HANDLE; - PRL_VM_DEV_EMULATION_TYPE emutype; - PRL_SERIAL_PORT_SOCKET_OPERATION_MODE socket_mode = - PSP_SERIAL_SOCKET_SERVER; - char *path; - int ret = -1; - - if (prlsdkCheckSerialUnsupportedParams(chr) < 0) - return -1; - - pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_SERIAL_PORT, &sdkchr); - prlsdkCheckRetGoto(pret, cleanup); - - switch (chr->source.type) { - case VIR_DOMAIN_CHR_TYPE_DEV: - emutype = PDT_USE_REAL_DEVICE; - path = chr->source.data.file.path; - break; - case VIR_DOMAIN_CHR_TYPE_FILE: - emutype = PDT_USE_OUTPUT_FILE; - path = chr->source.data.file.path; - break; - case VIR_DOMAIN_CHR_TYPE_UNIX: - emutype = PDT_USE_SERIAL_PORT_SOCKET_MODE; - path = chr->source.data.nix.path; - if (chr->source.data.nix.listen) - socket_mode = PSP_SERIAL_SOCKET_SERVER; - else - socket_mode = PSP_SERIAL_SOCKET_CLIENT; - break; - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vz driver doesn't support " - "specified serial source type.")); - goto cleanup; - } - - pret = PrlVmDev_SetEmulatedType(sdkchr, emutype); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetSysName(sdkchr, path); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetFriendlyName(sdkchr, path); - prlsdkCheckRetGoto(pret, cleanup); - - if (chr->source.type == VIR_DOMAIN_CHR_TYPE_UNIX) { - pret = PrlVmDevSerial_SetSocketMode(sdkchr, socket_mode); - prlsdkCheckRetGoto(pret, cleanup); - } - - pret = PrlVmDev_SetEnabled(sdkchr, 1); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetIndex(sdkchr, chr->target.port); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - cleanup: - PrlHandle_Free(sdkchr); - return ret; -} - -#define PRL_MAC_STRING_BUFNAME 13 - -static const char * prlsdkFormatMac(virMacAddrPtr mac, char *macstr) -{ - snprintf(macstr, PRL_MAC_STRING_BUFNAME, - "%02X%02X%02X%02X%02X%02X", - mac->addr[0], mac->addr[1], mac->addr[2], - mac->addr[3], mac->addr[4], mac->addr[5]); - macstr[PRL_MAC_STRING_BUFNAME - 1] = '\0'; - return macstr; -} - -static int prlsdkAddNet(PRL_HANDLE sdkdom, - vzConnPtr privconn, - virDomainNetDefPtr net, - bool isCt) -{ - PRL_RESULT pret; - PRL_HANDLE sdknet = PRL_INVALID_HANDLE; - PRL_HANDLE vnet = PRL_INVALID_HANDLE; - PRL_HANDLE job = PRL_INVALID_HANDLE; - int ret = -1; - char macstr[PRL_MAC_STRING_BUFNAME]; - - if (prlsdkCheckNetUnsupportedParams(net) < 0) - return -1; - - pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_GENERIC_NETWORK_ADAPTER, &sdknet); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetEnabled(sdknet, 1); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetConnected(sdknet, net->linkstate != - VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN); - - prlsdkCheckRetGoto(pret, cleanup); - - if (net->ifname) { - pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname); - prlsdkCheckRetGoto(pret, cleanup); - } - - prlsdkFormatMac(&net->mac, macstr); - pret = PrlVmDevNet_SetMacAddress(sdknet, macstr); - prlsdkCheckRetGoto(pret, cleanup); - - if (isCt) { - if (net->model) - VIR_WARN("Setting network adapter for containers is not " - "supported by vz driver."); - } else { - if (STREQ(net->model, "rtl8139")) { - pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_RTL); - } else if (STREQ(net->model, "e1000")) { - pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_E1000); - } else if (STREQ(net->model, "virtio")) { - pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_VIRTIO); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified network adapter model is not " - "supported by vz driver.")); - goto cleanup; - } - prlsdkCheckRetGoto(pret, cleanup); - } - - if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { - if (STREQ(net->data.network.name, PARALLELS_DOMAIN_ROUTED_NETWORK_NAME)) { - pret = PrlVmDev_SetEmulatedType(sdknet, PNA_ROUTED); - prlsdkCheckRetGoto(pret, cleanup); - } else if (STREQ(net->data.network.name, PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME)) { - pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGED_ETHERNET); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name); - prlsdkCheckRetGoto(pret, cleanup); - } - } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { - /* - * For this type of adapter we create a new - * Virtual Network assuming that bridge with given name exists - * Failing creating this means domain creation failure - */ - pret = PrlVirtNet_Create(&vnet); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVirtNet_SetNetworkId(vnet, net->data.network.name); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVirtNet_SetNetworkType(vnet, PVN_BRIDGED_ETHERNET); - prlsdkCheckRetGoto(pret, cleanup); - - job = PrlSrv_AddVirtualNetwork(privconn->server, vnet, 0); - if (PRL_FAILED(pret = waitJob(job))) - goto cleanup; - - pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGED_ETHERNET); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name); - prlsdkCheckRetGoto(pret, cleanup); - } - - if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_YES) - pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 0); - else if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_NO) - pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 1); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - cleanup: - PrlHandle_Free(vnet); - PrlHandle_Free(sdknet); - return ret; -} - -static void prlsdkDelNet(vzConnPtr privconn, virDomainNetDefPtr net) -{ - PRL_RESULT pret; - PRL_HANDLE vnet = PRL_INVALID_HANDLE; - PRL_HANDLE job = PRL_INVALID_HANDLE; - - if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE) - return; - - pret = PrlVirtNet_Create(&vnet); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVirtNet_SetNetworkId(vnet, net->data.network.name); - prlsdkCheckRetGoto(pret, cleanup); - - PrlSrv_DeleteVirtualNetwork(privconn->server, vnet, 0); - if (PRL_FAILED(pret = waitJob(job))) - goto cleanup; - - cleanup: - PrlHandle_Free(vnet); -} - -static int prlsdkDelDisk(PRL_HANDLE sdkdom, int idx) -{ - int ret = -1; - PRL_RESULT pret; - PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; - - pret = PrlVmCfg_GetHardDisk(sdkdom, idx, &sdkdisk); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_Remove(sdkdisk); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - - cleanup: - PrlHandle_Free(sdkdisk); - return ret; -} - -static int prlsdkAddDisk(PRL_HANDLE sdkdom, - virDomainDiskDefPtr disk, - bool bootDisk, - bool isCt) -{ - PRL_RESULT pret; - PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; - int ret = -1; - PRL_VM_DEV_EMULATION_TYPE emutype; - PRL_MASS_STORAGE_INTERFACE_TYPE sdkbus; - int idx; - virDomainDeviceDriveAddressPtr drive; - PRL_UINT32 devIndex; - PRL_DEVICE_TYPE devType; - char *dst = NULL; - - if (prlsdkCheckDiskUnsupportedParams(disk) < 0) - return -1; - - if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) - devType = PDE_HARD_DISK; - else - devType = PDE_OPTICAL_DISK; - - pret = PrlVmCfg_CreateVmDev(sdkdom, devType, &sdkdisk); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetEnabled(sdkdisk, 1); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetConnected(sdkdisk, 1); - prlsdkCheckRetGoto(pret, cleanup); - - if (disk->src->type == VIR_STORAGE_TYPE_FILE) { - if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && - virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid format of " - "disk %s, vz driver supports only " - "images in ploop format."), disk->src->path); - goto cleanup; - } - - emutype = PDT_USE_IMAGE_FILE; - } else { - if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && - (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_RAW && - virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_NONE && - virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_AUTO)) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid format " - "of disk %s, it should be either not set, or set " - "to raw or auto."), disk->src->path); - goto cleanup; - } - emutype = PDT_USE_REAL_DEVICE; - } - - pret = PrlVmDev_SetEmulatedType(sdkdisk, emutype); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetSysName(sdkdisk, disk->src->path); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetFriendlyName(sdkdisk, disk->src->path); - prlsdkCheckRetGoto(pret, cleanup); - - drive = &disk->info.addr.drive; - if (drive->controller > 0) { - /* We have only one controller of each type */ - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only one controller."), disk->dst); - goto cleanup; - } - - if (drive->target > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only target 0."), disk->dst); - goto cleanup; - } - - switch (disk->bus) { - case VIR_DOMAIN_DISK_BUS_IDE: - if (drive->unit > 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only units 0-1 for IDE bus."), disk->dst); - goto cleanup; - } - sdkbus = PMS_IDE_DEVICE; - idx = 2 * drive->bus + drive->unit; - dst = virIndexToDiskName(idx, "hd"); - break; - case VIR_DOMAIN_DISK_BUS_SCSI: - if (drive->bus > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only bus 0 for SCSI bus."), disk->dst); - goto cleanup; - } - sdkbus = PMS_SCSI_DEVICE; - idx = drive->unit; - dst = virIndexToDiskName(idx, "sd"); - break; - case VIR_DOMAIN_DISK_BUS_SATA: - if (drive->bus > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only bus 0 for SATA bus."), disk->dst); - goto cleanup; - } - sdkbus = PMS_SATA_DEVICE; - idx = drive->unit; - dst = virIndexToDiskName(idx, "sd"); - break; - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified disk bus is not " - "supported by vz driver.")); - goto cleanup; - } - - if (!dst) - goto cleanup; - - if (STRNEQ(dst, disk->dst)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " - "address of disk %s, vz driver supports " - "only defaults address to logical device name."), disk->dst); - goto cleanup; - } - - pret = PrlVmDev_SetIfaceType(sdkdisk, sdkbus); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetStackIndex(sdkdisk, idx); - prlsdkCheckRetGoto(pret, cleanup); - - switch (disk->cachemode) { - case VIR_DOMAIN_DISK_CACHE_DISABLE: - pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_FALSE); - prlsdkCheckRetGoto(pret, cleanup); - break; - case VIR_DOMAIN_DISK_CACHE_WRITEBACK: - pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_TRUE); - prlsdkCheckRetGoto(pret, cleanup); - break; - case VIR_DOMAIN_DISK_CACHE_DEFAULT: - break; - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Specified disk cache mode is not " - "supported by vz driver.")); - goto cleanup; - } - - if (bootDisk == true) { - pret = PrlVmDev_GetIndex(sdkdisk, &devIndex); - prlsdkCheckRetGoto(pret, cleanup); - - if (prlsdkAddDeviceToBootList(sdkdom, devIndex, devType, 0) < 0) - goto cleanup; - - /* If we add physical device as a boot disk to container - * we have to specify mount point for it */ - if (isCt) { - pret = PrlVmDevHd_SetMountPoint(sdkdisk, "/"); - prlsdkCheckRetGoto(pret, cleanup); - } - } - - return 0; - cleanup: - PrlHandle_Free(sdkdisk); - VIR_FREE(dst); - return ret; -} - -int -prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk) -{ - int ret = -1; - vzDomObjPtr privdom = dom->privateData; - PRL_HANDLE job = PRL_INVALID_HANDLE; - - job = PrlVm_BeginEdit(privdom->sdkdom); - if (PRL_FAILED(waitJob(job))) - goto cleanup; - - ret = prlsdkAddDisk(privdom->sdkdom, disk, false, IS_CT(dom->def)); - if (ret == 0) { - job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE); - if (PRL_FAILED(waitJob(job))) { - ret = -1; - goto cleanup; - } - } - - cleanup: - return ret; -} - -static int -prlsdkGetDiskIndex(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk) -{ - int idx = -1; - char *buf = NULL; - PRL_UINT32 buflen = 0; - PRL_RESULT pret; - PRL_UINT32 hddCount; - PRL_UINT32 i; - PRL_HANDLE hdd = PRL_INVALID_HANDLE; - - pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); - prlsdkCheckRetGoto(pret, cleanup); - - for (i = 0; i < hddCount; ++i) { - - pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_GetFriendlyName(hdd, 0, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (VIR_ALLOC_N(buf, buflen) < 0) - goto cleanup; - - pret = PrlVmDev_GetFriendlyName(hdd, buf, &buflen); - prlsdkCheckRetGoto(pret, cleanup); - - if (STRNEQ(disk->src->path, buf)) { - - PrlHandle_Free(hdd); - hdd = PRL_INVALID_HANDLE; - VIR_FREE(buf); - continue; - } - - VIR_FREE(buf); - idx = i; - break; - } - - cleanup: - PrlHandle_Free(hdd); - return idx; -} - -int -prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk) -{ - int ret = -1, idx; - vzDomObjPtr privdom = dom->privateData; - PRL_HANDLE job = PRL_INVALID_HANDLE; - - idx = prlsdkGetDiskIndex(privdom->sdkdom, disk); - if (idx < 0) - goto cleanup; - - job = PrlVm_BeginEdit(privdom->sdkdom); - if (PRL_FAILED(waitJob(job))) - goto cleanup; - - ret = prlsdkDelDisk(privdom->sdkdom, idx); - if (ret == 0) { - job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE); - if (PRL_FAILED(waitJob(job))) { - ret = -1; - goto cleanup; - } - } - - cleanup: - return ret; -} - -static int -prlsdkAddFS(PRL_HANDLE sdkdom, virDomainFSDefPtr fs) -{ - PRL_RESULT pret; - PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; - int ret = -1; - - if (prlsdkCheckFSUnsupportedParams(fs) < 0) - return -1; - - pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetEnabled(sdkdisk, 1); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetConnected(sdkdisk, 1); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetEmulatedType(sdkdisk, PDT_USE_IMAGE_FILE); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetSysName(sdkdisk, fs->src); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetImagePath(sdkdisk, fs->src); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDev_SetFriendlyName(sdkdisk, fs->src); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmDevHd_SetMountPoint(sdkdisk, fs->dst); - prlsdkCheckRetGoto(pret, cleanup); - - ret = 0; - - cleanup: - PrlHandle_Free(sdkdisk); - return ret; -} -static int -prlsdkDoApplyConfig(virConnectPtr conn, - PRL_HANDLE sdkdom, - virDomainDefPtr def, - virDomainDefPtr olddef) -{ - PRL_RESULT pret; - size_t i; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; - bool needBoot = true; - char *mask = NULL; - - if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0) - return -1; - - if (def->description) { - pret = PrlVmCfg_SetDescription(sdkdom, def->description); - prlsdkCheckRetGoto(pret, error); - } - - if (def->name) { - pret = PrlVmCfg_SetName(sdkdom, def->name); - prlsdkCheckRetGoto(pret, error); - } - - if (def->uuid) { - prlsdkUUIDFormat(def->uuid, uuidstr); - - pret = PrlVmCfg_SetUuid(sdkdom, uuidstr); - prlsdkCheckRetGoto(pret, error); - } - - pret = PrlVmCfg_SetRamSize(sdkdom, virDomainDefGetMemoryActual(def) >> 10); - prlsdkCheckRetGoto(pret, error); - - pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus); - prlsdkCheckRetGoto(pret, error); - - if (!(mask = virBitmapFormat(def->cpumask))) - goto error; - - pret = PrlVmCfg_SetCpuMask(sdkdom, mask); - prlsdkCheckRetGoto(pret, error); - VIR_FREE(mask); - - switch (def->os.arch) { - case VIR_ARCH_X86_64: - pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_64); - break; - case VIR_ARCH_I686: - pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_32); - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU mode: %s"), - virArchToString(def->os.arch)); - goto error; - } - prlsdkCheckRetGoto(pret, error); - - if (prlsdkClearDevices(sdkdom) < 0) - goto error; - - if (prlsdkRemoveBootDevices(sdkdom) < 0) - goto error; - - if (olddef) { - for (i = 0; i < olddef->nnets; i++) - prlsdkDelNet(conn->privateData, olddef->nets[i]); - } - - for (i = 0; i < def->nnets; i++) { - if (prlsdkAddNet(sdkdom, conn->privateData, def->nets[i], IS_CT(def)) < 0) - goto error; - } - - if (prlsdkApplyGraphicsParams(sdkdom, def) < 0) - goto error; - - if (prlsdkApplyVideoParams(sdkdom, def) < 0) - goto error; - - for (i = 0; i < def->nserials; i++) { - if (prlsdkAddSerial(sdkdom, def->serials[i]) < 0) - goto error; - } - - for (i = 0; i < def->nfss; i++) { - if (STREQ(def->fss[i]->dst, "/")) - needBoot = false; - if (prlsdkAddFS(sdkdom, def->fss[i]) < 0) - goto error; - } - - for (i = 0; i < def->ndisks; i++) { - bool bootDisk = false; - - if (needBoot == true && - def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { - - needBoot = false; - bootDisk = true; - } - if (prlsdkAddDisk(sdkdom, def->disks[i], bootDisk, IS_CT(def)) < 0) - goto error; - } - - return 0; - - error: - VIR_FREE(mask); - - for (i = 0; i < def->nnets; i++) - prlsdkDelNet(conn->privateData, def->nets[i]); - - return -1; -} - -int -prlsdkApplyConfig(virConnectPtr conn, - virDomainObjPtr dom, - virDomainDefPtr new) -{ - vzConnPtr privconn = conn->privateData; - PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; - PRL_HANDLE job = PRL_INVALID_HANDLE; - int ret; - - sdkdom = prlsdkSdkDomainLookupByUUID(privconn, dom->def->uuid); - if (sdkdom == PRL_INVALID_HANDLE) - return -1; - - job = PrlVm_BeginEdit(sdkdom); - if (PRL_FAILED(waitJob(job))) - return -1; - - ret = prlsdkDoApplyConfig(conn, sdkdom, new, dom->def); - - if (ret == 0) { - job = PrlVm_CommitEx(sdkdom, PVCF_DETACH_HDD_BUNDLE); - if (PRL_FAILED(waitJob(job))) - ret = -1; - } - - PrlHandle_Free(sdkdom); - - return ret; -} - -int -prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def) -{ - vzConnPtr privconn = conn->privateData; - PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; - PRL_HANDLE job = PRL_INVALID_HANDLE; - PRL_HANDLE result = PRL_INVALID_HANDLE; - PRL_HANDLE srvconf = PRL_INVALID_HANDLE; - PRL_RESULT pret; - int ret = -1; - - pret = PrlSrv_CreateVm(privconn->server, &sdkdom); - prlsdkCheckRetGoto(pret, cleanup); - - job = PrlSrv_GetSrvConfig(privconn->server); - if (PRL_FAILED(getJobResult(job, &result))) - goto cleanup; - - pret = PrlResult_GetParamByIndex(result, 0, &srvconf); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmCfg_SetDefaultConfig(sdkdom, srvconf, PVS_GUEST_VER_LIN_REDHAT, 0); - prlsdkCheckRetGoto(pret, cleanup); - - pret = PrlVmCfg_SetOfflineManagementEnabled(sdkdom, 0); - prlsdkCheckRetGoto(pret, cleanup); - - ret = prlsdkDoApplyConfig(conn, sdkdom, def, NULL); - if (ret) - goto cleanup; - - job = PrlVm_Reg(sdkdom, "", 1); - if (PRL_FAILED(waitJob(job))) - ret = -1; - - cleanup: - PrlHandle_Free(sdkdom); - return ret; -} - -int -prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) -{ - vzConnPtr privconn = conn->privateData; - PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; - PRL_GET_VM_CONFIG_PARAM_DATA confParam; - PRL_HANDLE job = PRL_INVALID_HANDLE; - PRL_HANDLE result = PRL_INVALID_HANDLE; - PRL_RESULT pret; - int ret = -1; - int useTemplate = 0; - size_t i; - - if (def->nfss > 1) { - /* Check all filesystems */ - for (i = 0; i < def->nfss; i++) { - if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_FILE) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Unsupported filesystem type.")); - return -1; - } - } - } else if (def->nfss == 1) { - if (def->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) { - useTemplate = 1; - } else if (def->fss[0]->type != VIR_DOMAIN_FS_TYPE_FILE) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Unsupported filesystem type.")); - return -1; - } - } - - confParam.nVmType = PVT_CT; - confParam.sConfigSample = "vswap.1024MB"; - confParam.nOsVersion = 0; - - job = PrlSrv_GetDefaultVmConfig(privconn->server, &confParam, 0); - if (PRL_FAILED(getJobResult(job, &result))) - goto cleanup; - - pret = PrlResult_GetParamByIndex(result, 0, &sdkdom); - prlsdkCheckRetGoto(pret, cleanup); - - if (useTemplate) { - pret = PrlVmCfg_SetOsTemplate(sdkdom, def->fss[0]->src); - prlsdkCheckRetGoto(pret, cleanup); - - } - - ret = prlsdkDoApplyConfig(conn, sdkdom, def, NULL); - if (ret) - goto cleanup; - - job = PrlVm_RegEx(sdkdom, "", - PACF_NON_INTERACTIVE_MODE | PRNVM_PRESERVE_DISK); - if (PRL_FAILED(waitJob(job))) - ret = -1; - - cleanup: - PrlHandle_Free(sdkdom); - return ret; -} - -int -prlsdkUnregisterDomain(vzConnPtr privconn, virDomainObjPtr dom) -{ - vzDomObjPtr privdom = dom->privateData; - PRL_HANDLE job; - size_t i; - - for (i = 0; i < dom->def->nnets; i++) - prlsdkDelNet(privconn, dom->def->nets[i]); - - job = PrlVm_Unreg(privdom->sdkdom); - if (PRL_FAILED(waitJob(job))) - return -1; - - if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, - VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) - return -1; - - virDomainObjListRemove(privconn->domains, dom); - return 0; -} - -int -prlsdkDomainManagedSaveRemove(virDomainObjPtr dom) -{ - vzDomObjPtr privdom = dom->privateData; - PRL_HANDLE job; - - job = PrlVm_DropSuspendedState(privdom->sdkdom); - if (PRL_FAILED(waitJob(job))) - return -1; - - return 0; -} - -static int -prlsdkExtractStatsParam(PRL_HANDLE sdkstats, const char *name, long long *val) -{ - PRL_HANDLE param = PRL_INVALID_HANDLE; - PRL_RESULT pret; - PRL_INT64 pval = 0; - int ret = -1; - - pret = PrlEvent_GetParamByName(sdkstats, name, ¶m); - if (pret == PRL_ERR_NO_DATA) { - *val = -1; - ret = 0; - goto cleanup; - } else if (PRL_FAILED(pret)) { - logPrlError(pret); - goto cleanup; - } - pret = PrlEvtPrm_ToInt64(param, &pval); - prlsdkCheckRetGoto(pret, cleanup); - - *val = pval; - ret = 0; - - cleanup: - PrlHandle_Free(param); - return ret; -} - -#define PARALLELS_STATISTICS_TIMEOUT (60 * 1000) - -static int -prlsdkGetStatsParam(virDomainObjPtr dom, const char *name, long long *val) -{ - vzDomObjPtr privdom = dom->privateData; - PRL_HANDLE job = PRL_INVALID_HANDLE; - unsigned long long now; - - if (privdom->cache.stats != PRL_INVALID_HANDLE) { - // reset count to keep subscribtion - privdom->cache.count = 0; - return prlsdkExtractStatsParam(privdom->cache.stats, name, val); - } - - if (privdom->cache.count == -1) { - job = PrlVm_SubscribeToPerfStats(privdom->sdkdom, NULL); - if (PRL_FAILED(waitJob(job))) - goto error; - } - - // change state to subscribed in case of unsubscribed - // or reset count so we stop unsubscribe attempts - privdom->cache.count = 0; - - if (virTimeMillisNow(&now) < 0) { - virReportSystemError(errno, "%s", _("Unable to get current time")); - goto error; - } - - while (privdom->cache.stats == PRL_INVALID_HANDLE) { - if (virCondWaitUntil(&privdom->cache.cond, &dom->parent.lock, - now + PARALLELS_STATISTICS_TIMEOUT) < 0) { - if (errno == ETIMEDOUT) { - virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", - _("Timeout on waiting statistics event.")); - goto error; - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to wait on monitor condition")); - goto error; - } - } - } - - return prlsdkExtractStatsParam(privdom->cache.stats, name, val); - error: - return -1; -} - -int -prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats) -{ - virDomainDeviceDriveAddressPtr address; - int idx; - const char *prefix; - int ret = -1; - char *name = NULL; - - address = &disk->info.addr.drive; - switch (disk->bus) { - case VIR_DOMAIN_DISK_BUS_IDE: - prefix = "ide"; - idx = address->bus * 2 + address->unit; - break; - case VIR_DOMAIN_DISK_BUS_SATA: - prefix = "sata"; - idx = address->unit; - break; - case VIR_DOMAIN_DISK_BUS_SCSI: - prefix = "scsi"; - idx = address->unit; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown disk bus: %X"), disk->bus); - goto cleanup; - } - - -#define PRLSDK_GET_STAT_PARAM(VAL, TYPE, NAME) \ - if (virAsprintf(&name, "devices.%s%d.%s", prefix, idx, NAME) < 0) \ - goto cleanup; \ - if (prlsdkGetStatsParam(dom, name, &stats->VAL) < 0) \ - goto cleanup; \ - VIR_FREE(name); - - PARALLELS_BLOCK_STATS_FOREACH(PRLSDK_GET_STAT_PARAM) - -#undef PRLSDK_GET_STAT_PARAM - - ret = 0; - - cleanup: - - VIR_FREE(name); - return ret; -} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h deleted file mode 100644 index 5de6473f2a..0000000000 --- a/src/parallels/parallels_sdk.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * parallels_sdk.h: core driver functions for managing - * Parallels Cloud Server hosts - * - * Copyright (C) 2014 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 - * . - * - */ - -#include - -#include "parallels_utils.h" - -int prlsdkInit(void); -void prlsdkDeinit(void); -int prlsdkConnect(vzConnPtr privconn); -void prlsdkDisconnect(vzConnPtr privconn); -int -prlsdkLoadDomains(vzConnPtr privconn); -virDomainObjPtr -prlsdkAddDomain(vzConnPtr privconn, const unsigned char *uuid); -int prlsdkUpdateDomain(vzConnPtr privconn, virDomainObjPtr dom); -int prlsdkSubscribeToPCSEvents(vzConnPtr privconn); -void prlsdkUnsubscribeFromPCSEvents(vzConnPtr privconn); -PRL_RESULT prlsdkStart(PRL_HANDLE sdkdom); -PRL_RESULT prlsdkKill(PRL_HANDLE sdkdom); -PRL_RESULT prlsdkStop(PRL_HANDLE sdkdom); -PRL_RESULT prlsdkPause(PRL_HANDLE sdkdom); -PRL_RESULT prlsdkResume(PRL_HANDLE sdkdom); -PRL_RESULT prlsdkSuspend(PRL_HANDLE sdkdom); - -typedef PRL_RESULT (*prlsdkChangeStateFunc)(PRL_HANDLE sdkdom); -int -prlsdkDomainChangeState(virDomainPtr domain, - prlsdkChangeStateFunc chstate); -int -prlsdkDomainChangeStateLocked(vzConnPtr privconn, - virDomainObjPtr dom, - prlsdkChangeStateFunc chstate); -int -prlsdkApplyConfig(virConnectPtr conn, - virDomainObjPtr dom, - virDomainDefPtr new); -int prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def); -int prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def); -int -prlsdkUnregisterDomain(vzConnPtr privconn, virDomainObjPtr dom); -int -prlsdkDomainManagedSaveRemove(virDomainObjPtr dom); -int -prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk); -int -prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk); -int -prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats); diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c deleted file mode 100644 index b0dac50bcc..0000000000 --- a/src/parallels/parallels_storage.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* - * parallels_storage.c: core driver functions for managing - * Parallels Cloud Server hosts - * - * Copyright (C) 2013-2014 Red Hat, Inc. - * 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 - * . - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "datatypes.h" -#include "dirname.h" -#include "viralloc.h" -#include "configmake.h" -#include "virstoragefile.h" -#include "virerror.h" -#include "virfile.h" -#include "parallels_utils.h" -#include "virstring.h" - -#define VIR_FROM_THIS VIR_FROM_PARALLELS - -#define vzPoolNotFoundError(pool_name) \ - virReportError(VIR_ERR_INVALID_ARG, \ - _("pool '%s' not found"), pool_name); - -static virStorageVolDefPtr -vzStorageVolDefineXML(virStoragePoolObjPtr pool, const char *xmldesc, - const char *xmlfile, bool is_new); -static virStorageVolPtr -vzStorageVolLookupByPath(virConnectPtr conn, const char *path); - -static int -vzStoragePoolGetAlloc(virStoragePoolDefPtr def); - -static void -vzStorageLock(virStorageDriverStatePtr driver) -{ - virMutexLock(&driver->lock); -} - -static void -vzStorageUnlock(virStorageDriverStatePtr driver) -{ - virMutexUnlock(&driver->lock); -} - -int -vzStorageClose(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - - if (!privconn) - return 0; - - virStorageDriverStatePtr storageState = privconn->storageState; - privconn->storageState = NULL; - - if (!storageState) - return 0; - - vzStorageLock(storageState); - virStoragePoolObjListFree(&privconn->pools); - VIR_FREE(storageState->configDir); - VIR_FREE(storageState->autostartDir); - vzStorageUnlock(storageState); - virMutexDestroy(&storageState->lock); - VIR_FREE(storageState); - - return 0; -} - -static int -vzFindVolumes(virStoragePoolObjPtr pool) -{ - DIR *dir; - struct dirent *ent; - char *path = NULL; - int ret = -1; - int direrr; - - if (!(dir = opendir(pool->def->target.path))) { - virReportSystemError(errno, - _("cannot open path '%s'"), - pool->def->target.path); - return -1; - } - - while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { - if (!virFileHasSuffix(ent->d_name, ".xml")) - continue; - - if (!(path = virFileBuildPath(pool->def->target.path, - ent->d_name, NULL))) - goto cleanup; - if (!vzStorageVolDefineXML(pool, NULL, path, false)) - goto cleanup; - - VIR_FREE(path); - } - if (direrr < 0) - goto cleanup; - - ret = 0; - cleanup: - VIR_FREE(path); - closedir(dir); - return ret; - -} - -/* - * Generate unique pool name by path - */ -static char *vzMakePoolName(virConnectPtr conn, const char *path) -{ - vzConnPtr privconn = conn->privateData; - char *name; - size_t i; - - for (i = 0; i < UINT_MAX; i++) { - bool found = false; - size_t j; - - if ((!i && VIR_STRDUP(name, path) < 0) || - (i && virAsprintf(&name, "%s-%zu", path, i) < 0)) - return NULL; - - for (j = 0; j < strlen(name); j++) - if (name[j] == '/') - name[j] = '-'; - - for (j = 0; j < privconn->pools.count; j++) { - if (STREQ(name, privconn->pools.objs[j]->def->name)) { - found = true; - break; - } - } - - if (!found) - return name; - - VIR_FREE(name); - } - - return NULL; -} - -static virStoragePoolObjPtr -vzPoolCreateByPath(virConnectPtr conn, const char *path) -{ - vzConnPtr privconn = conn->privateData; - virStoragePoolObjListPtr pools = &privconn->pools; - virStoragePoolDefPtr def; - virStoragePoolObjPtr pool = NULL; - - if (VIR_ALLOC(def) < 0) - goto error; - - if (!(def->name = vzMakePoolName(conn, path))) - goto error; - - if (virUUIDGenerate(def->uuid)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Can't generate UUID")); - goto error; - } - - def->type = VIR_STORAGE_POOL_DIR; - if (VIR_STRDUP(def->target.path, path) < 0) - goto error; - - if (!(pool = virStoragePoolObjAssignDef(pools, def))) - goto error; - - if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) { - virStoragePoolObjRemove(pools, pool); - goto error; - } - - virStoragePoolObjUnlock(pool); - - return pool; - error: - virStoragePoolDefFree(def); - if (pool) - virStoragePoolObjUnlock(pool); - return NULL; -} - -/* - * Create pool of type VIR_STORAGE_POOL_DIR with - * path to the VM, if it does not exist. - */ -static virStoragePoolObjPtr -vzPoolAddByDomain(virConnectPtr conn, virDomainObjPtr dom) -{ - vzConnPtr privconn = conn->privateData; - vzDomObjPtr pdom = dom->privateData; - virStoragePoolObjListPtr pools = &privconn->pools; - char *poolPath; - virStoragePoolObjPtr pool = NULL; - size_t j; - - poolPath = mdir_name(pdom->home); - if (!poolPath) { - virReportOOMError(); - return NULL; - } - - for (j = 0; j < pools->count; j++) { - if (STREQ(poolPath, pools->objs[j]->def->target.path)) { - pool = pools->objs[j]; - break; - } - } - - if (!pool) - pool = vzPoolCreateByPath(conn, poolPath); - - VIR_FREE(poolPath); - return pool; -} - -static int vzDiskDescParseNode(xmlDocPtr xml, - xmlNodePtr root, - virStorageVolDefPtr def) -{ - xmlXPathContextPtr ctxt = NULL; - int ret = -1; - - if (STRNEQ((const char *)root->name, "Parallels_disk_image")) { - virReportError(VIR_ERR_XML_ERROR, - "%s", _("unknown root element for storage pool")); - goto cleanup; - } - - ctxt = xmlXPathNewContext(xml); - if (ctxt == NULL) { - virReportOOMError(); - goto cleanup; - } - - ctxt->node = root; - - if (virXPathULongLong("string(./Disk_Parameters/Disk_size)", - ctxt, &def->target.capacity) < 0) { - virReportError(VIR_ERR_XML_ERROR, - "%s", _("failed to get disk size from " - "the disk descriptor xml")); - goto cleanup; - } - - def->target.capacity <<= 9; - def->target.allocation = def->target.capacity; - ret = 0; - cleanup: - xmlXPathFreeContext(ctxt); - return ret; - -} - -static int vzDiskDescParse(const char *path, virStorageVolDefPtr def) -{ - xmlDocPtr xml; - int ret = -1; - - if (!(xml = virXMLParse(path, NULL, NULL))) - return -1; - - ret = vzDiskDescParseNode(xml, xmlDocGetRootElement(xml), def); - xmlFreeDoc(xml); - return ret; -} - -static int vzAddDiskVolume(virStoragePoolObjPtr pool, - virDomainObjPtr dom, - const char *diskName, - const char *diskPath, - const char *diskDescPath) -{ - virStorageVolDefPtr def = NULL; - - if (VIR_ALLOC(def)) - goto error; - - if (virAsprintf(&def->name, "%s-%s", dom->def->name, diskName) < 0) - goto error; - - def->type = VIR_STORAGE_VOL_FILE; - - if (vzDiskDescParse(diskDescPath, def) < 0) - goto error; - - if (!(def->target.path = realpath(diskPath, NULL))) - goto no_memory; - - if (VIR_STRDUP(def->key, def->target.path) < 0) - goto error; - - if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, def) < 0) - goto error; - - return 0; - no_memory: - virReportOOMError(); - error: - virStorageVolDefFree(def); - return -1; -} - -static int vzFindVmVolumes(virStoragePoolObjPtr pool, - virDomainObjPtr dom) -{ - vzDomObjPtr pdom = dom->privateData; - DIR *dir; - struct dirent *ent; - char *diskPath = NULL, *diskDescPath = NULL; - struct stat sb; - int ret = -1; - int direrr; - - if (!(dir = opendir(pdom->home))) { - virReportSystemError(errno, - _("cannot open path '%s'"), - pdom->home); - return ret; - } - - while ((direrr = virDirRead(dir, &ent, pdom->home)) > 0) { - VIR_FREE(diskPath); - VIR_FREE(diskDescPath); - - if (!(diskPath = virFileBuildPath(pdom->home, ent->d_name, NULL))) - goto cleanup; - - if (lstat(diskPath, &sb) < 0) { - virReportSystemError(errno, - _("cannot stat path '%s'"), - ent->d_name); - goto cleanup; - } - - if (!S_ISDIR(sb.st_mode)) - continue; - - if (!(diskDescPath = virFileBuildPath(diskPath, - "DiskDescriptor", ".xml"))) - goto cleanup; - - if (!virFileExists(diskDescPath)) - continue; - - /* here we know, that ent->d_name is a disk image directory */ - - if (vzAddDiskVolume(pool, dom, ent->d_name, - diskPath, diskDescPath)) - goto cleanup; - } - if (direrr < 0) - goto cleanup; - - ret = 0; - cleanup: - VIR_FREE(diskPath); - VIR_FREE(diskDescPath); - closedir(dir); - return ret; - -} - -static int -vzPoolsAdd(virDomainObjPtr dom, - void *opaque) -{ - virConnectPtr conn = opaque; - virStoragePoolObjPtr pool; - - if (!(pool = vzPoolAddByDomain(conn, dom))) - return -1; - - if (vzFindVmVolumes(pool, dom)) - return -1; - - return 0; -} - -static int vzLoadPools(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - virStorageDriverStatePtr storageState = privconn->storageState; - char *base = NULL; - size_t i; - - if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0) - goto error; - - /* Configuration path is /etc/libvirt/parallels-storage/... . */ - if (virAsprintf(&storageState->configDir, - "%s/parallels-storage", base) == -1) - goto error; - - if (virAsprintf(&storageState->autostartDir, - "%s/parallels-storage/autostart", base) == -1) - goto error; - - VIR_FREE(base); - - if (virStoragePoolLoadAllConfigs(&privconn->pools, - storageState->configDir, - storageState->autostartDir) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to load pool configs")); - goto error; - } - - if (virDomainObjListForEach(privconn->domains, vzPoolsAdd, conn) < 0) - goto error; - - for (i = 0; i < privconn->pools.count; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - virStoragePoolObjPtr pool; - - pool = privconn->pools.objs[i]; - pool->active = 1; - - if (vzStoragePoolGetAlloc(pool->def) < 0) - goto error; - - if (vzFindVolumes(pool) < 0) - goto error; - - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - - return 0; - - error: - VIR_FREE(base); - return -1; -} - -virDrvOpenStatus -vzStorageOpen(virConnectPtr conn, - unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - virStorageDriverStatePtr storageState; - virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - - if (STRNEQ(conn->driver->name, "vz") && - STRNEQ(conn->driver->name, "Parallels")) - return VIR_DRV_OPEN_DECLINED; - - if (VIR_ALLOC(storageState) < 0) - return VIR_DRV_OPEN_ERROR; - - if (virMutexInit(&storageState->lock) < 0) { - VIR_FREE(storageState); - return VIR_DRV_OPEN_ERROR; - } - - privconn->storageState = storageState; - vzStorageLock(storageState); - - if (vzLoadPools(conn)) - goto error; - - vzStorageUnlock(storageState); - - return VIR_DRV_OPEN_SUCCESS; - - error: - vzStorageUnlock(storageState); - vzStorageClose(conn); - return VIR_DRV_OPEN_ERROR; -} - -static int -vzConnectNumOfStoragePools(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - int numActive = 0; - size_t i; - - vzDriverLock(privconn); - for (i = 0; i < privconn->pools.count; i++) - if (virStoragePoolObjIsActive(privconn->pools.objs[i])) - numActive++; - vzDriverUnlock(privconn); - - return numActive; -} - -static int -vzConnectListStoragePools(virConnectPtr conn, char **const names, int nnames) -{ - vzConnPtr privconn = conn->privateData; - int n = 0; - size_t i; - - vzDriverLock(privconn); - memset(names, 0, sizeof(*names) * nnames); - for (i = 0; i < privconn->pools.count && n < nnames; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - if (virStoragePoolObjIsActive(privconn->pools.objs[i]) && - VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) { - virStoragePoolObjUnlock(privconn->pools.objs[i]); - goto error; - } - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - vzDriverUnlock(privconn); - - return n; - - error: - for (n = 0; n < nnames; n++) - VIR_FREE(names[n]); - vzDriverUnlock(privconn); - return -1; -} - -static int -vzConnectNumOfDefinedStoragePools(virConnectPtr conn) -{ - vzConnPtr privconn = conn->privateData; - int numInactive = 0; - size_t i; - - vzDriverLock(privconn); - for (i = 0; i < privconn->pools.count; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - if (!virStoragePoolObjIsActive(privconn->pools.objs[i])) - numInactive++; - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - vzDriverUnlock(privconn); - - return numInactive; -} - -static int -vzConnectListDefinedStoragePools(virConnectPtr conn, - char **const names, int nnames) -{ - vzConnPtr privconn = conn->privateData; - int n = 0; - size_t i; - - vzDriverLock(privconn); - memset(names, 0, sizeof(*names) * nnames); - for (i = 0; i < privconn->pools.count && n < nnames; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) && - VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) { - virStoragePoolObjUnlock(privconn->pools.objs[i]); - goto error; - } - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - vzDriverUnlock(privconn); - - return n; - - error: - for (n = 0; n < nnames; n++) - VIR_FREE(names[n]); - vzDriverUnlock(privconn); - return -1; -} - - -static int -vzStoragePoolIsActive(virStoragePoolPtr pool) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr obj; - int ret = -1; - - vzDriverLock(privconn); - obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid); - vzDriverUnlock(privconn); - if (!obj) { - virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); - goto cleanup; - } - ret = virStoragePoolObjIsActive(obj); - - cleanup: - if (obj) - virStoragePoolObjUnlock(obj); - return ret; -} - -static int -vzStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED) -{ - return 1; -} - -static virStoragePoolPtr -vzStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid) -{ - vzConnPtr privconn = conn->privateData; - virStoragePoolObjPtr pool; - virStoragePoolPtr ret = NULL; - - vzDriverLock(privconn); - pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid); - vzDriverUnlock(privconn); - - if (pool == NULL) { - virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); - goto cleanup; - } - - ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, - NULL, NULL); - - cleanup: - if (pool) - virStoragePoolObjUnlock(pool); - return ret; -} - -static virStoragePoolPtr -vzStoragePoolLookupByName(virConnectPtr conn, const char *name) -{ - vzConnPtr privconn = conn->privateData; - virStoragePoolObjPtr pool; - virStoragePoolPtr ret = NULL; - - vzDriverLock(privconn); - pool = virStoragePoolObjFindByName(&privconn->pools, name); - vzDriverUnlock(privconn); - - if (pool == NULL) { - virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); - goto cleanup; - } - - ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, - NULL, NULL); - - cleanup: - if (pool) - virStoragePoolObjUnlock(pool); - return ret; -} - -static virStoragePoolPtr -vzStoragePoolLookupByVolume(virStorageVolPtr vol) -{ - return vzStoragePoolLookupByName(vol->conn, vol->pool); -} - -/* - * Fill capacity, available and allocation - * fields in pool definition. - */ -static int -vzStoragePoolGetAlloc(virStoragePoolDefPtr def) -{ - struct statvfs sb; - - if (statvfs(def->target.path, &sb) < 0) { - virReportSystemError(errno, - _("cannot statvfs path '%s'"), - def->target.path); - return -1; - } - - def->capacity = ((unsigned long long)sb.f_frsize * - (unsigned long long)sb.f_blocks); - def->available = ((unsigned long long)sb.f_bfree * - (unsigned long long)sb.f_frsize); - def->allocation = def->capacity - def->available; - - return 0; -} - -static virStoragePoolPtr -vzStoragePoolDefineXML(virConnectPtr conn, - const char *xml, unsigned int flags) -{ - vzConnPtr privconn = conn->privateData; - virStoragePoolDefPtr def; - virStoragePoolObjPtr pool = NULL; - virStoragePoolPtr ret = NULL; - - virCheckFlags(0, NULL); - - vzDriverLock(privconn); - if (!(def = virStoragePoolDefParseString(xml))) - goto cleanup; - - if (def->type != VIR_STORAGE_POOL_DIR) { - virReportError(VIR_ERR_NO_SUPPORT, "%s", - _("Only local directories are supported")); - goto cleanup; - } - - if (virStoragePoolObjIsDuplicate(&privconn->pools, def, 0) < 0) - goto cleanup; - - if (virStoragePoolSourceFindDuplicate(conn, &privconn->pools, def) < 0) - goto cleanup; - - if (vzStoragePoolGetAlloc(def)) - goto cleanup; - - if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def))) - goto cleanup; - - if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) { - virStoragePoolObjRemove(&privconn->pools, pool); - def = NULL; - goto cleanup; - } - def = NULL; - - if (VIR_STRDUP(pool->configFile, "\0") < 0) - goto cleanup; - - ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, - NULL, NULL); - - cleanup: - virStoragePoolDefFree(def); - if (pool) - virStoragePoolObjUnlock(pool); - vzDriverUnlock(privconn); - return ret; -} - -static int -vzStoragePoolUndefine(virStoragePoolPtr pool) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is still active"), pool->name); - goto cleanup; - } - - if (virStoragePoolObjDeleteDef(privpool) < 0) - goto cleanup; - - VIR_FREE(privpool->configFile); - - virStoragePoolObjRemove(&privconn->pools, privpool); - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - vzDriverUnlock(privconn); - return ret; -} - -static int -vzStoragePoolCreate(virStoragePoolPtr pool, unsigned int flags) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - virCheckFlags(0, -1); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is already active"), pool->name); - goto cleanup; - } - - privpool->active = 1; - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static int -vzStoragePoolDestroy(virStoragePoolPtr pool) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - - if (privpool->configFile == NULL) { - virStoragePoolObjRemove(&privconn->pools, privpool); - privpool = NULL; - } - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - vzDriverUnlock(privconn); - return ret; -} - -static int -vzStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - virCheckFlags(0, -1); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - - -static int -vzStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - memset(info, 0, sizeof(virStoragePoolInfo)); - if (privpool->active) - info->state = VIR_STORAGE_POOL_RUNNING; - else - info->state = VIR_STORAGE_POOL_INACTIVE; - info->capacity = privpool->def->capacity; - info->allocation = privpool->def->allocation; - info->available = privpool->def->available; - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static char * -vzStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - char *ret = NULL; - - virCheckFlags(0, NULL); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - ret = virStoragePoolDefFormat(privpool->def); - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static int -vzStoragePoolGetAutostart(virStoragePoolPtr pool, int *autostart) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!privpool->configFile) { - *autostart = 0; - } else { - *autostart = privpool->autostart; - } - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static int -vzStoragePoolSetAutostart(virStoragePoolPtr pool, int autostart) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!privpool->configFile) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("pool has no config file")); - goto cleanup; - } - - privpool->autostart = (autostart != 0); - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static int -vzStoragePoolNumOfVolumes(virStoragePoolPtr pool) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - - ret = privpool->volumes.count; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static int -vzStoragePoolListVolumes(virStoragePoolPtr pool, - char **const names, int maxnames) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - int n = 0; - size_t i = 0; - - memset(names, 0, maxnames * sizeof(*names)); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto error; - } - - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto error; - } - - for (i = 0; i < privpool->volumes.count && n < maxnames; i++) { - if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0) - goto error; - } - - virStoragePoolObjUnlock(privpool); - return n; - - error: - for (n = 0; n < maxnames; n++) - VIR_FREE(names[i]); - - if (privpool) - virStoragePoolObjUnlock(privpool); - return -1; -} - -static virStorageVolPtr -vzStorageVolLookupByName(virStoragePoolPtr pool, - const char *name) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol; - virStorageVolPtr ret = NULL; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - - privvol = virStorageVolDefFindByName(privpool, name); - - if (!privvol) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), name); - goto cleanup; - } - - ret = virGetStorageVol(pool->conn, privpool->def->name, - privvol->name, privvol->key, - NULL, NULL); - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - - -static virStorageVolPtr -vzStorageVolLookupByKey(virConnectPtr conn, const char *key) -{ - vzConnPtr privconn = conn->privateData; - size_t i; - virStorageVolPtr ret = NULL; - - vzDriverLock(privconn); - for (i = 0; i < privconn->pools.count; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - if (virStoragePoolObjIsActive(privconn->pools.objs[i])) { - virStorageVolDefPtr privvol = - virStorageVolDefFindByKey(privconn->pools.objs[i], key); - - if (privvol) { - ret = virGetStorageVol(conn, - privconn->pools.objs[i]->def->name, - privvol->name, privvol->key, - NULL, NULL); - virStoragePoolObjUnlock(privconn->pools.objs[i]); - break; - } - } - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - vzDriverUnlock(privconn); - - if (!ret) - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching key '%s'"), key); - - return ret; -} - -virStorageVolPtr -vzStorageVolLookupByPathLocked(virConnectPtr conn, const char *path) -{ - vzConnPtr privconn = conn->privateData; - size_t i; - virStorageVolPtr ret = NULL; - - for (i = 0; i < privconn->pools.count; i++) { - virStoragePoolObjLock(privconn->pools.objs[i]); - if (virStoragePoolObjIsActive(privconn->pools.objs[i])) { - virStorageVolDefPtr privvol = - virStorageVolDefFindByPath(privconn->pools.objs[i], path); - - if (privvol) { - ret = virGetStorageVol(conn, - privconn->pools.objs[i]->def->name, - privvol->name, privvol->key, - NULL, NULL); - virStoragePoolObjUnlock(privconn->pools.objs[i]); - break; - } - } - virStoragePoolObjUnlock(privconn->pools.objs[i]); - } - - if (!ret) - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching path '%s'"), path); - - return ret; -} - -static virStorageVolPtr -vzStorageVolLookupByPath(virConnectPtr conn, const char *path) -{ - vzConnPtr privconn = conn->privateData; - virStorageVolPtr ret = NULL; - - vzDriverLock(privconn); - ret = vzStorageVolLookupByPathLocked(conn, path); - vzDriverUnlock(privconn); - - return ret; -} - -static virStorageVolDefPtr -vzStorageVolDefineXML(virStoragePoolObjPtr pool, - const char *xmldesc, - const char *xmlfile, bool is_new) -{ - virStorageVolDefPtr privvol = NULL; - virStorageVolDefPtr ret = NULL; - char *xml_path = NULL; - - if (xmlfile) - privvol = virStorageVolDefParseFile(pool->def, xmlfile, 0); - else - privvol = virStorageVolDefParseString(pool->def, xmldesc, 0); - - if (privvol == NULL) - goto cleanup; - - if (virStorageVolDefFindByName(pool, privvol->name)) { - virReportError(VIR_ERR_OPERATION_FAILED, - "%s", _("storage vol already exists")); - goto cleanup; - } - - if (is_new) { - /* Make sure enough space */ - if ((pool->def->allocation + privvol->target.allocation) > - pool->def->capacity) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Not enough free space in pool for volume '%s'"), - privvol->name); - goto cleanup; - } - } - - if (virAsprintf(&privvol->target.path, "%s/%s", - pool->def->target.path, privvol->name) < 0) - goto cleanup; - - if (VIR_STRDUP(privvol->key, privvol->target.path) < 0) - goto cleanup; - - if (is_new) { - xml_path = vzAddFileExt(privvol->target.path, ".xml"); - if (!xml_path) - goto cleanup; - - if (virXMLSaveFile(xml_path, NULL, "volume-create", xmldesc)) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("Can't create file with volume description")); - goto cleanup; - } - - pool->def->allocation += privvol->target.allocation; - pool->def->available = (pool->def->capacity - - pool->def->allocation); - } - - if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, - pool->volumes.count, privvol) < 0) - goto cleanup; - - ret = privvol; - privvol = NULL; - - cleanup: - virStorageVolDefFree(privvol); - VIR_FREE(xml_path); - return ret; -} - -static virStorageVolPtr -vzStorageVolCreateXML(virStoragePoolPtr pool, - const char *xmldesc, unsigned int flags) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolPtr ret = NULL; - virStorageVolDefPtr privvol = NULL; - - virCheckFlags(0, NULL); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - - privvol = vzStorageVolDefineXML(privpool, xmldesc, NULL, true); - if (!privvol) - goto cleanup; - - ret = virGetStorageVol(pool->conn, privpool->def->name, - privvol->name, privvol->key, - NULL, NULL); - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static virStorageVolPtr -vzStorageVolCreateXMLFrom(virStoragePoolPtr pool, - const char *xmldesc, - virStorageVolPtr clonevol, - unsigned int flags) -{ - vzConnPtr privconn = pool->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol = NULL, origvol = NULL; - virStorageVolPtr ret = NULL; - - virCheckFlags(0, NULL); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(pool->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), pool->name); - goto cleanup; - } - - privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0); - if (privvol == NULL) - goto cleanup; - - if (virStorageVolDefFindByName(privpool, privvol->name)) { - virReportError(VIR_ERR_OPERATION_FAILED, - "%s", _("storage vol already exists")); - goto cleanup; - } - - origvol = virStorageVolDefFindByName(privpool, clonevol->name); - if (!origvol) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), - clonevol->name); - goto cleanup; - } - - /* Make sure enough space */ - if ((privpool->def->allocation + privvol->target.allocation) > - privpool->def->capacity) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Not enough free space in pool for volume '%s'"), - privvol->name); - goto cleanup; - } - privpool->def->available = (privpool->def->capacity - - privpool->def->allocation); - - if (virAsprintf(&privvol->target.path, "%s/%s", - privpool->def->target.path, privvol->name) == -1) - goto cleanup; - - if (VIR_STRDUP(privvol->key, privvol->target.path) < 0) - goto cleanup; - - privpool->def->allocation += privvol->target.allocation; - privpool->def->available = (privpool->def->capacity - - privpool->def->allocation); - - if (VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs, - privpool->volumes.count, privvol) < 0) - goto cleanup; - - ret = virGetStorageVol(pool->conn, privpool->def->name, - privvol->name, privvol->key, - NULL, NULL); - privvol = NULL; - - cleanup: - virStorageVolDefFree(privvol); - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -int vzStorageVolDefRemove(virStoragePoolObjPtr privpool, - virStorageVolDefPtr privvol) -{ - int ret = -1; - char *xml_path = NULL; - size_t i; - - privpool->def->allocation -= privvol->target.allocation; - privpool->def->available = (privpool->def->capacity - - privpool->def->allocation); - - for (i = 0; i < privpool->volumes.count; i++) { - if (privpool->volumes.objs[i] == privvol) { - xml_path = vzAddFileExt(privvol->target.path, ".xml"); - if (!xml_path) - goto cleanup; - - if (unlink(xml_path)) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Can't remove file '%s'"), xml_path); - goto cleanup; - } - - virStorageVolDefFree(privvol); - - VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count); - break; - } - } - - ret = 0; - cleanup: - VIR_FREE(xml_path); - return ret; -} - -static int -vzStorageVolDelete(virStorageVolPtr vol, unsigned int flags) -{ - vzConnPtr privconn = vol->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol; - int ret = -1; - - virCheckFlags(0, -1); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(vol->pool); - goto cleanup; - } - - - privvol = virStorageVolDefFindByName(privpool, vol->name); - - if (privvol == NULL) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), vol->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), vol->pool); - goto cleanup; - } - - - if (vzStorageVolDefRemove(privpool, privvol)) - goto cleanup; - - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - - -static int -vzStorageVolTypeForPool(int pooltype) -{ - - switch (pooltype) { - case VIR_STORAGE_POOL_DIR: - case VIR_STORAGE_POOL_FS: - case VIR_STORAGE_POOL_NETFS: - return VIR_STORAGE_VOL_FILE; - default: - return VIR_STORAGE_VOL_BLOCK; - } -} - -static int -vzStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) -{ - vzConnPtr privconn = vol->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol; - int ret = -1; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(vol->pool); - goto cleanup; - } - - privvol = virStorageVolDefFindByName(privpool, vol->name); - - if (privvol == NULL) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), vol->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), vol->pool); - goto cleanup; - } - - memset(info, 0, sizeof(*info)); - info->type = vzStorageVolTypeForPool(privpool->def->type); - info->capacity = privvol->target.capacity; - info->allocation = privvol->target.allocation; - ret = 0; - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static char * -vzStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags) -{ - vzConnPtr privconn = vol->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol; - char *ret = NULL; - - virCheckFlags(0, NULL); - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(vol->pool); - goto cleanup; - } - - privvol = virStorageVolDefFindByName(privpool, vol->name); - - if (privvol == NULL) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), vol->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), vol->pool); - goto cleanup; - } - - ret = virStorageVolDefFormat(privpool->def, privvol); - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -static char * -vzStorageVolGetPath(virStorageVolPtr vol) -{ - vzConnPtr privconn = vol->conn->privateData; - virStoragePoolObjPtr privpool; - virStorageVolDefPtr privvol; - char *ret = NULL; - - vzDriverLock(privconn); - privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); - vzDriverUnlock(privconn); - - if (privpool == NULL) { - vzPoolNotFoundError(vol->pool); - goto cleanup; - } - - privvol = virStorageVolDefFindByName(privpool, vol->name); - - if (privvol == NULL) { - virReportError(VIR_ERR_NO_STORAGE_VOL, - _("no storage vol with matching name '%s'"), vol->name); - goto cleanup; - } - - if (!virStoragePoolObjIsActive(privpool)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("storage pool '%s' is not active"), vol->pool); - goto cleanup; - } - - ignore_value(VIR_STRDUP(ret, privvol->target.path)); - - cleanup: - if (privpool) - virStoragePoolObjUnlock(privpool); - return ret; -} - -virStorageDriver vzStorageDriver = { - .name = "Parallels", - - .connectNumOfStoragePools = vzConnectNumOfStoragePools, /* 0.10.0 */ - .connectListStoragePools = vzConnectListStoragePools, /* 0.10.0 */ - .connectNumOfDefinedStoragePools = vzConnectNumOfDefinedStoragePools, /* 0.10.0 */ - .connectListDefinedStoragePools = vzConnectListDefinedStoragePools, /* 0.10.0 */ - .storagePoolLookupByName = vzStoragePoolLookupByName, /* 0.10.0 */ - .storagePoolLookupByUUID = vzStoragePoolLookupByUUID, /* 0.10.0 */ - .storagePoolLookupByVolume = vzStoragePoolLookupByVolume, /* 0.10.0 */ - .storagePoolDefineXML = vzStoragePoolDefineXML, /* 0.10.0 */ - .storagePoolUndefine = vzStoragePoolUndefine, /* 0.10.0 */ - .storagePoolCreate = vzStoragePoolCreate, /* 0.10.0 */ - .storagePoolDestroy = vzStoragePoolDestroy, /* 0.10.0 */ - .storagePoolRefresh = vzStoragePoolRefresh, /* 0.10.0 */ - .storagePoolGetInfo = vzStoragePoolGetInfo, /* 0.10.0 */ - .storagePoolGetXMLDesc = vzStoragePoolGetXMLDesc, /* 0.10.0 */ - .storagePoolGetAutostart = vzStoragePoolGetAutostart, /* 0.10.0 */ - .storagePoolSetAutostart = vzStoragePoolSetAutostart, /* 0.10.0 */ - .storagePoolNumOfVolumes = vzStoragePoolNumOfVolumes, /* 0.10.0 */ - .storagePoolListVolumes = vzStoragePoolListVolumes, /* 0.10.0 */ - - .storageVolLookupByName = vzStorageVolLookupByName, /* 0.10.0 */ - .storageVolLookupByKey = vzStorageVolLookupByKey, /* 0.10.0 */ - .storageVolLookupByPath = vzStorageVolLookupByPath, /* 0.10.0 */ - .storageVolCreateXML = vzStorageVolCreateXML, /* 0.10.0 */ - .storageVolCreateXMLFrom = vzStorageVolCreateXMLFrom, /* 0.10.0 */ - .storageVolDelete = vzStorageVolDelete, /* 0.10.0 */ - .storageVolGetInfo = vzStorageVolGetInfo, /* 0.10.0 */ - .storageVolGetXMLDesc = vzStorageVolGetXMLDesc, /* 0.10.0 */ - .storageVolGetPath = vzStorageVolGetPath, /* 0.10.0 */ - .storagePoolIsActive = vzStoragePoolIsActive, /* 0.10.0 */ - .storagePoolIsPersistent = vzStoragePoolIsPersistent, /* 0.10.0 */ -}; diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c deleted file mode 100644 index 995ef79960..0000000000 --- a/src/parallels/parallels_utils.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * parallels_utils.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 - * . - * - */ - -#include - -#include - -#include "vircommand.h" -#include "virerror.h" -#include "viralloc.h" -#include "virjson.h" -#include "parallels_utils.h" -#include "virstring.h" -#include "datatypes.h" - -#define VIR_FROM_THIS VIR_FROM_PARALLELS - -/** - * vzDomObjFromDomain: - * @domain: Domain pointer that has to be looked up - * - * This function looks up @domain and returns the appropriate virDomainObjPtr - * that has to be unlocked by virObjectUnlock(). - * - * Returns the domain object without incremented reference counter which is locked - * on success, NULL otherwise. - */ -virDomainObjPtr -vzDomObjFromDomain(virDomainPtr domain) -{ - virDomainObjPtr vm; - vzConnPtr privconn = domain->conn->privateData; - char uuidstr[VIR_UUID_STRING_BUFLEN]; - - vm = virDomainObjListFindByUUID(privconn->domains, domain->uuid); - if (!vm) { - virUUIDFormat(domain->uuid, uuidstr); - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s' (%s)"), - uuidstr, domain->name); - return NULL; - } - - return vm; - -} - -/** - * vzDomObjFromDomainRef: - * @domain: Domain pointer that has to be looked up - * - * This function looks up @domain and returns the appropriate virDomainObjPtr - * that has to be released by calling virDomainObjEndAPI(). - * - * Returns the domain object with incremented reference counter which is locked - * on success, NULL otherwise. - */ -virDomainObjPtr -vzDomObjFromDomainRef(virDomainPtr domain) -{ - virDomainObjPtr vm; - vzConnPtr privconn = domain->conn->privateData; - char uuidstr[VIR_UUID_STRING_BUFLEN]; - - vm = virDomainObjListFindByUUIDRef(privconn->domains, domain->uuid); - if (!vm) { - virUUIDFormat(domain->uuid, uuidstr); - virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s' (%s)"), - uuidstr, domain->name); - return NULL; - } - - return vm; -} - -static int -vzDoCmdRun(char **outbuf, const char *binary, va_list list) -{ - virCommandPtr cmd = virCommandNewVAList(binary, list); - int ret = -1; - - if (outbuf) - virCommandSetOutputBuffer(cmd, outbuf); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - - cleanup: - virCommandFree(cmd); - if (ret && outbuf) - VIR_FREE(*outbuf); - return ret; -} - -/* - * Run command and parse its JSON output, return - * pointer to virJSONValue or NULL in case of error. - */ -virJSONValuePtr -vzParseOutput(const char *binary, ...) -{ - char *outbuf; - virJSONValuePtr jobj = NULL; - va_list list; - int ret; - - va_start(list, binary); - ret = vzDoCmdRun(&outbuf, binary, list); - va_end(list); - if (ret) - return NULL; - - jobj = virJSONValueFromString(outbuf); - if (!jobj) - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid output from prlctl: %s"), outbuf); - - VIR_FREE(outbuf); - return jobj; -} - -/* - * Run command and return its output, pointer to - * buffer or NULL in case of error. Caller os responsible - * for freeing the buffer. - */ -char * -vzGetOutput(const char *binary, ...) -{ - char *outbuf; - va_list list; - int ret; - - va_start(list, binary); - ret = vzDoCmdRun(&outbuf, binary, list); - va_end(list); - if (ret) - return NULL; - - return outbuf; -} - -/* - * Run prlctl command and check for errors - * - * Return value is 0 in case of success, else - -1 - */ -int -vzCmdRun(const char *binary, ...) -{ - int ret; - va_list list; - - va_start(list, binary); - ret = vzDoCmdRun(NULL, binary, list); - va_end(list); - - return ret; -} - -/* - * Return new file path in malloced string created by - * concatenating first and second function arguments. - */ -char * -vzAddFileExt(const char *path, const char *ext) -{ - char *new_path = NULL; - size_t len = strlen(path) + strlen(ext) + 1; - - if (VIR_ALLOC_N(new_path, len) < 0) - return NULL; - - if (!virStrcpy(new_path, path, len)) { - VIR_FREE(new_path); - return NULL; - } - strcat(new_path, ext); - - return new_path; -} diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h deleted file mode 100644 index ce540b6a38..0000000000 --- a/src/parallels/parallels_utils.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * parallels_utils.h: 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 - * . - * - */ - -#ifndef PARALLELS_UTILS_H -# define PARALLELS_UTILS_H - -# include - -# include "driver.h" -# include "conf/domain_conf.h" -# include "conf/storage_conf.h" -# include "conf/domain_event.h" -# include "conf/network_conf.h" -# include "virthread.h" -# include "virjson.h" - -# define vzParseError() \ - virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ - __FUNCTION__, __LINE__, _("Can't parse prlctl output")) - -# define IS_CT(def) (def->os.type == VIR_DOMAIN_OSTYPE_EXE) - -# define vzDomNotFoundError(domain) \ - do { \ - char uuidstr[VIR_UUID_STRING_BUFLEN]; \ - virUUIDFormat(domain->uuid, uuidstr); \ - virReportError(VIR_ERR_NO_DOMAIN, \ - _("no domain with matching uuid '%s'"), uuidstr); \ - } while (0) - -# define PARALLELS_DOMAIN_ROUTED_NETWORK_NAME "Routed" -# define PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME "Bridged" - -# define PARALLELS_REQUIRED_HOSTONLY_NETWORK "Host-Only" -# define PARALLELS_HOSTONLY_NETWORK_TYPE "host-only" -# define PARALLELS_REQUIRED_BRIDGED_NETWORK "Bridged" -# define PARALLELS_BRIDGED_NETWORK_TYPE "bridged" - -struct _vzConn { - virMutex lock; - - /* Immutable pointer, self-locking APIs */ - virDomainObjListPtr domains; - - PRL_HANDLE server; - virStoragePoolObjList pools; - virNetworkObjListPtr networks; - virCapsPtr caps; - virDomainXMLOptionPtr xmlopt; - virObjectEventStatePtr domainEventState; - virStorageDriverStatePtr storageState; - const char *drivername; -}; - -typedef struct _vzConn vzConn; -typedef struct _vzConn *vzConnPtr; - -struct _vzCountersCache { - PRL_HANDLE stats; - virCond cond; - // -1 - unsubscribed - // > -1 - subscribed - int count; -}; - -typedef struct _vzCountersCache vzCountersCache; - -struct vzDomObj { - int id; - char *uuid; - char *home; - PRL_HANDLE sdkdom; - vzCountersCache cache; -}; - -typedef struct vzDomObj *vzDomObjPtr; - -virDrvOpenStatus vzStorageOpen(virConnectPtr conn, unsigned int flags); -int vzStorageClose(virConnectPtr conn); -extern virStorageDriver vzStorageDriver; - -virDrvOpenStatus vzNetworkOpen(virConnectPtr conn, unsigned int flags); -int vzNetworkClose(virConnectPtr conn); -extern virNetworkDriver vzNetworkDriver; - -virDomainObjPtr vzDomObjFromDomain(virDomainPtr domain); -virDomainObjPtr vzDomObjFromDomainRef(virDomainPtr domain); - -virJSONValuePtr vzParseOutput(const char *binary, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; -char * vzGetOutput(const char *binary, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; -int vzCmdRun(const char *binary, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; -char * vzAddFileExt(const char *path, const char *ext); -void vzDriverLock(vzConnPtr driver); -void vzDriverUnlock(vzConnPtr driver); -virStorageVolPtr vzStorageVolLookupByPathLocked(virConnectPtr conn, - const char *path); -int vzStorageVolDefRemove(virStoragePoolObjPtr privpool, - virStorageVolDefPtr privvol); - -# define PARALLELS_BLOCK_STATS_FOREACH(OP) \ - OP(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ, "read_requests") \ - OP(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "read_total") \ - OP(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "write_requests") \ - OP(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "write_total") - -#endif diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c new file mode 100644 index 0000000000..cef3c7714e --- /dev/null +++ b/src/vz/vz_driver.c @@ -0,0 +1,1418 @@ +/* + * vz_driver.c: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2014-2015 Red Hat, Inc. + * 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 + * . + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "datatypes.h" +#include "virerror.h" +#include "viralloc.h" +#include "virlog.h" +#include "vircommand.h" +#include "configmake.h" +#include "virfile.h" +#include "virstoragefile.h" +#include "nodeinfo.h" +#include "virstring.h" +#include "cpu/cpu.h" +#include "virtypedparam.h" + +#include "vz_driver.h" +#include "vz_utils.h" +#include "vz_sdk.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +VIR_LOG_INIT("parallels.parallels_driver"); + +#define PRLCTL "prlctl" +#define PRLSRVCTL "prlsrvctl" + +static int vzConnectClose(virConnectPtr conn); + +void +vzDriverLock(vzConnPtr driver) +{ + virMutexLock(&driver->lock); +} + +void +vzDriverUnlock(vzConnPtr driver) +{ + virMutexUnlock(&driver->lock); +} + +static virCapsPtr +vzBuildCapabilities(void) +{ + virCapsPtr caps = NULL; + virCPUDefPtr cpu = NULL; + virCPUDataPtr data = NULL; + virCapsGuestPtr guest; + virNodeInfo nodeinfo; + + if ((caps = virCapabilitiesNew(virArchFromHost(), + false, false)) == NULL) + return NULL; + + if (nodeCapsInitNUMA(caps) < 0) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, + VIR_ARCH_X86_64, + "parallels", + NULL, 0, NULL)) == NULL) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, + VIR_ARCH_I686, + "parallels", + NULL, 0, NULL)) == NULL) + goto error; + + + if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_PARALLELS, + NULL, NULL, 0, NULL) == NULL) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, + VIR_ARCH_X86_64, + "parallels", + NULL, 0, NULL)) == NULL) + goto error; + + if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_PARALLELS, + NULL, NULL, 0, NULL) == NULL) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, + VIR_ARCH_X86_64, + "vz", + NULL, 0, NULL)) == NULL) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, + VIR_ARCH_I686, + "vz", + NULL, 0, NULL)) == NULL) + goto error; + + + if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VZ, + NULL, NULL, 0, NULL) == NULL) + goto error; + + if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, + VIR_ARCH_X86_64, + "vz", + NULL, 0, NULL)) == NULL) + goto error; + + if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VZ, + NULL, NULL, 0, NULL) == NULL) + goto error; + + if (nodeGetInfo(&nodeinfo)) + goto error; + + if (VIR_ALLOC(cpu) < 0) + goto error; + + cpu->arch = caps->host.arch; + cpu->type = VIR_CPU_TYPE_HOST; + cpu->sockets = nodeinfo.sockets; + cpu->cores = nodeinfo.cores; + cpu->threads = nodeinfo.threads; + + caps->host.cpu = cpu; + + if (!(data = cpuNodeData(cpu->arch)) + || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { + goto cleanup; + } + + cleanup: + cpuDataFree(data); + return caps; + + error: + virObjectUnref(caps); + goto cleanup; +} + +static char * +vzConnectGetCapabilities(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + char *xml; + + vzDriverLock(privconn); + xml = virCapabilitiesFormatXML(privconn->caps); + vzDriverUnlock(privconn); + return xml; +} + +static int +vzDomainDefPostParse(virDomainDefPtr def, + virCapsPtr caps ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + /* memory hotplug tunables are not supported by this driver */ + if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0) + return -1; + + return 0; +} + +static int +vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, + const virDomainDef *def, + virCapsPtr caps ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + + if (dev->type == VIR_DOMAIN_DEVICE_NET && + (dev->data.net->type == VIR_DOMAIN_NET_TYPE_NETWORK || + dev->data.net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) && + !dev->data.net->model && + def->os.type == VIR_DOMAIN_OSTYPE_HVM && + VIR_STRDUP(dev->data.net->model, "e1000") < 0) + goto cleanup; + + ret = 0; + cleanup: + return ret; +} + + +virDomainDefParserConfig vzDomainDefParserConfig = { + .macPrefix = {0x42, 0x1C, 0x00}, + .devicesPostParseCallback = vzDomainDeviceDefPostParse, + .domainPostParseCallback = vzDomainDefPostParse, +}; + + +static int +vzOpenDefault(virConnectPtr conn) +{ + vzConnPtr privconn; + + if (VIR_ALLOC(privconn) < 0) + return VIR_DRV_OPEN_ERROR; + if (virMutexInit(&privconn->lock) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + goto err_free; + } + + privconn->drivername = conn->driver->name; + + if (prlsdkInit()) { + VIR_DEBUG("%s", _("Can't initialize Parallels SDK")); + goto err_free; + } + + if (prlsdkConnect(privconn) < 0) + goto err_free; + + if (!(privconn->caps = vzBuildCapabilities())) + goto error; + + if (!(privconn->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig, + NULL, NULL))) + goto error; + + if (!(privconn->domains = virDomainObjListNew())) + goto error; + + if (!(privconn->domainEventState = virObjectEventStateNew())) + goto error; + + if (prlsdkSubscribeToPCSEvents(privconn)) + goto error; + + conn->privateData = privconn; + + if (prlsdkLoadDomains(privconn)) + goto error; + + return VIR_DRV_OPEN_SUCCESS; + + error: + virObjectUnref(privconn->domains); + virObjectUnref(privconn->caps); + virStoragePoolObjListFree(&privconn->pools); + virObjectEventStateFree(privconn->domainEventState); + prlsdkDisconnect(privconn); + prlsdkDeinit(); + err_free: + VIR_FREE(privconn); + return VIR_DRV_OPEN_ERROR; +} + +static virDrvOpenStatus +vzConnectOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret; + + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (!conn->uri) + return VIR_DRV_OPEN_DECLINED; + + if (!conn->uri->scheme) + return VIR_DRV_OPEN_DECLINED; + + if (STRNEQ(conn->uri->scheme, "vz") && + STRNEQ(conn->uri->scheme, "parallels")) + return VIR_DRV_OPEN_DECLINED; + + if (STREQ(conn->uri->scheme, "vz") && STRNEQ(conn->driver->name, "vz")) + return VIR_DRV_OPEN_DECLINED; + + if (STREQ(conn->uri->scheme, "parallels") && STRNEQ(conn->driver->name, "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 (!STREQ_NULLABLE(conn->uri->path, "/system")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected Virtuozzo URI path '%s', try vz:///system"), + conn->uri->path); + return VIR_DRV_OPEN_ERROR; + } + + if ((ret = vzOpenDefault(conn)) != VIR_DRV_OPEN_SUCCESS || + (ret = vzStorageOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS || + (ret = vzNetworkOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS) { + vzConnectClose(conn); + return ret; + } + + return VIR_DRV_OPEN_SUCCESS; +} + +static int +vzConnectClose(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + + if (!privconn) + return 0; + + vzNetworkClose(conn); + vzStorageClose(conn); + + vzDriverLock(privconn); + prlsdkUnsubscribeFromPCSEvents(privconn); + virObjectUnref(privconn->caps); + virObjectUnref(privconn->xmlopt); + virObjectUnref(privconn->domains); + virObjectEventStateFree(privconn->domainEventState); + prlsdkDisconnect(privconn); + conn->privateData = NULL; + prlsdkDeinit(); + + vzDriverUnlock(privconn); + virMutexDestroy(&privconn->lock); + + VIR_FREE(privconn); + return 0; +} + +static int +vzConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + char *output, *sVer, *tmp; + const char *searchStr = "prlsrvctl version "; + int ret = -1; + + output = vzGetOutput(PRLSRVCTL, "--help", NULL); + + if (!output) { + vzParseError(); + goto cleanup; + } + + if (!(sVer = strstr(output, searchStr))) { + vzParseError(); + goto cleanup; + } + + sVer = sVer + strlen(searchStr); + + /* parallels server has versions number like 6.0.17977.782218, + * so libvirt can handle only first two numbers. */ + if (!(tmp = strchr(sVer, '.'))) { + vzParseError(); + goto cleanup; + } + + if (!(tmp = strchr(tmp + 1, '.'))) { + vzParseError(); + goto cleanup; + } + + tmp[0] = '\0'; + if (virParseVersionString(sVer, hvVer, true) < 0) { + vzParseError(); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(output); + return ret; +} + + +static char *vzConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return virGetHostname(); +} + + +static int +vzConnectListDomains(virConnectPtr conn, int *ids, int maxids) +{ + vzConnPtr privconn = conn->privateData; + int n; + + vzDriverLock(privconn); + n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids, + NULL, NULL); + vzDriverUnlock(privconn); + + return n; +} + +static int +vzConnectNumOfDomains(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + int count; + + vzDriverLock(privconn); + count = virDomainObjListNumOfDomains(privconn->domains, true, + NULL, NULL); + vzDriverUnlock(privconn); + + return count; +} + +static int +vzConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) +{ + vzConnPtr privconn = conn->privateData; + int n; + + vzDriverLock(privconn); + memset(names, 0, sizeof(*names) * maxnames); + n = virDomainObjListGetInactiveNames(privconn->domains, names, + maxnames, NULL, NULL); + vzDriverUnlock(privconn); + + return n; +} + +static int +vzConnectNumOfDefinedDomains(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + int count; + + vzDriverLock(privconn); + count = virDomainObjListNumOfDomains(privconn->domains, false, + NULL, NULL); + vzDriverUnlock(privconn); + + return count; +} + +static int +vzConnectListAllDomains(virConnectPtr conn, + virDomainPtr **domains, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); + vzDriverLock(privconn); + ret = virDomainObjListExport(privconn->domains, conn, domains, + NULL, flags); + vzDriverUnlock(privconn); + + return ret; +} + +static virDomainPtr +vzDomainLookupByID(virConnectPtr conn, int id) +{ + vzConnPtr privconn = conn->privateData; + virDomainPtr ret = NULL; + virDomainObjPtr dom; + + vzDriverLock(privconn); + dom = virDomainObjListFindByID(privconn->domains, id); + vzDriverUnlock(privconn); + + if (dom == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + ret = virGetDomain(conn, dom->def->name, dom->def->uuid); + if (ret) + ret->id = dom->def->id; + + cleanup: + if (dom) + virObjectUnlock(dom); + return ret; +} + +static virDomainPtr +vzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) +{ + vzConnPtr privconn = conn->privateData; + virDomainPtr ret = NULL; + virDomainObjPtr dom; + + vzDriverLock(privconn); + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + vzDriverUnlock(privconn); + + if (dom == NULL) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + ret = virGetDomain(conn, dom->def->name, dom->def->uuid); + if (ret) + ret->id = dom->def->id; + + cleanup: + if (dom) + virObjectUnlock(dom); + return ret; +} + +static virDomainPtr +vzDomainLookupByName(virConnectPtr conn, const char *name) +{ + vzConnPtr privconn = conn->privateData; + virDomainPtr ret = NULL; + virDomainObjPtr dom; + + vzDriverLock(privconn); + dom = virDomainObjListFindByName(privconn->domains, name); + vzDriverUnlock(privconn); + + if (dom == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), name); + goto cleanup; + } + + ret = virGetDomain(conn, dom->def->name, dom->def->uuid); + if (ret) + ret->id = dom->def->id; + + cleanup: + virDomainObjEndAPI(&dom); + return ret; +} + +static int +vzDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) +{ + virDomainObjPtr privdom; + int ret = -1; + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + info->state = virDomainObjGetState(privdom, NULL); + info->memory = privdom->def->mem.cur_balloon; + info->maxMem = virDomainDefGetMemoryActual(privdom->def); + info->nrVirtCpu = privdom->def->vcpus; + info->cpuTime = 0; + ret = 0; + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static char * +vzDomainGetOSType(virDomainPtr domain) +{ + virDomainObjPtr privdom; + + char *ret = NULL; + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + ignore_value(VIR_STRDUP(ret, virDomainOSTypeToString(privdom->def->os.type))); + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static int +vzDomainIsPersistent(virDomainPtr domain) +{ + virDomainObjPtr privdom; + int ret = -1; + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + ret = 1; + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static int +vzDomainGetState(virDomainPtr domain, + int *state, int *reason, unsigned int flags) +{ + virDomainObjPtr privdom; + int ret = -1; + virCheckFlags(0, -1); + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + *state = virDomainObjGetState(privdom, reason); + ret = 0; + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static char * +vzDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) +{ + virDomainDefPtr def; + virDomainObjPtr privdom; + char *ret = NULL; + + /* Flags checked by virDomainDefFormat */ + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + def = (flags & VIR_DOMAIN_XML_INACTIVE) && + privdom->newDef ? privdom->newDef : privdom->def; + + ret = virDomainDefFormat(def, flags); + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static int +vzDomainGetAutostart(virDomainPtr domain, int *autostart) +{ + virDomainObjPtr privdom; + int ret = -1; + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + *autostart = privdom->autostart; + ret = 0; + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + +static virDomainPtr +vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + virDomainPtr retdom = NULL; + virDomainDefPtr def; + virDomainObjPtr olddom = NULL; + unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE; + + virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL); + + if (flags & VIR_DOMAIN_DEFINE_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE; + + vzDriverLock(privconn); + if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, + parse_flags)) == NULL) + goto cleanup; + + olddom = virDomainObjListFindByUUID(privconn->domains, def->uuid); + if (olddom == NULL) { + virResetLastError(); + if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { + if (prlsdkCreateVm(conn, def)) + goto cleanup; + } else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) { + if (prlsdkCreateCt(conn, def)) + goto cleanup; + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("Unsupported OS type: %s"), + virDomainOSTypeToString(def->os.type)); + goto cleanup; + } + + olddom = prlsdkAddDomain(privconn, def->uuid); + if (!olddom) + goto cleanup; + } else { + int state, reason; + + state = virDomainObjGetState(olddom, &reason); + + if (state == VIR_DOMAIN_SHUTOFF && + reason == VIR_DOMAIN_SHUTOFF_SAVED) { + + /* PCS doesn't store domain config in managed save state file. + * It's forbidden to change config for VMs in this state. + * It's possible to change config for containers, but after + * restoring domain will have that new config, not a config, + * which domain had at the moment of virDomainManagedSave. + * + * So forbid this operation, if config is changed. If it's + * not changed - just do nothing. */ + + if (!virDomainDefCheckABIStability(olddom->def, def)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Can't change domain configuration " + "in managed save state")); + goto cleanup; + } + } else { + if (prlsdkApplyConfig(conn, olddom, def)) + goto cleanup; + + if (prlsdkUpdateDomain(privconn, olddom)) + goto cleanup; + } + } + + retdom = virGetDomain(conn, def->name, def->uuid); + if (retdom) + retdom->id = def->id; + + cleanup: + if (olddom) + virObjectUnlock(olddom); + virDomainDefFree(def); + vzDriverUnlock(privconn); + return retdom; +} + +static virDomainPtr +vzDomainDefineXML(virConnectPtr conn, const char *xml) +{ + return vzDomainDefineXMLFlags(conn, xml, 0); +} + + +static int +vzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeInfoPtr nodeinfo) +{ + return nodeGetInfo(nodeinfo); +} + +static int vzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* Encryption is not relevant / applicable to way we talk to PCS */ + return 0; +} + +static int vzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* We run CLI tools directly so this is secure */ + return 1; +} + +static int vzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return 1; +} + + +static char * +vzConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL); + + return cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags); +} + + +static int +vzDomainGetVcpus(virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen) +{ + virDomainObjPtr privdom = NULL; + size_t i; + int v, maxcpu, hostcpus; + int ret = -1; + + if (!(privdom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (!virDomainObjIsActive(privdom)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", + _("cannot list vcpu pinning for an inactive domain")); + goto cleanup; + } + + if ((hostcpus = nodeGetCPUCount()) < 0) + goto cleanup; + + maxcpu = maplen * 8; + if (maxcpu > hostcpus) + maxcpu = hostcpus; + + if (maxinfo >= 1) { + if (info != NULL) { + memset(info, 0, sizeof(*info) * maxinfo); + for (i = 0; i < maxinfo; i++) { + info[i].number = i; + info[i].state = VIR_VCPU_RUNNING; + } + } + if (cpumaps != NULL) { + unsigned char *tmpmap = NULL; + int tmpmapLen = 0; + + memset(cpumaps, 0, maplen * maxinfo); + virBitmapToData(privdom->def->cpumask, &tmpmap, &tmpmapLen); + if (tmpmapLen > maplen) + tmpmapLen = maplen; + + for (v = 0; v < maxinfo; v++) { + unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v); + memcpy(cpumap, tmpmap, tmpmapLen); + } + VIR_FREE(tmpmap); + } + } + ret = maxinfo; + + cleanup: + if (privdom) + virObjectUnlock(privdom); + return ret; +} + + +static int +vzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags) +{ + return nodeGetCPUMap(cpumap, online, flags); +} + +static int +vzConnectDomainEventRegisterAny(virConnectPtr conn, + virDomainPtr domain, + int eventID, + virConnectDomainEventGenericCallback callback, + void *opaque, + virFreeCallback freecb) +{ + int ret = -1; + vzConnPtr privconn = conn->privateData; + if (virDomainEventStateRegisterID(conn, + privconn->domainEventState, + domain, eventID, + callback, opaque, freecb, &ret) < 0) + ret = -1; + return ret; +} + +static int +vzConnectDomainEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + vzConnPtr privconn = conn->privateData; + int ret = -1; + + if (virObjectEventStateDeregisterID(conn, + privconn->domainEventState, + callbackID) < 0) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} + +static int vzDomainSuspend(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkPause); +} + +static int vzDomainResume(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkResume); +} + +static int vzDomainCreate(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStart); +} + +static int vzDomainDestroy(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkKill); +} + +static int vzDomainShutdown(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStop); +} + +static int vzDomainIsActive(virDomainPtr domain) +{ + virDomainObjPtr dom = NULL; + int ret = -1; + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + ret = virDomainObjIsActive(dom); + virObjectUnlock(dom); + + return ret; +} + +static int +vzDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) +{ + /* we don't support any create flags */ + virCheckFlags(0, -1); + + return vzDomainCreate(domain); +} + +static int +vzDomainUndefineFlags(virDomainPtr domain, + unsigned int flags) +{ + vzConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom = NULL; + int ret; + + virCheckFlags(0, -1); + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + ret = prlsdkUnregisterDomain(privconn, dom); + if (ret) + virObjectUnlock(dom); + + return ret; +} + +static int +vzDomainUndefine(virDomainPtr domain) +{ + return vzDomainUndefineFlags(domain, 0); +} + +static int +vzDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags) +{ + virDomainObjPtr dom = NULL; + int state, reason; + int ret = 0; + + virCheckFlags(0, -1); + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + state = virDomainObjGetState(dom, &reason); + if (state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED) + ret = 1; + virObjectUnlock(dom); + + return ret; +} + +static int +vzDomainManagedSave(virDomainPtr domain, unsigned int flags) +{ + vzConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom = NULL; + int state, reason; + int ret = -1; + + virCheckFlags(VIR_DOMAIN_SAVE_RUNNING | + VIR_DOMAIN_SAVE_PAUSED, -1); + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + state = virDomainObjGetState(dom, &reason); + + if (state == VIR_DOMAIN_RUNNING && (flags & VIR_DOMAIN_SAVE_PAUSED)) { + ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkPause); + if (ret) + goto cleanup; + } + + ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkSuspend); + + cleanup: + virObjectUnlock(dom); + return ret; +} + +static int +vzDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags) +{ + virDomainObjPtr dom = NULL; + int state, reason; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + state = virDomainObjGetState(dom, &reason); + + if (!(state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED)) + goto cleanup; + + ret = prlsdkDomainManagedSaveRemove(dom); + + cleanup: + virObjectUnlock(dom); + return ret; +} + +static int vzDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, + unsigned int flags) +{ + int ret = -1; + vzConnPtr privconn = dom->conn->privateData; + virDomainDeviceDefPtr dev = NULL; + virDomainObjPtr privdom = NULL; + bool domactive = false; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(privdom = vzDomObjFromDomain(dom))) + return -1; + + if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("device attach needs VIR_DOMAIN_AFFECT_CONFIG " + "flag to be set")); + goto cleanup; + } + + domactive = virDomainObjIsActive(privdom); + if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot do live update a device on " + "inactive domain")); + goto cleanup; + } + if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Updates on a running domain need " + "VIR_DOMAIN_AFFECT_LIVE flag")); + } + + dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps, + privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE); + if (dev == NULL) + goto cleanup; + + switch (dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + ret = prlsdkAttachVolume(privdom, dev->data.disk); + if (ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("disk attach failed")); + goto cleanup; + } + break; + default: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("device type '%s' cannot be attached"), + virDomainDeviceTypeToString(dev->type)); + break; + } + + ret = 0; + cleanup: + virObjectUnlock(privdom); + return ret; +} + +static int vzDomainAttachDevice(virDomainPtr dom, const char *xml) +{ + return vzDomainAttachDeviceFlags(dom, xml, + VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE); +} + +static int vzDomainDetachDeviceFlags(virDomainPtr dom, const char *xml, + unsigned int flags) +{ + int ret = -1; + vzConnPtr privconn = dom->conn->privateData; + virDomainDeviceDefPtr dev = NULL; + virDomainObjPtr privdom = NULL; + bool domactive = false; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + privdom = vzDomObjFromDomain(dom); + if (privdom == NULL) + return -1; + + if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("device detach needs VIR_DOMAIN_AFFECT_CONFIG " + "flag to be set")); + goto cleanup; + } + + domactive = virDomainObjIsActive(privdom); + if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot do live update a device on " + "inactive domain")); + goto cleanup; + } + if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Updates on a running domain need " + "VIR_DOMAIN_AFFECT_LIVE flag")); + } + + dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps, + privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE); + if (dev == NULL) + goto cleanup; + + switch (dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + ret = prlsdkDetachVolume(privdom, dev->data.disk); + if (ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("disk detach failed")); + goto cleanup; + } + break; + default: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("device type '%s' cannot be detached"), + virDomainDeviceTypeToString(dev->type)); + break; + } + + ret = 0; + cleanup: + virObjectUnlock(privdom); + return ret; +} + +static int vzDomainDetachDevice(virDomainPtr dom, const char *xml) +{ + return vzDomainDetachDeviceFlags(dom, xml, + VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE); +} + +static unsigned long long +vzDomainGetMaxMemory(virDomainPtr domain) +{ + virDomainObjPtr dom = NULL; + int ret = -1; + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + ret = dom->def->mem.max_balloon; + virObjectUnlock(dom); + return ret; +} + +static int +vzDomainBlockStats(virDomainPtr domain, const char *path, + virDomainBlockStatsPtr stats) +{ + virDomainObjPtr dom = NULL; + int ret = -1; + size_t i; + int idx; + + if (!(dom = vzDomObjFromDomainRef(domain))) + return -1; + + if (*path) { + if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path); + goto cleanup; + } + if (prlsdkGetBlockStats(dom, dom->def->disks[idx], stats) < 0) + goto cleanup; + } else { + virDomainBlockStatsStruct s; + +#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME) \ + stats->VAR = 0; + + PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS) + +#undef PARALLELS_ZERO_STATS + + for (i = 0; i < dom->def->ndisks; i++) { + if (prlsdkGetBlockStats(dom, dom->def->disks[i], &s) < 0) + goto cleanup; + +#define PARALLELS_SUM_STATS(VAR, TYPE, NAME) \ + if (s.VAR != -1) \ + stats->VAR += s.VAR; + + PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_SUM_STATS) + +#undef PARALLELS_SUM_STATS + } + } + stats->errs = -1; + ret = 0; + + cleanup: + if (dom) + virDomainObjEndAPI(&dom); + + return ret; +} + +static int +vzDomainBlockStatsFlags(virDomainPtr domain, + const char *path, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virDomainBlockStatsStruct stats; + int ret = -1; + size_t i; + + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + /* We don't return strings, and thus trivially support this flag. */ + flags &= ~VIR_TYPED_PARAM_STRING_OKAY; + + if (vzDomainBlockStats(domain, path, &stats) < 0) + goto cleanup; + + if (*nparams == 0) { +#define PARALLELS_COUNT_STATS(VAR, TYPE, NAME) \ + if ((stats.VAR) != -1) \ + ++*nparams; + + PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_COUNT_STATS) + +#undef PARALLELS_COUNT_STATS + ret = 0; + goto cleanup; + } + + i = 0; +#define PARALLELS_BLOCK_STATS_ASSIGN_PARAM(VAR, TYPE, NAME) \ + if (i < *nparams && (stats.VAR) != -1) { \ + if (virTypedParameterAssign(params + i, TYPE, \ + VIR_TYPED_PARAM_LLONG, (stats.VAR)) < 0) \ + goto cleanup; \ + i++; \ + } + + PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_BLOCK_STATS_ASSIGN_PARAM) + +#undef PARALLELS_BLOCK_STATS_ASSIGN_PARAM + + *nparams = i; + ret = 0; + + cleanup: + return ret; +} + + +static virHypervisorDriver vzDriver = { + .name = "vz", + .connectOpen = vzConnectOpen, /* 0.10.0 */ + .connectClose = vzConnectClose, /* 0.10.0 */ + .connectGetVersion = vzConnectGetVersion, /* 0.10.0 */ + .connectGetHostname = vzConnectGetHostname, /* 0.10.0 */ + .nodeGetInfo = vzNodeGetInfo, /* 0.10.0 */ + .connectGetCapabilities = vzConnectGetCapabilities, /* 0.10.0 */ + .connectBaselineCPU = vzConnectBaselineCPU, /* 1.2.6 */ + .connectListDomains = vzConnectListDomains, /* 0.10.0 */ + .connectNumOfDomains = vzConnectNumOfDomains, /* 0.10.0 */ + .connectListDefinedDomains = vzConnectListDefinedDomains, /* 0.10.0 */ + .connectNumOfDefinedDomains = vzConnectNumOfDefinedDomains, /* 0.10.0 */ + .connectListAllDomains = vzConnectListAllDomains, /* 0.10.0 */ + .domainLookupByID = vzDomainLookupByID, /* 0.10.0 */ + .domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */ + .domainLookupByName = vzDomainLookupByName, /* 0.10.0 */ + .domainGetOSType = vzDomainGetOSType, /* 0.10.0 */ + .domainGetInfo = vzDomainGetInfo, /* 0.10.0 */ + .domainGetState = vzDomainGetState, /* 0.10.0 */ + .domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */ + .domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */ + .domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */ + .domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */ + .domainSuspend = vzDomainSuspend, /* 0.10.0 */ + .domainResume = vzDomainResume, /* 0.10.0 */ + .domainDestroy = vzDomainDestroy, /* 0.10.0 */ + .domainShutdown = vzDomainShutdown, /* 0.10.0 */ + .domainCreate = vzDomainCreate, /* 0.10.0 */ + .domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */ + .domainDefineXML = vzDomainDefineXML, /* 0.10.0 */ + .domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */ + .domainUndefine = vzDomainUndefine, /* 1.2.10 */ + .domainUndefineFlags = vzDomainUndefineFlags, /* 1.2.10 */ + .domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */ + .domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */ + .domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */ + .domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */ + .domainIsActive = vzDomainIsActive, /* 1.2.10 */ + .connectDomainEventRegisterAny = vzConnectDomainEventRegisterAny, /* 1.2.10 */ + .connectDomainEventDeregisterAny = vzConnectDomainEventDeregisterAny, /* 1.2.10 */ + .nodeGetCPUMap = vzNodeGetCPUMap, /* 1.2.8 */ + .connectIsEncrypted = vzConnectIsEncrypted, /* 1.2.5 */ + .connectIsSecure = vzConnectIsSecure, /* 1.2.5 */ + .connectIsAlive = vzConnectIsAlive, /* 1.2.5 */ + .domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */ + .domainManagedSave = vzDomainManagedSave, /* 1.2.14 */ + .domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */ + .domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */ + .domainBlockStats = vzDomainBlockStats, /* 1.3.0 */ + .domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.3.0 */ +}; + +static virConnectDriver vzConnectDriver = { + .hypervisorDriver = &vzDriver, + .storageDriver = &vzStorageDriver, + .networkDriver = &vzNetworkDriver, +}; + +/* Parallels domain type backward compatibility*/ +static virHypervisorDriver parallelsDriver; +static virConnectDriver parallelsConnectDriver; + +/** + * vzRegister: + * + * Registers the vz driver + */ +int +vzRegister(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); + + /* Backward compatibility with Parallels domain type */ + parallelsDriver = vzDriver; + parallelsDriver.name = "Parallels"; + parallelsConnectDriver = vzConnectDriver; + parallelsConnectDriver.hypervisorDriver = ¶llelsDriver; + if (virRegisterConnectDriver(¶llelsConnectDriver, false) < 0) + return -1; + + if (virRegisterConnectDriver(&vzConnectDriver, false) < 0) + return -1; + + return 0; +} diff --git a/src/vz/vz_driver.h b/src/vz/vz_driver.h new file mode 100644 index 0000000000..3c7610637f --- /dev/null +++ b/src/vz/vz_driver.h @@ -0,0 +1,28 @@ +/* + * vz_driver.h: 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 + * . + * + */ + +#ifndef PARALLELS_DRIVER_H +# define PARALLELS_DRIVER_H + +int vzRegister(void); + +#endif diff --git a/src/vz/vz_network.c b/src/vz/vz_network.c new file mode 100644 index 0000000000..3a5a3ffaf5 --- /dev/null +++ b/src/vz/vz_network.c @@ -0,0 +1,556 @@ +/* + * vz_network.c: core privconn functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2013-2014 Red Hat, Inc. + * 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 + * . + * + */ + +#include + +#include "datatypes.h" +#include "dirname.h" +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "virnetdev.h" +#include "md5.h" +#include "vz_utils.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS +#define PARALLELS_ROUTED_NETWORK_UUID "eb593dd1-6846-45b0-84a0-de0729286982" + +#define vzParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + +static int vzGetBridgedNetInfo(virNetworkDefPtr def, virJSONValuePtr jobj) +{ + const char *ifname; + char *bridgeLink = NULL; + char *bridgePath = NULL; + char *bridgeAddressPath = NULL; + char *bridgeAddress = NULL; + int len = 0; + int ret = -1; + + if (!(ifname = virJSONValueObjectGetString(jobj, "Bound To"))) { + vzParseError(); + goto cleanup; + } + + if (virAsprintf(&bridgeLink, SYSFS_NET_DIR "%s/brport/bridge", ifname) < 0) + goto cleanup; + + if (virFileResolveLink(bridgeLink, &bridgePath) < 0) { + virReportSystemError(errno, _("cannot read link '%s'"), bridgeLink); + goto cleanup; + } + + if (VIR_STRDUP(def->bridge, last_component(bridgePath)) < 0) + goto cleanup; + + if (virAsprintf(&bridgeAddressPath, SYSFS_NET_DIR "%s/brport/bridge/address", + ifname) < 0) + goto cleanup; + + if ((len = virFileReadAll(bridgeAddressPath, 18, &bridgeAddress)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading file '%s'"), bridgeAddressPath); + + goto cleanup; + } + + if (len < VIR_MAC_STRING_BUFLEN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading MAC from '%s'"), bridgeAddressPath); + } + + bridgeAddress[VIR_MAC_STRING_BUFLEN - 1] = '\0'; + if (virMacAddrParse(bridgeAddress, &def->mac) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse MAC '%s'"), bridgeAddress); + goto cleanup; + } + def->mac_specified = 1; + + ret = 0; + + cleanup: + VIR_FREE(bridgeLink); + VIR_FREE(bridgePath); + VIR_FREE(bridgeAddress); + VIR_FREE(bridgeAddressPath); + return ret; +} + +static int vzGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) +{ + const char *tmp; + virJSONValuePtr jobj = NULL, jobj2; + int ret = -1; + + if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) + goto cleanup; + + jobj = vzParseOutput("prlsrvctl", "net", "info", "-j", name, NULL); + + if (!jobj) { + vzParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "Parallels adapter"))) { + vzParseError(); + goto cleanup; + } + + if (VIR_STRDUP(def->ips[0].family, "ipv4") < 0) + goto cleanup; + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP address"))) { + vzParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].address, tmp) < 0) { + vzParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "Subnet mask"))) { + vzParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].netmask, tmp) < 0) { + vzParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "DHCPv4 server"))) { + vzParseError(); + goto cleanup; + } + + if (VIR_EXPAND_N(def->ips[0].ranges, def->ips[0].nranges, 1) < 0) + goto cleanup; + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope start address"))) { + vzParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].start, tmp) < 0) { + vzParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope end address"))) { + vzParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].end, tmp) < 0) { + vzParseError(); + goto cleanup; + } + + ret = 0; + cleanup: + virJSONValueFree(jobj); + return ret; +} + +static int +vzLoadNetwork(vzConnPtr privconn, virJSONValuePtr jobj) +{ + int ret = -1; + virNetworkObjPtr net = NULL; + virNetworkDefPtr def; + const char *tmp; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + if (!(tmp = virJSONValueObjectGetString(jobj, "Network ID"))) { + vzParseError(); + goto cleanup; + } + + if (VIR_STRDUP(def->name, tmp) < 0) + goto cleanup; + + /* Network names are unique in Parallels Cloud Server, so we can make + * a UUID from it */ + md5_buffer(tmp, strlen(tmp), md5); + memcpy(def->uuid, md5, VIR_UUID_BUFLEN); + def->uuid_specified = 1; + + if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { + vzParseError(); + goto cleanup; + } + + if (STREQ(tmp, PARALLELS_BRIDGED_NETWORK_TYPE)) { + def->forward.type = VIR_NETWORK_FORWARD_BRIDGE; + + if (vzGetBridgedNetInfo(def, jobj) < 0) { + + /* Only mandatory networks are required to be configured completely */ + if (STRNEQ(def->name, PARALLELS_REQUIRED_BRIDGED_NETWORK)) + ret = 0; + + goto cleanup; + } + } else if (STREQ(tmp, PARALLELS_HOSTONLY_NETWORK_TYPE)) { + def->forward.type = VIR_NETWORK_FORWARD_NONE; + + if (vzGetHostOnlyNetInfo(def, def->name) < 0) { + + /* Only mandatory networks are required to be configured completely */ + if (STRNEQ(def->name, PARALLELS_REQUIRED_HOSTONLY_NETWORK)) + ret = 0; + + goto cleanup; + } + } else { + vzParseError(); + goto cleanup; + } + + if (!(net = virNetworkAssignDef(privconn->networks, def, 0))) + goto cleanup; + def = NULL; + net->active = 1; + net->autostart = 1; + ret = 0; + + cleanup: + virNetworkObjEndAPI(&net); + virNetworkDefFree(def); + return ret; +} + +static int +vzAddRoutedNetwork(vzConnPtr privconn) +{ + virNetworkObjPtr net = NULL; + virNetworkDefPtr def; + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + def->forward.type = VIR_NETWORK_FORWARD_ROUTE; + + if (VIR_STRDUP(def->name, PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) + goto cleanup; + + if (virUUIDParse(PARALLELS_ROUTED_NETWORK_UUID, def->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Can't parse UUID")); + goto cleanup; + } + def->uuid_specified = 1; + + if (!(net = virNetworkAssignDef(privconn->networks, def, 0))) + goto cleanup; + + net->active = 1; + net->autostart = 1; + virNetworkObjEndAPI(&net); + + return 0; + + cleanup: + virNetworkDefFree(def); + return -1; +} + +static int vzLoadNetworks(vzConnPtr privconn) +{ + virJSONValuePtr jobj, jobj2; + int ret = -1; + int count; + size_t i; + + jobj = vzParseOutput("prlsrvctl", "net", "list", "-j", NULL); + + if (!jobj) { + vzParseError(); + goto cleanup; + } + + count = virJSONValueArraySize(jobj); + if (count < 0) { + vzParseError(); + goto cleanup; + } + + for (i = 0; i < count; i++) { + jobj2 = virJSONValueArrayGet(jobj, i); + if (!jobj2) { + vzParseError(); + goto cleanup; + } + + if (vzLoadNetwork(privconn, jobj2) < 0) + goto cleanup; + } + + if (vzAddRoutedNetwork(privconn) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(jobj); + return ret; +} + +virDrvOpenStatus +vzNetworkOpen(virConnectPtr conn, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (STRNEQ(conn->driver->name, "vz") && + STRNEQ(conn->driver->name, "Parallels")) + return VIR_DRV_OPEN_DECLINED; + + if (!(privconn->networks = virNetworkObjListNew())) + goto error; + + if (vzLoadNetworks(conn->privateData) < 0) + goto error; + + return VIR_DRV_OPEN_SUCCESS; + error: + virObjectUnref(privconn->networks); + privconn->networks = NULL; + return VIR_DRV_OPEN_ERROR; +} + +int vzNetworkClose(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + + if (!privconn) + return 0; + + virObjectUnref(privconn->networks); + return 0; +} + +static int vzConnectNumOfNetworks(virConnectPtr conn) +{ + int nactive; + vzConnPtr privconn = conn->privateData; + + nactive = virNetworkObjListNumOfNetworks(privconn->networks, + true, NULL, conn); + return nactive; +} + +static int vzConnectListNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + vzConnPtr privconn = conn->privateData; + int got; + + got = virNetworkObjListGetNames(privconn->networks, + true, names, nnames, NULL, conn); + return got; +} + +static int vzConnectNumOfDefinedNetworks(virConnectPtr conn) +{ + int ninactive; + vzConnPtr privconn = conn->privateData; + + ninactive = virNetworkObjListNumOfNetworks(privconn->networks, + false, NULL, conn); + return ninactive; +} + +static int vzConnectListDefinedNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + vzConnPtr privconn = conn->privateData; + int got; + + got = virNetworkObjListGetNames(privconn->networks, + false, names, nnames, NULL, conn); + return got; +} + +static int vzConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags); +} + +static virNetworkPtr vzNetworkLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + vzConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + network = virNetworkObjFindByUUID(privconn->networks, uuid); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + + cleanup: + virNetworkObjEndAPI(&network); + return ret; +} + +static virNetworkPtr vzNetworkLookupByName(virConnectPtr conn, + const char *name) +{ + vzConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + network = virNetworkObjFindByName(privconn->networks, name); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + _("no network with matching name '%s'"), name); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + + cleanup: + virNetworkObjEndAPI(&network); + return ret; +} + +static char *vzNetworkGetXMLDesc(virNetworkPtr net, + unsigned int flags) +{ + vzConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + char *ret = NULL; + + virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL); + + network = virNetworkObjFindByUUID(privconn->networks, net->uuid); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virNetworkDefFormat(network->def, flags); + + cleanup: + virNetworkObjEndAPI(&network); + return ret; +} + +static int vzNetworkIsActive(virNetworkPtr net) +{ + vzConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + obj = virNetworkObjFindByUUID(privconn->networks, net->uuid); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = virNetworkObjIsActive(obj); + + cleanup: + virNetworkObjEndAPI(&obj); + return ret; +} + +static int vzNetworkIsPersistent(virNetworkPtr net) +{ + vzConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + obj = virNetworkObjFindByUUID(privconn->networks, net->uuid); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = obj->persistent; + + cleanup: + virNetworkObjEndAPI(&obj); + return ret; +} + +static int vzNetworkGetAutostart(virNetworkPtr net, + int *autostart) +{ + vzConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + int ret = -1; + + network = virNetworkObjFindByUUID(privconn->networks, net->uuid); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + *autostart = network->autostart; + ret = 0; + + cleanup: + virNetworkObjEndAPI(&network); + return ret; +} + +virNetworkDriver vzNetworkDriver = { + .name = "Parallels", + .connectNumOfNetworks = vzConnectNumOfNetworks, /* 1.0.1 */ + .connectListNetworks = vzConnectListNetworks, /* 1.0.1 */ + .connectNumOfDefinedNetworks = vzConnectNumOfDefinedNetworks, /* 1.0.1 */ + .connectListDefinedNetworks = vzConnectListDefinedNetworks, /* 1.0.1 */ + .connectListAllNetworks = vzConnectListAllNetworks, /* 1.0.1 */ + .networkLookupByUUID = vzNetworkLookupByUUID, /* 1.0.1 */ + .networkLookupByName = vzNetworkLookupByName, /* 1.0.1 */ + .networkGetXMLDesc = vzNetworkGetXMLDesc, /* 1.0.1 */ + .networkGetAutostart = vzNetworkGetAutostart, /* 1.0.1 */ + .networkIsActive = vzNetworkIsActive, /* 1.0.1 */ + .networkIsPersistent = vzNetworkIsPersistent, /* 1.0.1 */ +}; diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c new file mode 100644 index 0000000000..f9cde44475 --- /dev/null +++ b/src/vz/vz_sdk.c @@ -0,0 +1,3660 @@ +/* + * vz_sdk.c: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2014 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 + * . + * + */ + +#include +#include + +#include "virerror.h" +#include "viralloc.h" +#include "virstring.h" +#include "nodeinfo.h" +#include "virlog.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "virtime.h" + +#include "vz_sdk.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS +#define JOB_INFINIT_WAIT_TIMEOUT UINT_MAX + +VIR_LOG_INIT("parallels.sdk"); + +/* + * Log error description + */ +static void +logPrlErrorHelper(PRL_RESULT err, const char *filename, + const char *funcname, size_t linenr) +{ + char *msg1 = NULL, *msg2 = NULL; + PRL_UINT32 len = 0; + + /* Get required buffer length */ + PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, NULL, &len); + + if (VIR_ALLOC_N(msg1, len) < 0) + goto cleanup; + + /* get short error description */ + PrlApi_GetResultDescription(err, PRL_TRUE, PRL_FALSE, msg1, &len); + + PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, NULL, &len); + + if (VIR_ALLOC_N(msg2, len) < 0) + goto cleanup; + + /* get long error description */ + PrlApi_GetResultDescription(err, PRL_FALSE, PRL_FALSE, msg2, &len); + + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR, + filename, funcname, linenr, + _("%s %s"), msg1, msg2); + + cleanup: + VIR_FREE(msg1); + VIR_FREE(msg2); +} + +#define logPrlError(code) \ + logPrlErrorHelper(code, __FILE__, \ + __FUNCTION__, __LINE__) + +#define prlsdkCheckRetGoto(ret, label) \ + do { \ + if (PRL_FAILED(ret)) { \ + logPrlError(ret); \ + goto label; \ + } \ + } while (0) + +static PRL_RESULT +logPrlEventErrorHelper(PRL_HANDLE event, const char *filename, + const char *funcname, size_t linenr) +{ + PRL_RESULT ret, retCode; + char *msg1 = NULL, *msg2 = NULL; + PRL_UINT32 len = 0; + int err = -1; + + if ((ret = PrlEvent_GetErrCode(event, &retCode))) { + logPrlError(ret); + return ret; + } + + PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, NULL, &len); + + if (VIR_ALLOC_N(msg1, len) < 0) + goto cleanup; + + PrlEvent_GetErrString(event, PRL_TRUE, PRL_FALSE, msg1, &len); + + PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, NULL, &len); + + if (VIR_ALLOC_N(msg2, len) < 0) + goto cleanup; + + PrlEvent_GetErrString(event, PRL_FALSE, PRL_FALSE, msg2, &len); + + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INTERNAL_ERROR, + filename, funcname, linenr, + _("%s %s"), msg1, msg2); + err = 0; + + cleanup: + VIR_FREE(msg1); + VIR_FREE(msg2); + + return err; +} + +#define logPrlEventError(event) \ + logPrlEventErrorHelper(event, __FILE__, \ + __FUNCTION__, __LINE__) + +static PRL_RESULT +getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result, + const char *filename, const char *funcname, + size_t linenr) +{ + PRL_RESULT ret, retCode; + + if ((ret = PrlJob_Wait(job, timeout))) { + logPrlErrorHelper(ret, filename, funcname, linenr); + goto cleanup; + } + + if ((ret = PrlJob_GetRetCode(job, &retCode))) { + logPrlErrorHelper(ret, filename, funcname, linenr); + goto cleanup; + } + + if (retCode) { + PRL_HANDLE err_handle; + + /* Sometimes it's possible to get additional error info. */ + if ((ret = PrlJob_GetError(job, &err_handle))) { + logPrlErrorHelper(ret, filename, funcname, linenr); + goto cleanup; + } + + if (logPrlEventErrorHelper(err_handle, filename, funcname, linenr)) + logPrlErrorHelper(retCode, filename, funcname, linenr); + + PrlHandle_Free(err_handle); + ret = retCode; + } else { + ret = PrlJob_GetResult(job, result); + if (PRL_FAILED(ret)) { + logPrlErrorHelper(ret, filename, funcname, linenr); + PrlHandle_Free(*result); + *result = NULL; + goto cleanup; + } + + ret = PRL_ERR_SUCCESS; + } + + cleanup: + PrlHandle_Free(job); + return ret; +} + +#define getJobResult(job, result) \ + getJobResultHelper(job, JOB_INFINIT_WAIT_TIMEOUT, \ + result, __FILE__, __FUNCTION__, __LINE__) + +static PRL_RESULT +waitJobHelper(PRL_HANDLE job, unsigned int timeout, + const char *filename, const char *funcname, + size_t linenr) +{ + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_RESULT ret; + + ret = getJobResultHelper(job, timeout, &result, + filename, funcname, linenr); + PrlHandle_Free(result); + return ret; +} + +#define waitJob(job) \ + waitJobHelper(job, JOB_INFINIT_WAIT_TIMEOUT, __FILE__, \ + __FUNCTION__, __LINE__) + + +int +prlsdkInit(void) +{ + PRL_RESULT ret; + + /* Disable console output */ + PrlApi_SwitchConsoleLogging(0); + + ret = PrlApi_InitEx(PARALLELS_API_VER, PAM_SERVER, 0, 0); + if (PRL_FAILED(ret)) { + logPrlError(ret); + return -1; + } + + return 0; +}; + +void +prlsdkDeinit(void) +{ + PrlApi_Deinit(); +}; + +int +prlsdkConnect(vzConnPtr privconn) +{ + PRL_RESULT ret; + PRL_HANDLE job = PRL_INVALID_HANDLE; + + ret = PrlSrv_Create(&privconn->server); + if (PRL_FAILED(ret)) { + logPrlError(ret); + return -1; + } + + job = PrlSrv_LoginLocalEx(privconn->server, NULL, 0, + PSL_HIGH_SECURITY, PACF_NON_INTERACTIVE_MODE); + + if (waitJob(job)) { + PrlHandle_Free(privconn->server); + return -1; + } + + return 0; +} + +void +prlsdkDisconnect(vzConnPtr privconn) +{ + PRL_HANDLE job; + + job = PrlSrv_Logoff(privconn->server); + waitJob(job); + + PrlHandle_Free(privconn->server); +} + +static int +prlsdkSdkDomainLookup(vzConnPtr privconn, + const char *id, + unsigned int flags, + PRL_HANDLE *sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + int ret = -1; + + job = PrlSrv_GetVmConfig(privconn->server, id, flags); + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(result); + return ret; +} + +static void +prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr) +{ + virUUIDFormat(uuid, uuidstr + 1); + + uuidstr[0] = '{'; + uuidstr[VIR_UUID_STRING_BUFLEN] = '}'; + uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0'; +} + +static PRL_HANDLE +prlsdkSdkDomainLookupByUUID(vzConnPtr privconn, const unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + + prlsdkUUIDFormat(uuid, uuidstr); + + if (prlsdkSdkDomainLookup(privconn, uuidstr, + PGVC_SEARCH_BY_UUID, &sdkdom) < 0) { + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + return PRL_INVALID_HANDLE; + } + + return sdkdom; +} + +static int +prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid) +{ + char *tmp = NULL; + int ret = -1; + + virCheckNonNullArgGoto(uuidstr, error); + virCheckNonNullArgGoto(uuid, error); + + if (VIR_STRDUP(tmp, uuidstr) < 0) + goto error; + + tmp[strlen(tmp) - 1] = '\0'; + + /* trim curly braces */ + if (virUUIDParse(tmp + 1, uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("UUID in config file malformed")); + ret = -1; + goto error; + } + + ret = 0; + error: + VIR_FREE(tmp); + return ret; +} + +static int +prlsdkGetDomainIds(PRL_HANDLE sdkdom, + char **name, + unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 len; + PRL_RESULT pret; + + len = 0; + /* get name length */ + pret = PrlVmCfg_GetName(sdkdom, NULL, &len); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(*name, len) < 0) + goto error; + + PrlVmCfg_GetName(sdkdom, *name, &len); + prlsdkCheckRetGoto(pret, error); + + len = sizeof(uuidstr); + PrlVmCfg_GetUuid(sdkdom, uuidstr, &len); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + goto error; + + return 0; + + error: + VIR_FREE(*name); + return -1; +} + +static int +prlsdkGetDomainState(PRL_HANDLE sdkdom, VIRTUAL_MACHINE_STATE_PTR vmState) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_HANDLE vmInfo = PRL_INVALID_HANDLE; + PRL_RESULT pret; + int ret = -1; + + job = PrlVm_GetState(sdkdom); + + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, &vmInfo); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmInfo_GetState(vmInfo, vmState); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(vmInfo); + PrlHandle_Free(result); + return ret; +} + +static void +prlsdkDomObjFreePrivate(void *p) +{ + vzDomObjPtr pdom = p; + + if (!pdom) + return; + + PrlHandle_Free(pdom->sdkdom); + PrlHandle_Free(pdom->cache.stats); + virCondDestroy(&pdom->cache.cond); + VIR_FREE(pdom->uuid); + VIR_FREE(pdom->home); + VIR_FREE(p); +}; + +static int +prlsdkAddDomainVideoInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainVideoDefPtr video = NULL; + virDomainVideoAccelDefPtr accel = NULL; + PRL_RESULT ret; + PRL_UINT32 videoRam; + + /* video info */ + ret = PrlVmCfg_GetVideoRamSize(sdkdom, &videoRam); + prlsdkCheckRetGoto(ret, error); + + if (VIR_ALLOC(video) < 0) + goto error; + + if (VIR_ALLOC(accel) < 0) + goto error; + + if (VIR_APPEND_ELEMENT_COPY(def->videos, def->nvideos, video) < 0) + goto error; + + video->type = VIR_DOMAIN_VIDEO_TYPE_VGA; + video->vram = videoRam << 10; /* from mbibytes to kbibytes */ + video->heads = 1; + video->accel = accel; + + return 0; + + error: + VIR_FREE(accel); + virDomainVideoDefFree(video); + return -1; +} + +static int +prlsdkGetDiskInfo(PRL_HANDLE prldisk, + virDomainDiskDefPtr disk, + bool isCdrom, + bool isCt) +{ + char *buf = NULL; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 emulatedType; + PRL_UINT32 ifType; + PRL_UINT32 pos; + virDomainDeviceDriveAddressPtr address; + int ret = -1; + + pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType); + prlsdkCheckRetGoto(pret, cleanup); + if (emulatedType == PDT_USE_IMAGE_FILE) { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); + if (isCdrom) + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); + else + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); + } else { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); + } + + if (isCdrom) { + disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + disk->src->readonly = true; + } else { + disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; + } + + pret = PrlVmDev_GetFriendlyName(prldisk, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmDev_GetFriendlyName(prldisk, buf, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (virDomainDiskSetSource(disk, buf) < 0) + goto cleanup; + + /* Let physical devices added to CT look like SATA disks */ + if (isCt) { + ifType = PMS_SATA_DEVICE; + } else { + pret = PrlVmDev_GetIfaceType(prldisk, &ifType); + prlsdkCheckRetGoto(pret, cleanup); + } + + pret = PrlVmDev_GetStackIndex(prldisk, &pos); + prlsdkCheckRetGoto(pret, cleanup); + + address = &disk->info.addr.drive; + switch (ifType) { + case PMS_IDE_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + disk->dst = virIndexToDiskName(pos, "hd"); + address->bus = pos / 2; + address->target = 0; + address->unit = pos % 2; + break; + case PMS_SCSI_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; + disk->dst = virIndexToDiskName(pos, "sd"); + address->bus = 0; + address->target = 0; + address->unit = pos; + break; + case PMS_SATA_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SATA; + disk->dst = virIndexToDiskName(pos, "sd"); + address->bus = 0; + address->target = 0; + address->unit = pos; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown disk bus: %X"), ifType); + goto cleanup; + break; + } + + if (!disk->dst) + goto cleanup; + + disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + + ret = 0; + + cleanup: + VIR_FREE(buf); + return ret; +} + +static int +prlsdkGetFSInfo(PRL_HANDLE prldisk, + virDomainFSDefPtr fs) +{ + char *buf = NULL; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + int ret = -1; + + fs->type = VIR_DOMAIN_FS_TYPE_FILE; + fs->fsdriver = VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP; + fs->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; + fs->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT; + fs->format = VIR_STORAGE_FILE_PLOOP; + + fs->readonly = false; + fs->symlinksResolved = false; + + pret = PrlVmDev_GetImagePath(prldisk, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmDev_GetImagePath(prldisk, buf, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + fs->src = buf; + buf = NULL; + + pret = PrlVmDevHd_GetMountPoint(prldisk, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmDevHd_GetMountPoint(prldisk, buf, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + fs->dst = buf; + buf = NULL; + + ret = 0; + + cleanup: + VIR_FREE(buf); + return ret; +} + +static int +prlsdkAddDomainHardDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_RESULT pret; + PRL_UINT32 hddCount; + PRL_UINT32 i; + PRL_HANDLE hdd = PRL_INVALID_HANDLE; + virDomainDiskDefPtr disk = NULL; + virDomainFSDefPtr fs = NULL; + + pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < hddCount; ++i) { + + PRL_UINT32 emulatedType; + + pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); + prlsdkCheckRetGoto(pret, error); + + pret = PrlVmDev_GetEmulatedType(hdd, &emulatedType); + prlsdkCheckRetGoto(pret, error); + + if (PDT_USE_REAL_DEVICE != emulatedType && IS_CT(def)) { + + if (VIR_ALLOC(fs) < 0) + goto error; + + if (prlsdkGetFSInfo(hdd, fs) < 0) + goto error; + + if (virDomainFSInsert(def, fs) < 0) + goto error; + + fs = NULL; + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + } else { + if (!(disk = virDomainDiskDefNew(NULL))) + goto error; + + if (prlsdkGetDiskInfo(hdd, disk, false, IS_CT(def)) < 0) + goto error; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + goto error; + + disk = NULL; + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + } + } + + return 0; + + error: + PrlHandle_Free(hdd); + virDomainDiskDefFree(disk); + virDomainFSDefFree(fs); + return -1; +} + +static int +prlsdkAddDomainOpticalDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_RESULT pret; + PRL_UINT32 cdromsCount; + PRL_UINT32 i; + PRL_HANDLE cdrom = PRL_INVALID_HANDLE; + virDomainDiskDefPtr disk = NULL; + + pret = PrlVmCfg_GetOpticalDisksCount(sdkdom, &cdromsCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < cdromsCount; ++i) { + pret = PrlVmCfg_GetOpticalDisk(sdkdom, i, &cdrom); + prlsdkCheckRetGoto(pret, error); + + if (!(disk = virDomainDiskDefNew(NULL))) + goto error; + + if (prlsdkGetDiskInfo(cdrom, disk, true, IS_CT(def)) < 0) + goto error; + + PrlHandle_Free(cdrom); + cdrom = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + goto error; + } + + return 0; + + error: + PrlHandle_Free(cdrom); + virDomainDiskDefFree(disk); + return -1; +} + +static int +prlsdkGetNetInfo(PRL_HANDLE netAdapter, virDomainNetDefPtr net, bool isCt) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + PRL_UINT32 buflen; + PRL_UINT32 netAdapterIndex; + PRL_UINT32 emulatedType; + PRL_RESULT pret; + PRL_BOOL isConnected; + int ret = -1; + + net->type = VIR_DOMAIN_NET_TYPE_NETWORK; + + + /* use device name, shown by prlctl as target device + * for identifying network adapter in virDomainDefineXML */ + pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(net->ifname, buflen) < 0) + goto cleanup; + + pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, net->ifname, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_GetIndex(netAdapter, &netAdapterIndex); + prlsdkCheckRetGoto(pret, cleanup); + + if (isCt && netAdapterIndex == (PRL_UINT32) -1) { + /* venet devices don't have mac address and + * always up */ + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (VIR_STRDUP(net->data.network.name, + PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) + goto cleanup; + return 0; + } + + buflen = ARRAY_CARDINALITY(macstr); + if (VIR_ALLOC_N(macstr, buflen)) + goto cleanup; + pret = PrlVmDevNet_GetMacAddressCanonical(netAdapter, macstr, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (virMacAddrParse(macstr, &net->mac) < 0) + goto cleanup; + + pret = PrlVmDev_GetEmulatedType(netAdapter, &emulatedType); + prlsdkCheckRetGoto(pret, cleanup); + + if (emulatedType == PNA_ROUTED) { + if (VIR_STRDUP(net->data.network.name, + PARALLELS_DOMAIN_ROUTED_NETWORK_NAME) < 0) + goto cleanup; + } else { + pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(net->data.network.name, buflen) < 0) + goto cleanup; + + pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, + net->data.network.name, + &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + /* + * We use VIR_DOMAIN_NET_TYPE_NETWORK for all network adapters + * except those whose Virtual Network Id differ from Parallels + * predefined ones such as PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME + * and PARALLELS_DONAIN_ROUTED_NETWORK_NAME + */ + if (STRNEQ(net->data.network.name, PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME)) + net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + + } + + if (!isCt) { + PRL_VM_NET_ADAPTER_TYPE type; + pret = PrlVmDevNet_GetAdapterType(netAdapter, &type); + prlsdkCheckRetGoto(pret, cleanup); + + switch (type) { + case PNT_RTL: + if (VIR_STRDUP(net->model, "rtl8139") < 0) + goto cleanup; + break; + case PNT_E1000: + if (VIR_STRDUP(net->model, "e1000") < 0) + goto cleanup; + break; + case PNT_VIRTIO: + if (VIR_STRDUP(net->model, "virtio") < 0) + goto cleanup; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown adapter type: %X"), type); + goto cleanup; + } + } + + pret = PrlVmDev_IsConnected(netAdapter, &isConnected); + prlsdkCheckRetGoto(pret, cleanup); + + if (isConnected) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + + ret = 0; + cleanup: + return ret; +} + +static int +prlsdkAddDomainNetInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainNetDefPtr net = NULL; + PRL_RESULT ret; + PRL_HANDLE netAdapter; + PRL_UINT32 netAdaptersCount; + PRL_UINT32 i; + + ret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &netAdaptersCount); + prlsdkCheckRetGoto(ret, error); + for (i = 0; i < netAdaptersCount; ++i) { + ret = PrlVmCfg_GetNetAdapter(sdkdom, i, &netAdapter); + prlsdkCheckRetGoto(ret, error); + + if (VIR_ALLOC(net) < 0) + goto error; + + if (prlsdkGetNetInfo(netAdapter, net, IS_CT(def)) < 0) + goto error; + + PrlHandle_Free(netAdapter); + netAdapter = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0) + goto error; + } + + return 0; + + error: + PrlHandle_Free(netAdapter); + virDomainNetDefFree(net); + return -1; +} + +static int +prlsdkGetSerialInfo(PRL_HANDLE serialPort, virDomainChrDefPtr chr) +{ + PRL_RESULT pret; + PRL_UINT32 serialPortIndex; + PRL_UINT32 emulatedType; + char *friendlyName = NULL; + PRL_UINT32 buflen; + + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->targetTypeAttr = false; + pret = PrlVmDev_GetIndex(serialPort, &serialPortIndex); + prlsdkCheckRetGoto(pret, error); + chr->target.port = serialPortIndex; + + pret = PrlVmDev_GetEmulatedType(serialPort, &emulatedType); + prlsdkCheckRetGoto(pret, error); + + pret = PrlVmDev_GetFriendlyName(serialPort, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(friendlyName, buflen) < 0) + goto error; + + pret = PrlVmDev_GetFriendlyName(serialPort, friendlyName, &buflen); + prlsdkCheckRetGoto(pret, error); + + switch (emulatedType) { + case PDT_USE_OUTPUT_FILE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_FILE; + chr->source.data.file.path = friendlyName; + break; + case PDT_USE_SERIAL_PORT_SOCKET_MODE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_UNIX; + chr->source.data.nix.path = friendlyName; + break; + case PDT_USE_REAL_DEVICE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + chr->source.data.file.path = friendlyName; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown serial type: %X"), emulatedType); + goto error; + break; + } + + return 0; + error: + VIR_FREE(friendlyName); + return -1; +} + + +static int +prlsdkAddSerialInfo(PRL_HANDLE sdkdom, + virDomainChrDefPtr **serials, + size_t *nserials) +{ + PRL_RESULT ret; + PRL_HANDLE serialPort; + PRL_UINT32 serialPortsCount; + PRL_UINT32 i; + virDomainChrDefPtr chr = NULL; + + ret = PrlVmCfg_GetSerialPortsCount(sdkdom, &serialPortsCount); + prlsdkCheckRetGoto(ret, cleanup); + for (i = 0; i < serialPortsCount; ++i) { + ret = PrlVmCfg_GetSerialPort(sdkdom, i, &serialPort); + prlsdkCheckRetGoto(ret, cleanup); + + if (!(chr = virDomainChrDefNew())) + goto cleanup; + + if (prlsdkGetSerialInfo(serialPort, chr)) + goto cleanup; + + PrlHandle_Free(serialPort); + serialPort = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(*serials, *nserials, chr) < 0) + goto cleanup; + } + + return 0; + + cleanup: + PrlHandle_Free(serialPort); + virDomainChrDefFree(chr); + return -1; +} + + +static int +prlsdkAddDomainHardware(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + if (!IS_CT(def)) + if (prlsdkAddDomainVideoInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainHardDisksInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainOpticalDisksInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainNetInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddSerialInfo(sdkdom, + &def->serials, + &def->nserials) < 0) + goto error; + + return 0; + error: + return -1; +} + + +static int +prlsdkAddVNCInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr = NULL; + PRL_VM_REMOTE_DISPLAY_MODE vncMode; + PRL_UINT32 port; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + + pret = PrlVmCfg_GetVNCMode(sdkdom, &vncMode); + prlsdkCheckRetGoto(pret, error); + + if (vncMode == PRD_DISABLED) + return 0; + + if (VIR_ALLOC(gr) < 0) + goto error; + + pret = PrlVmCfg_GetVNCPort(sdkdom, &port); + prlsdkCheckRetGoto(pret, error); + + gr->data.vnc.autoport = (vncMode == PRD_AUTO); + gr->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; + gr->data.vnc.port = port; + gr->data.vnc.keymap = NULL; + gr->data.vnc.socket = NULL; + gr->data.vnc.auth.passwd = NULL; + gr->data.vnc.auth.expires = false; + gr->data.vnc.auth.connected = 0; + + if (VIR_ALLOC(gr->listens) < 0) + goto error; + + gr->nListens = 1; + + pret = PrlVmCfg_GetVNCHostName(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(gr->listens[0].address, buflen) < 0) + goto error; + + pret = PrlVmCfg_GetVNCHostName(sdkdom, gr->listens[0].address, &buflen); + prlsdkCheckRetGoto(pret, error); + + gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; + + if (VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr) < 0) + goto error; + + if (IS_CT(def)) { + virDomainVideoDefPtr video; + if (VIR_ALLOC(video) < 0) + goto error; + video->type = virDomainVideoDefaultType(def); + if (video->type < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot determine default video type")); + VIR_FREE(video); + goto error; + } + video->vram = virDomainVideoDefaultRAM(def, video->type); + video->heads = 1; + if (VIR_ALLOC_N(def->videos, 1) < 0) { + virDomainVideoDefFree(video); + goto error; + } + def->videos[def->nvideos++] = video; + } + return 0; + + error: + virDomainGraphicsDefFree(gr); + return -1; +} + +static int +prlsdkConvertDomainState(VIRTUAL_MACHINE_STATE domainState, + PRL_UINT32 envId, + virDomainObjPtr dom) +{ + switch (domainState) { + case VMS_STOPPED: + case VMS_MOUNTED: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, + VIR_DOMAIN_SHUTOFF_SHUTDOWN); + dom->def->id = -1; + break; + case VMS_STARTING: + case VMS_COMPACTING: + case VMS_RESETTING: + case VMS_PAUSING: + case VMS_RECONNECTING: + case VMS_RUNNING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_BOOTED); + dom->def->id = envId; + break; + case VMS_PAUSED: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_USER); + dom->def->id = envId; + break; + case VMS_SUSPENDED: + case VMS_DELETING_STATE: + case VMS_SUSPENDING_SYNC: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, + VIR_DOMAIN_SHUTOFF_SAVED); + dom->def->id = -1; + break; + case VMS_STOPPING: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTDOWN, + VIR_DOMAIN_SHUTDOWN_USER); + dom->def->id = envId; + break; + case VMS_SNAPSHOTING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_SNAPSHOT); + dom->def->id = envId; + break; + case VMS_MIGRATING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + dom->def->id = envId; + break; + case VMS_SUSPENDING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_SAVE); + dom->def->id = envId; + break; + case VMS_RESTORING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_RESTORED); + dom->def->id = envId; + break; + case VMS_CONTINUING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_UNPAUSED); + dom->def->id = envId; + break; + case VMS_RESUMING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_RESTORED); + dom->def->id = envId; + break; + case VMS_UNKNOWN: + virDomainObjSetState(dom, VIR_DOMAIN_NOSTATE, + VIR_DOMAIN_NOSTATE_UNKNOWN); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown domain state: %X"), domainState); + return -1; + break; + } + + return 0; +} + +static int +prlsdkConvertCpuInfo(PRL_HANDLE sdkdom, + virDomainDefPtr def) +{ + char *buf; + PRL_UINT32 buflen = 0; + int hostcpus; + PRL_UINT32 cpuCount; + PRL_RESULT pret; + int ret = -1; + + if ((hostcpus = nodeGetCPUCount()) < 0) + goto cleanup; + + /* get number of CPUs */ + pret = PrlVmCfg_GetCpuCount(sdkdom, &cpuCount); + prlsdkCheckRetGoto(pret, cleanup); + + if (cpuCount > hostcpus) + cpuCount = hostcpus; + + def->vcpus = cpuCount; + def->maxvcpus = cpuCount; + + pret = PrlVmCfg_GetCpuMask(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmCfg_GetCpuMask(sdkdom, buf, &buflen); + + if (strlen(buf) == 0) { + if (!(def->cpumask = virBitmapNew(hostcpus))) + goto cleanup; + virBitmapSetAll(def->cpumask); + } else { + if (virBitmapParse(buf, 0, &def->cpumask, hostcpus) < 0) + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(buf); + return ret; +} + +static int +prlsdkConvertDomainType(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_VM_TYPE domainType; + PRL_RESULT pret; + + pret = PrlVmCfg_GetVmType(sdkdom, &domainType); + prlsdkCheckRetGoto(pret, error); + + switch (domainType) { + case PVT_VM: + def->os.type = VIR_DOMAIN_OSTYPE_HVM; + break; + case PVT_CT: + def->os.type = VIR_DOMAIN_OSTYPE_EXE; + if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) + return -1; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown domain type: %X"), domainType); + return -1; + } + + return 0; + + error: + return -1; +} + +static int +prlsdkConvertCpuMode(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_RESULT pret; + PRL_CPU_MODE cpuMode; + + pret = PrlVmCfg_GetCpuMode(sdkdom, &cpuMode); + prlsdkCheckRetGoto(pret, error); + + switch (cpuMode) { + case PCM_CPU_MODE_32: + def->os.arch = VIR_ARCH_I686; + break; + case PCM_CPU_MODE_64: + def->os.arch = VIR_ARCH_X86_64; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU mode: %X"), cpuMode); + return -1; + } + + return 0; + error: + return -1; +} + +/* + * This function retrieves information about domain. + * If the domains is already in the domains list + * privconn->domains, then locked 'olddom' must be + * provided. If the domains must be added to the list, + * olddom must be NULL. + * + * The function return a pointer to a locked virDomainObj. + */ +static virDomainObjPtr +prlsdkLoadDomain(vzConnPtr privconn, + PRL_HANDLE sdkdom, + virDomainObjPtr olddom) +{ + virDomainObjPtr dom = NULL; + virDomainDefPtr def = NULL; + vzDomObjPtr pdom = NULL; + VIRTUAL_MACHINE_STATE domainState; + + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 ram; + PRL_UINT32 envId; + PRL_VM_AUTOSTART_OPTION autostart; + + virCheckNonNullArgGoto(privconn, error); + virCheckNonNullArgGoto(sdkdom, error); + + if (!(def = virDomainDefNew())) + goto error; + + if (!olddom) { + if (VIR_ALLOC(pdom) < 0) + goto error; + } else { + pdom = olddom->privateData; + } + + if (STREQ(privconn->drivername, "vz")) + def->virtType = VIR_DOMAIN_VIRT_VZ; + else + def->virtType = VIR_DOMAIN_VIRT_PARALLELS; + + def->id = -1; + + /* we will remove this field in the near future, so let's set it + * to NULL temporarily */ + pdom->uuid = NULL; + + pdom->cache.stats = PRL_INVALID_HANDLE; + pdom->cache.count = -1; + if (virCondInit(&pdom->cache.cond) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize condition")); + goto error; + } + + if (prlsdkGetDomainIds(sdkdom, &def->name, def->uuid) < 0) + goto error; + + def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; + def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; + def->onCrash = VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY; + + /* get RAM parameters */ + pret = PrlVmCfg_GetRamSize(sdkdom, &ram); + prlsdkCheckRetGoto(pret, error); + virDomainDefSetMemoryInitial(def, ram << 10); /* RAM size obtained in Mbytes, + convert to Kbytes */ + def->mem.cur_balloon = ram << 10; + + if (prlsdkConvertCpuInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkConvertCpuMode(sdkdom, def) < 0) + goto error; + + if (prlsdkConvertDomainType(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainHardware(sdkdom, def) < 0) + goto error; + + if (prlsdkAddVNCInfo(sdkdom, def) < 0) + goto error; + + pret = PrlVmCfg_GetEnvId(sdkdom, &envId); + prlsdkCheckRetGoto(pret, error); + pdom->id = envId; + + buflen = 0; + pret = PrlVmCfg_GetHomePath(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + VIR_FREE(pdom->home); + if (VIR_ALLOC_N(pdom->home, buflen) < 0) + goto error; + + pret = PrlVmCfg_GetHomePath(sdkdom, pdom->home, &buflen); + prlsdkCheckRetGoto(pret, error); + + /* For VMs pdom->home is actually /directory/config.pvs */ + if (!IS_CT(def)) { + /* Get rid of /config.pvs in path string */ + char *s = strrchr(pdom->home, '/'); + if (s) + *s = '\0'; + } + + pret = PrlVmCfg_GetAutoStart(sdkdom, &autostart); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkGetDomainState(sdkdom, &domainState) < 0) + goto error; + + if (virDomainDefAddImplicitControllers(def) < 0) + goto error; + + if (def->ngraphics > 0) { + int bus = IS_CT(def) ? VIR_DOMAIN_INPUT_BUS_PARALLELS: + VIR_DOMAIN_INPUT_BUS_PS2; + + if (virDomainDefMaybeAddInput(def, + VIR_DOMAIN_INPUT_TYPE_MOUSE, + bus) < 0) + goto error; + + if (virDomainDefMaybeAddInput(def, + VIR_DOMAIN_INPUT_TYPE_KBD, + bus) < 0) + goto error; + } + + if (olddom) { + /* assign new virDomainDef without any checks */ + /* we can't use virDomainObjAssignDef, because it checks + * for state and domain name */ + dom = olddom; + virDomainDefFree(dom->def); + dom->def = def; + } else { + if (!(dom = virDomainObjListAdd(privconn->domains, def, + privconn->xmlopt, + 0, NULL))) + goto error; + } + /* dom is locked here */ + + dom->privateData = pdom; + dom->privateDataFreeFunc = prlsdkDomObjFreePrivate; + dom->persistent = 1; + + switch (autostart) { + case PAO_VM_START_ON_LOAD: + dom->autostart = 1; + break; + case PAO_VM_START_MANUAL: + dom->autostart = 0; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown autostart mode: %X"), autostart); + goto error; + } + + if (prlsdkConvertDomainState(domainState, envId, dom) < 0) + goto error; + + if (!pdom->sdkdom) { + pret = PrlHandle_AddRef(sdkdom); + prlsdkCheckRetGoto(pret, error); + pdom->sdkdom = sdkdom; + } + + return dom; + error: + if (dom && !olddom) { + /* Domain isn't persistent means that we haven't yet set + * prlsdkDomObjFreePrivate and should call it manually + */ + if (!dom->persistent) + prlsdkDomObjFreePrivate(pdom); + + virDomainObjListRemove(privconn->domains, dom); + } + /* Delete newly allocated def only if we haven't assigned it to domain + * Otherwise we will end up with domain having invalid def within it + */ + if (!dom) + virDomainDefFree(def); + + return NULL; +} + +int +prlsdkLoadDomains(vzConnPtr privconn) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result; + PRL_HANDLE sdkdom; + PRL_UINT32 paramsCount; + PRL_RESULT pret; + size_t i = 0; + virDomainObjPtr dom; + + job = PrlSrv_GetVmListEx(privconn->server, PVTF_VM | PVTF_CT); + + if (PRL_FAILED(getJobResult(job, &result))) + return -1; + + pret = PrlResult_GetParamsCount(result, ¶msCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < paramsCount; i++) { + pret = PrlResult_GetParamByIndex(result, i, &sdkdom); + if (PRL_FAILED(pret)) { + logPrlError(pret); + PrlHandle_Free(sdkdom); + goto error; + } + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + + if (!dom) + goto error; + else + virObjectUnlock(dom); + } + + PrlHandle_Free(result); + return 0; + + error: + PrlHandle_Free(result); + return -1; +} + +virDomainObjPtr +prlsdkAddDomain(vzConnPtr privconn, const unsigned char *uuid) +{ + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + virDomainObjPtr dom; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom) { + /* domain is already in the list */ + return dom; + } + + sdkdom = prlsdkSdkDomainLookupByUUID(privconn, uuid); + if (sdkdom == PRL_INVALID_HANDLE) + return NULL; + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + return dom; +} + +int +prlsdkUpdateDomain(vzConnPtr privconn, virDomainObjPtr dom) +{ + PRL_HANDLE job; + virDomainObjPtr retdom = NULL; + vzDomObjPtr pdom = dom->privateData; + + job = PrlVm_RefreshConfig(pdom->sdkdom); + if (waitJob(job)) + return -1; + + retdom = prlsdkLoadDomain(privconn, pdom->sdkdom, dom); + return retdom ? 0 : -1; +} + +static int prlsdkSendEvent(vzConnPtr privconn, + virDomainObjPtr dom, + virDomainEventType lvEventType, + int lvEventTypeDetails) +{ + virObjectEventPtr event = NULL; + + event = virDomainEventLifecycleNewFromObj(dom, + lvEventType, + lvEventTypeDetails); + if (!event) + return -1; + + virObjectEventStateQueue(privconn->domainEventState, event); + return 0; +} + +static void +prlsdkNewStateToEvent(VIRTUAL_MACHINE_STATE domainState, + virDomainEventType *lvEventType, + int *lvEventTypeDetails) +{ + /* We skip all intermediate states here, because + * libvirt doesn't have correspoding event types for + * them */ + switch (domainState) { + case VMS_STOPPED: + case VMS_MOUNTED: + *lvEventType = VIR_DOMAIN_EVENT_STOPPED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN; + break; + case VMS_RUNNING: + *lvEventType = VIR_DOMAIN_EVENT_STARTED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STARTED_BOOTED; + break; + case VMS_PAUSED: + *lvEventType = VIR_DOMAIN_EVENT_SUSPENDED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED; + break; + case VMS_SUSPENDED: + *lvEventType = VIR_DOMAIN_EVENT_STOPPED; + *lvEventTypeDetails = VIR_DOMAIN_EVENT_STOPPED_SAVED; + break; + default: + VIR_DEBUG("Skip sending event about changing state to %X", + domainState); + break; + } +} + +static void +prlsdkHandleVmStateEvent(vzConnPtr privconn, + PRL_HANDLE prlEvent, + unsigned char *uuid) +{ + PRL_RESULT pret = PRL_ERR_FAILURE; + PRL_HANDLE eventParam = PRL_INVALID_HANDLE; + PRL_INT32 domainState; + virDomainObjPtr dom = NULL; + vzDomObjPtr pdom; + virDomainEventType lvEventType = 0; + int lvEventTypeDetails = 0; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) + return; + + pret = PrlEvent_GetParamByName(prlEvent, "vminfo_vm_state", &eventParam); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlEvtPrm_ToInt32(eventParam, &domainState); + prlsdkCheckRetGoto(pret, cleanup); + + pdom = dom->privateData; + if (prlsdkConvertDomainState(domainState, pdom->id, dom) < 0) + goto cleanup; + + prlsdkNewStateToEvent(domainState, + &lvEventType, + &lvEventTypeDetails); + + prlsdkSendEvent(privconn, dom, lvEventType, lvEventTypeDetails); + + cleanup: + virObjectUnlock(dom); + return; +} + +static void +prlsdkHandleVmConfigEvent(vzConnPtr privconn, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) + return; + + if (prlsdkUpdateDomain(privconn, dom) < 0) + goto cleanup; + + prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_UPDATED); + + cleanup: + virObjectUnlock(dom); + return; +} + +static void +prlsdkHandleVmAddedEvent(vzConnPtr privconn, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + + dom = prlsdkAddDomain(privconn, uuid); + if (dom == NULL) + return; + + prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_ADDED); + + virObjectUnlock(dom); + return; +} + +static void +prlsdkHandleVmRemovedEvent(vzConnPtr privconn, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + /* domain was removed from the list from the libvirt + * API function in current connection */ + if (dom == NULL) + return; + + prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED); + + virDomainObjListRemove(privconn->domains, dom); + return; +} + +#define PARALLELS_STATISTICS_DROP_COUNT 3 + +static PRL_RESULT +prlsdkHandlePerfEvent(vzConnPtr privconn, + PRL_HANDLE event, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + vzDomObjPtr privdom = NULL; + PRL_HANDLE job = PRL_INVALID_HANDLE; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) + goto cleanup; + privdom = dom->privateData; + + // delayed event after unsubscribe + if (privdom->cache.count == -1) + goto cleanup; + + PrlHandle_Free(privdom->cache.stats); + privdom->cache.stats = PRL_INVALID_HANDLE; + + if (privdom->cache.count > PARALLELS_STATISTICS_DROP_COUNT) { + job = PrlVm_UnsubscribeFromPerfStats(privdom->sdkdom); + if (PRL_FAILED(waitJob(job))) + goto cleanup; + // change state to unsubscribed + privdom->cache.count = -1; + } else { + ++privdom->cache.count; + privdom->cache.stats = event; + // thus we get own of event handle + event = PRL_INVALID_HANDLE; + virCondSignal(&privdom->cache.cond); + } + + cleanup: + PrlHandle_Free(event); + if (dom) + virObjectUnlock(dom); + + return PRL_ERR_SUCCESS; +} + +static void +prlsdkHandleVmEvent(vzConnPtr privconn, PRL_HANDLE prlEvent) +{ + PRL_RESULT pret = PRL_ERR_FAILURE; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + unsigned char uuid[VIR_UUID_BUFLEN]; + PRL_UINT32 bufsize = ARRAY_CARDINALITY(uuidstr); + PRL_EVENT_TYPE prlEventType; + + pret = PrlEvent_GetType(prlEvent, &prlEventType); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlEvent_GetIssuerId(prlEvent, uuidstr, &bufsize); + prlsdkCheckRetGoto(pret, cleanup); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + goto cleanup; + + switch (prlEventType) { + case PET_DSP_EVT_VM_STATE_CHANGED: + prlsdkHandleVmStateEvent(privconn, prlEvent, uuid); + break; + case PET_DSP_EVT_VM_CONFIG_CHANGED: + prlsdkHandleVmConfigEvent(privconn, uuid); + break; + case PET_DSP_EVT_VM_CREATED: + case PET_DSP_EVT_VM_ADDED: + prlsdkHandleVmAddedEvent(privconn, uuid); + break; + case PET_DSP_EVT_VM_DELETED: + case PET_DSP_EVT_VM_UNREGISTERED: + prlsdkHandleVmRemovedEvent(privconn, uuid); + break; + case PET_DSP_EVT_VM_PERFSTATS: + prlsdkHandlePerfEvent(privconn, prlEvent, uuid); + // above function takes own of event + prlEvent = PRL_INVALID_HANDLE; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't handle event of type %d"), prlEventType); + } + + cleanup: + PrlHandle_Free(prlEvent); + return; +} + +static PRL_RESULT +prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) +{ + vzConnPtr privconn = opaque; + PRL_RESULT pret = PRL_ERR_FAILURE; + PRL_HANDLE_TYPE handleType; + PRL_EVENT_ISSUER_TYPE prlIssuerType = PIE_UNKNOWN; + + pret = PrlHandle_GetType(prlEvent, &handleType); + prlsdkCheckRetGoto(pret, cleanup); + + /* Currently, there is no need to handle anything but events */ + if (handleType != PHT_EVENT) + goto cleanup; + + if (privconn == NULL) + goto cleanup; + + PrlEvent_GetIssuerType(prlEvent, &prlIssuerType); + prlsdkCheckRetGoto(pret, cleanup); + + switch (prlIssuerType) { + case PIE_VIRTUAL_MACHINE: + prlsdkHandleVmEvent(privconn, prlEvent); + // above function takes own of event + prlEvent = PRL_INVALID_HANDLE; + break; + default: + VIR_DEBUG("Skipping event of issuer type %d", prlIssuerType); + } + + cleanup: + PrlHandle_Free(prlEvent); + return PRL_ERR_SUCCESS; +} + + +int prlsdkSubscribeToPCSEvents(vzConnPtr privconn) +{ + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + + pret = PrlSrv_RegEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + prlsdkCheckRetGoto(pret, error); + return 0; + + error: + return -1; +} + +void prlsdkUnsubscribeFromPCSEvents(vzConnPtr privconn) +{ + PRL_RESULT ret = PRL_ERR_UNINITIALIZED; + ret = PrlSrv_UnregEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + if (PRL_FAILED(ret)) + logPrlError(ret); +} + +PRL_RESULT prlsdkStart(PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_StartEx(sdkdom, PSM_VM_START, 0); + return waitJob(job); +} + +static PRL_RESULT prlsdkStopEx(PRL_HANDLE sdkdom, PRL_UINT32 mode) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_StopEx(sdkdom, mode, 0); + return waitJob(job); +} + +PRL_RESULT prlsdkKill(PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(sdkdom, PSM_KILL); +} + +PRL_RESULT prlsdkStop(PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(sdkdom, PSM_SHUTDOWN); +} + +PRL_RESULT prlsdkPause(PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Pause(sdkdom, false); + return waitJob(job); +} + +PRL_RESULT prlsdkResume(PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Resume(sdkdom); + return waitJob(job); +} + +PRL_RESULT prlsdkSuspend(PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Suspend(sdkdom); + return waitJob(job); +} + +int +prlsdkDomainChangeStateLocked(vzConnPtr privconn, + virDomainObjPtr dom, + prlsdkChangeStateFunc chstate) +{ + vzDomObjPtr pdom; + PRL_RESULT pret; + virErrorNumber virerr; + + pdom = dom->privateData; + pret = chstate(pdom->sdkdom); + if (PRL_FAILED(pret)) { + virResetLastError(); + + switch (pret) { + case PRL_ERR_DISP_VM_IS_NOT_STARTED: + case PRL_ERR_DISP_VM_IS_NOT_STOPPED: + virerr = VIR_ERR_OPERATION_INVALID; + break; + default: + virerr = VIR_ERR_OPERATION_FAILED; + } + + virReportError(virerr, "%s", _("Can't change domain state.")); + return -1; + } + + return prlsdkUpdateDomain(privconn, dom); +} + +int +prlsdkDomainChangeState(virDomainPtr domain, + prlsdkChangeStateFunc chstate) +{ + vzConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom; + int ret = -1; + + if (!(dom = vzDomObjFromDomain(domain))) + return -1; + + ret = prlsdkDomainChangeStateLocked(privconn, dom, chstate); + virObjectUnlock(dom); + return ret; +} + +static int +prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + size_t i; + PRL_VM_TYPE vmType; + PRL_RESULT pret; + virDomainNumatuneMemMode memMode; + + if (def->title) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("titles are not supported by vz driver")); + return -1; + } + + if (def->blkio.ndevices > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("blkio parameters are not supported " + "by vz driver")); + return -1; + } + + if (virDomainDefGetMemoryActual(def) != def->mem.cur_balloon) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing balloon parameters is not supported " + "by vz driver")); + return -1; + } + + if (virDomainDefGetMemoryActual(def) % (1 << 10) != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Memory size should be multiple of 1Mb.")); + return -1; + } + + if (def->mem.nhugepages || + virMemoryLimitIsSet(def->mem.hard_limit) || + virMemoryLimitIsSet(def->mem.soft_limit) || + def->mem.min_guarantee || + virMemoryLimitIsSet(def->mem.swap_hard_limit)) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Memory parameter is not supported " + "by vz driver")); + return -1; + } + + if (def->vcpus != def->maxvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("current vcpus must be equal to maxvcpus")); + return -1; + } + + if (def->placement_mode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing cpu placement mode is not supported " + "by vz driver")); + return -1; + } + + if (def->cputune.shares || + def->cputune.sharesSpecified || + def->cputune.period || + def->cputune.quota) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cputune is not supported by vz driver")); + return -1; + } + + if (def->cputune.vcpupin) { + for (i = 0; i < def->vcpus; i++) { + if (!virBitmapEqual(def->cpumask, + def->cputune.vcpupin[i]->cpumask)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("vcpupin cpumask differs from default cpumask")); + return -1; + } + } + } + + + /* + * Though we don't support NUMA configuration at the moment + * virDomainDefPtr always contain non zero NUMA configuration + * So, just make sure this configuration does't differ from auto generated. + */ + if ((virDomainNumatuneGetMode(def->numa, -1, &memMode) == 0 && + memMode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) || + virDomainNumatuneHasPerNodeBinding(def->numa)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("numa parameters are not supported " + "by vz driver")); + return -1; + } + + if (def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART || + def->onPoweroff != VIR_DOMAIN_LIFECYCLE_DESTROY || + def->onCrash != VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("on_reboot, on_poweroff and on_crash parameters " + "are not supported by vz driver")); + return -1; + } + + /* we fill only type and arch fields in vzLoadDomain for + * hvm type and also init for containers, so we can check that all + * other paramenters are null and boot devices config is default */ + + if (def->os.machine != NULL || def->os.bootmenu != 0 || + def->os.kernel != NULL || def->os.initrd != NULL || + def->os.cmdline != NULL || def->os.root != NULL || + def->os.loader != NULL || def->os.bootloader != NULL || + def->os.bootloaderArgs != NULL || def->os.smbios_mode != 0 || + def->os.bios.useserial != 0) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing OS parameters is not supported " + "by vz driver")); + return -1; + } + + pret = PrlVmCfg_GetVmType(sdkdom, &vmType); + if (PRL_FAILED(pret)) { + logPrlError(pret); + return -1; + } + + if (!(vmType == PVT_VM && !IS_CT(def)) && + !(vmType == PVT_CT && IS_CT(def))) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing OS type is not supported " + "by vz driver")); + return -1; + } + + if (!IS_CT(def)) { + if (def->os.nBootDevs != 1 || + def->os.bootDevs[0] != VIR_DOMAIN_BOOT_DISK || + def->os.init != NULL || def->os.initargv != NULL) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing OS parameters is not supported " + "by vz driver")); + return -1; + } + } else { + if (def->os.nBootDevs != 0 || + !STREQ_NULLABLE(def->os.init, "/sbin/init") || + (def->os.initargv != NULL && def->os.initargv[0] != NULL)) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing OS parameters is not supported " + "by vz driver")); + return -1; + } + } + + if (def->emulator) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing emulator is not supported " + "by vz driver")); + return -1; + } + + for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) { + if (def->features[i]) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing features is not supported " + "by vz driver")); + return -1; + } + } + + if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC || + def->clock.ntimers != 0) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing clock parameters is not supported " + "by vz driver")); + return -1; + } + + if (!IS_CT(def) && def->nfss != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Filesystems in VMs are not supported " + "by vz driver")); + return -1; + } + + if (def->nsounds != 0 || def->nhostdevs != 0 || + def->nredirdevs != 0 || def->nsmartcards != 0 || + def->nparallels || def->nchannels != 0 || + def->nleases != 0 || def->nhubs != 0) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing devices parameters is not supported " + "by vz driver")); + return -1; + } + + /* there may be one auto-input */ + if (def->ninputs != 0 && + (def->ninputs != 2 && + def->inputs[0]->type != VIR_DOMAIN_INPUT_TYPE_MOUSE && + def->inputs[0]->bus != VIR_DOMAIN_INPUT_BUS_PS2 && + def->inputs[1]->type != VIR_DOMAIN_INPUT_TYPE_KBD && + def->inputs[1]->bus != VIR_DOMAIN_INPUT_BUS_PS2)) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing input devices parameters is not supported " + "by vz driver")); + return -1; + } + + return 0; +} + +static int prlsdkClearDevices(PRL_HANDLE sdkdom) +{ + PRL_RESULT pret; + PRL_UINT32 n, i; + PRL_HANDLE devList; + PRL_HANDLE dev; + int ret = -1; + + pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_DISABLED); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmCfg_GetAllDevices(sdkdom, &devList); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlHndlList_GetItemsCount(devList, &n); + prlsdkCheckRetGoto(pret, cleanup); + + for (i = 0; i < n; i++) { + pret = PrlHndlList_GetItem(devList, i, &dev); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_Remove(dev); + PrlHandle_Free(dev); + } + + ret = 0; + cleanup: + PrlHandle_Free(devList); + return ret; +} + +static int +prlsdkRemoveBootDevices(PRL_HANDLE sdkdom) +{ + PRL_RESULT pret; + PRL_UINT32 i, devCount; + PRL_HANDLE dev = PRL_INVALID_HANDLE; + PRL_DEVICE_TYPE devType; + + pret = PrlVmCfg_GetBootDevCount(sdkdom, &devCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < devCount; i++) { + + /* always get device by index 0, because device list resort after delete */ + pret = PrlVmCfg_GetBootDev(sdkdom, 0, &dev); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_GetType(dev, &devType); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_Remove(dev); + prlsdkCheckRetGoto(pret, error); + } + + return 0; + + error: + return -1; +} + +static int +prlsdkAddDeviceToBootList(PRL_HANDLE sdkdom, + PRL_UINT32 devIndex, + PRL_DEVICE_TYPE devType, + PRL_UINT32 bootSequence) +{ + PRL_RESULT pret; + PRL_HANDLE bootDev = PRL_INVALID_HANDLE; + + pret = PrlVmCfg_CreateBootDev(sdkdom, &bootDev); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_SetIndex(bootDev, devIndex); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_SetType(bootDev, devType); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_SetSequenceIndex(bootDev, bootSequence); + prlsdkCheckRetGoto(pret, error); + + pret = PrlBootDev_SetInUse(bootDev, PRL_TRUE); + prlsdkCheckRetGoto(pret, error); + + return 0; + + error: + if (bootDev != PRL_INVALID_HANDLE) + PrlBootDev_Remove(bootDev); + + return -1; +} + +static int prlsdkCheckGraphicsUnsupportedParams(virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr; + + if (def->ngraphics == 0) + return 0; + + if (def->ngraphics > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver supports only " + "one VNC per domain.")); + return -1; + } + + gr = def->graphics[0]; + + if (gr->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver supports only " + "VNC graphics.")); + return -1; + } + + if (gr->data.vnc.websocket != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "websockets for VNC graphics.")); + return -1; + } + + if (gr->data.vnc.keymap != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "keymap setting for VNC graphics.")); + return -1; + } + + if (gr->data.vnc.sharePolicy == VIR_DOMAIN_GRAPHICS_VNC_SHARE_ALLOW_EXCLUSIVE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "exclusive share policy for VNC graphics.")); + return -1; + } + + if (gr->data.vnc.socket) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "VNC graphics over unix sockets.")); + return -1; + } + + if (gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL || + gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "given action in case of password change.")); + return -1; + } + + if (gr->data.vnc.auth.expires) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "setting password expire time.")); + return -1; + } + + if (gr->nListens > 1) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("vz driver doesn't support more than " + "one listening VNC server per domain")); + return -1; + } + + if (gr->nListens == 1 && + virDomainGraphicsListenGetType(gr, 0) != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("vz driver supports only address-based VNC listening")); + return -1; + } + + return 0; +} + +static int prlsdkCheckVideoUnsupportedParams(virDomainDefPtr def) +{ + virDomainVideoDefPtr v; + + if (IS_CT(def)) { + if (def->nvideos == 0) { + return 0; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Video adapters are not supported " + "int containers.")); + return -1; + } + } else { + if (def->nvideos != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver supports " + "only one video adapter.")); + return -1; + } + } + + v = def->videos[0]; + + if (v->type != VIR_DOMAIN_VIDEO_TYPE_VGA) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver supports " + "only VGA video adapters.")); + return -1; + } + + if (v->heads != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "multihead video adapters.")); + return -1; + } + + if (v->accel != NULL && (v->accel->support2d || v->accel->support3d)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "setting video acceleration parameters.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckSerialUnsupportedParams(virDomainChrDefPtr chr) +{ + if (chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified character device type is not supported " + "by vz driver.")); + return -1; + } + + if (chr->targetTypeAttr) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified character device target type is not " + "supported by vz driver.")); + return -1; + } + + if (chr->source.type != VIR_DOMAIN_CHR_TYPE_DEV && + chr->source.type != VIR_DOMAIN_CHR_TYPE_FILE && + chr->source.type != VIR_DOMAIN_CHR_TYPE_UNIX) { + + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified character device source type is not " + "supported by vz driver.")); + return -1; + } + + if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting device info for character devices is not " + "supported by vz driver.")); + return -1; + } + + if (chr->nseclabels > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting security labels is not " + "supported by vz driver.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckNetUnsupportedParams(virDomainNetDefPtr net) +{ + if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK && + net->type != VIR_DOMAIN_NET_TYPE_BRIDGE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified network adapter type is not " + "supported by vz driver.")); + return -1; + } + + if (net->backend.tap || net->backend.vhost) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Interface backend parameters are not " + "supported by vz driver.")); + return -1; + } + + if (net->data.network.portgroup) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Virtual network portgroups are not " + "supported by vz driver.")); + return -1; + } + + if (net->tune.sndbuf_specified) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting interface sndbuf is not " + "supported by vz driver.")); + return -1; + } + + if (net->script) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting interface script is not " + "supported by vz driver.")); + return -1; + } + + if (net->ifname_guest) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting guest interface name is not " + "supported by vz driver.")); + return -1; + } + + if (net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting device info for network devices is not " + "supported by vz driver.")); + return -1; + } + + if (net->filter) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting network filter is not " + "supported by vz driver.")); + return -1; + } + + if (net->bandwidth) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting network bandwidth is not " + "supported by vz driver.")); + return -1; + } + + if (net->vlan.trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up vlans is not " + "supported by vz driver.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckDiskUnsupportedParams(virDomainDiskDefPtr disk) +{ + if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK && + disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only hard disks and cdroms are supported " + "by vz driver.")); + return -1; + } + + if (disk->blockio.logical_block_size || + disk->blockio.physical_block_size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk block sizes is not " + "supported by vz driver.")); + return -1; + } + + if (disk->blkdeviotune.total_bytes_sec || + disk->blkdeviotune.read_bytes_sec || + disk->blkdeviotune.write_bytes_sec || + disk->blkdeviotune.total_iops_sec || + disk->blkdeviotune.read_iops_sec || + disk->blkdeviotune.write_iops_sec) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk io limits is not " + "supported by vz driver yet.")); + return -1; + } + + if (disk->serial) { + VIR_INFO("%s", _("Setting disk serial number is not " + "supported by vz driver.")); + } + + if (disk->wwn) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk wwn id is not " + "supported by vz driver.")); + return -1; + } + + if (disk->vendor) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk vendor is not " + "supported by vz driver.")); + return -1; + } + + if (disk->product) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk product id is not " + "supported by vz driver.")); + return -1; + } + + if (disk->error_policy != VIR_DOMAIN_DISK_ERROR_POLICY_DEFAULT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk error policy is not " + "supported by vz driver.")); + return -1; + } + + if (disk->iomode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk io mode is not " + "supported by vz driver.")); + return -1; + } + + if (disk->copy_on_read) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Disk copy_on_read is not " + "supported by vz driver.")); + return -1; + } + + if (disk->startupPolicy != VIR_DOMAIN_STARTUP_POLICY_DEFAULT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up disk startup policy is not " + "supported by vz driver.")); + return -1; + } + + if (disk->transient) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Transient disks are not " + "supported by vz driver.")); + return -1; + } + + if (disk->discard) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up disk discard parameter is not " + "supported by vz driver.")); + return -1; + } + + if (disk->iothread) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up disk io thread # is not " + "supported by vz driver.")); + return -1; + } + + if (disk->src->type != VIR_STORAGE_TYPE_FILE && + disk->src->type != VIR_STORAGE_TYPE_BLOCK) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only disk and block storage types are " + "supported by vz driver.")); + return -1; + + } + + return 0; +} + +static int prlsdkCheckFSUnsupportedParams(virDomainFSDefPtr fs) +{ + if (fs->type != VIR_DOMAIN_FS_TYPE_FILE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only file based filesystems are " + "supported by vz driver.")); + return -1; + } + + if (fs->fsdriver != VIR_DOMAIN_FS_DRIVER_TYPE_PLOOP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only ploop fs driver is " + "supported by vz driver.")); + return -1; + } + + if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Changing fs access mode is not " + "supported by vz driver.")); + return -1; + } + + if (fs->wrpolicy != VIR_DOMAIN_FS_WRPOLICY_DEFAULT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Changing fs write policy is not " + "supported by vz driver.")); + return -1; + } + + if (fs->format != VIR_STORAGE_FILE_PLOOP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only ploop disk images are " + "supported by vz driver.")); + return -1; + } + + if (fs->readonly) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting readonly for filesystems is " + "supported by vz driver.")); + return -1; + } + + if (fs->space_hard_limit || fs->space_soft_limit) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting fs quotas is not " + "supported by vz driver.")); + return -1; + } + + return 0; +} + +static int prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr; + PRL_RESULT pret; + int ret = -1; + const char *listenAddr = NULL; + + if (prlsdkCheckGraphicsUnsupportedParams(def)) + return -1; + + if (def->ngraphics == 0) + return 0; + + gr = def->graphics[0]; + + if (gr->data.vnc.autoport) { + pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_AUTO); + prlsdkCheckRetGoto(pret, cleanup); + } else { + pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_MANUAL); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmCfg_SetVNCPort(sdkdom, gr->data.vnc.port); + prlsdkCheckRetGoto(pret, cleanup); + } + + if (gr->nListens == 1) { + listenAddr = virDomainGraphicsListenGetAddress(gr, 0); + if (!listenAddr) + goto cleanup; + pret = PrlVmCfg_SetVNCHostName(sdkdom, listenAddr); + prlsdkCheckRetGoto(pret, cleanup); + } + + ret = 0; + cleanup: + return ret; +} + +static int prlsdkApplyVideoParams(PRL_HANDLE sdkdom ATTRIBUTE_UNUSED, virDomainDefPtr def) +{ + PRL_RESULT pret; + + if (def->nvideos == 0) + return 0; + + if (IS_CT(def)) { + /* ignore video parameters */ + return 0; + } + + if (prlsdkCheckVideoUnsupportedParams(def)) + return -1; + + pret = PrlVmCfg_SetVideoRamSize(sdkdom, def->videos[0]->vram >> 10); + prlsdkCheckRetGoto(pret, error); + + return 0; + error: + return -1; +} + +static int prlsdkAddSerial(PRL_HANDLE sdkdom, virDomainChrDefPtr chr) +{ + PRL_RESULT pret; + PRL_HANDLE sdkchr = PRL_INVALID_HANDLE; + PRL_VM_DEV_EMULATION_TYPE emutype; + PRL_SERIAL_PORT_SOCKET_OPERATION_MODE socket_mode = + PSP_SERIAL_SOCKET_SERVER; + char *path; + int ret = -1; + + if (prlsdkCheckSerialUnsupportedParams(chr) < 0) + return -1; + + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_SERIAL_PORT, &sdkchr); + prlsdkCheckRetGoto(pret, cleanup); + + switch (chr->source.type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + emutype = PDT_USE_REAL_DEVICE; + path = chr->source.data.file.path; + break; + case VIR_DOMAIN_CHR_TYPE_FILE: + emutype = PDT_USE_OUTPUT_FILE; + path = chr->source.data.file.path; + break; + case VIR_DOMAIN_CHR_TYPE_UNIX: + emutype = PDT_USE_SERIAL_PORT_SOCKET_MODE; + path = chr->source.data.nix.path; + if (chr->source.data.nix.listen) + socket_mode = PSP_SERIAL_SOCKET_SERVER; + else + socket_mode = PSP_SERIAL_SOCKET_CLIENT; + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vz driver doesn't support " + "specified serial source type.")); + goto cleanup; + } + + pret = PrlVmDev_SetEmulatedType(sdkchr, emutype); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetSysName(sdkchr, path); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetFriendlyName(sdkchr, path); + prlsdkCheckRetGoto(pret, cleanup); + + if (chr->source.type == VIR_DOMAIN_CHR_TYPE_UNIX) { + pret = PrlVmDevSerial_SetSocketMode(sdkchr, socket_mode); + prlsdkCheckRetGoto(pret, cleanup); + } + + pret = PrlVmDev_SetEnabled(sdkchr, 1); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetIndex(sdkchr, chr->target.port); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + cleanup: + PrlHandle_Free(sdkchr); + return ret; +} + +#define PRL_MAC_STRING_BUFNAME 13 + +static const char * prlsdkFormatMac(virMacAddrPtr mac, char *macstr) +{ + snprintf(macstr, PRL_MAC_STRING_BUFNAME, + "%02X%02X%02X%02X%02X%02X", + mac->addr[0], mac->addr[1], mac->addr[2], + mac->addr[3], mac->addr[4], mac->addr[5]); + macstr[PRL_MAC_STRING_BUFNAME - 1] = '\0'; + return macstr; +} + +static int prlsdkAddNet(PRL_HANDLE sdkdom, + vzConnPtr privconn, + virDomainNetDefPtr net, + bool isCt) +{ + PRL_RESULT pret; + PRL_HANDLE sdknet = PRL_INVALID_HANDLE; + PRL_HANDLE vnet = PRL_INVALID_HANDLE; + PRL_HANDLE job = PRL_INVALID_HANDLE; + int ret = -1; + char macstr[PRL_MAC_STRING_BUFNAME]; + + if (prlsdkCheckNetUnsupportedParams(net) < 0) + return -1; + + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_GENERIC_NETWORK_ADAPTER, &sdknet); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetEnabled(sdknet, 1); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetConnected(sdknet, net->linkstate != + VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN); + + prlsdkCheckRetGoto(pret, cleanup); + + if (net->ifname) { + pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname); + prlsdkCheckRetGoto(pret, cleanup); + } + + prlsdkFormatMac(&net->mac, macstr); + pret = PrlVmDevNet_SetMacAddress(sdknet, macstr); + prlsdkCheckRetGoto(pret, cleanup); + + if (isCt) { + if (net->model) + VIR_WARN("Setting network adapter for containers is not " + "supported by vz driver."); + } else { + if (STREQ(net->model, "rtl8139")) { + pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_RTL); + } else if (STREQ(net->model, "e1000")) { + pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_E1000); + } else if (STREQ(net->model, "virtio")) { + pret = PrlVmDevNet_SetAdapterType(sdknet, PNT_VIRTIO); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified network adapter model is not " + "supported by vz driver.")); + goto cleanup; + } + prlsdkCheckRetGoto(pret, cleanup); + } + + if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { + if (STREQ(net->data.network.name, PARALLELS_DOMAIN_ROUTED_NETWORK_NAME)) { + pret = PrlVmDev_SetEmulatedType(sdknet, PNA_ROUTED); + prlsdkCheckRetGoto(pret, cleanup); + } else if (STREQ(net->data.network.name, PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME)) { + pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGED_ETHERNET); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name); + prlsdkCheckRetGoto(pret, cleanup); + } + } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + /* + * For this type of adapter we create a new + * Virtual Network assuming that bridge with given name exists + * Failing creating this means domain creation failure + */ + pret = PrlVirtNet_Create(&vnet); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVirtNet_SetNetworkId(vnet, net->data.network.name); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVirtNet_SetNetworkType(vnet, PVN_BRIDGED_ETHERNET); + prlsdkCheckRetGoto(pret, cleanup); + + job = PrlSrv_AddVirtualNetwork(privconn->server, vnet, 0); + if (PRL_FAILED(pret = waitJob(job))) + goto cleanup; + + pret = PrlVmDev_SetEmulatedType(sdknet, PNA_BRIDGED_ETHERNET); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name); + prlsdkCheckRetGoto(pret, cleanup); + } + + if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_YES) + pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 0); + else if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_NO) + pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 1); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + cleanup: + PrlHandle_Free(vnet); + PrlHandle_Free(sdknet); + return ret; +} + +static void prlsdkDelNet(vzConnPtr privconn, virDomainNetDefPtr net) +{ + PRL_RESULT pret; + PRL_HANDLE vnet = PRL_INVALID_HANDLE; + PRL_HANDLE job = PRL_INVALID_HANDLE; + + if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE) + return; + + pret = PrlVirtNet_Create(&vnet); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVirtNet_SetNetworkId(vnet, net->data.network.name); + prlsdkCheckRetGoto(pret, cleanup); + + PrlSrv_DeleteVirtualNetwork(privconn->server, vnet, 0); + if (PRL_FAILED(pret = waitJob(job))) + goto cleanup; + + cleanup: + PrlHandle_Free(vnet); +} + +static int prlsdkDelDisk(PRL_HANDLE sdkdom, int idx) +{ + int ret = -1; + PRL_RESULT pret; + PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; + + pret = PrlVmCfg_GetHardDisk(sdkdom, idx, &sdkdisk); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_Remove(sdkdisk); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(sdkdisk); + return ret; +} + +static int prlsdkAddDisk(PRL_HANDLE sdkdom, + virDomainDiskDefPtr disk, + bool bootDisk, + bool isCt) +{ + PRL_RESULT pret; + PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; + int ret = -1; + PRL_VM_DEV_EMULATION_TYPE emutype; + PRL_MASS_STORAGE_INTERFACE_TYPE sdkbus; + int idx; + virDomainDeviceDriveAddressPtr drive; + PRL_UINT32 devIndex; + PRL_DEVICE_TYPE devType; + char *dst = NULL; + + if (prlsdkCheckDiskUnsupportedParams(disk) < 0) + return -1; + + if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) + devType = PDE_HARD_DISK; + else + devType = PDE_OPTICAL_DISK; + + pret = PrlVmCfg_CreateVmDev(sdkdom, devType, &sdkdisk); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetEnabled(sdkdisk, 1); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetConnected(sdkdisk, 1); + prlsdkCheckRetGoto(pret, cleanup); + + if (disk->src->type == VIR_STORAGE_TYPE_FILE) { + if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && + virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid format of " + "disk %s, vz driver supports only " + "images in ploop format."), disk->src->path); + goto cleanup; + } + + emutype = PDT_USE_IMAGE_FILE; + } else { + if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && + (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_RAW && + virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_NONE && + virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_AUTO)) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid format " + "of disk %s, it should be either not set, or set " + "to raw or auto."), disk->src->path); + goto cleanup; + } + emutype = PDT_USE_REAL_DEVICE; + } + + pret = PrlVmDev_SetEmulatedType(sdkdisk, emutype); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetSysName(sdkdisk, disk->src->path); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetFriendlyName(sdkdisk, disk->src->path); + prlsdkCheckRetGoto(pret, cleanup); + + drive = &disk->info.addr.drive; + if (drive->controller > 0) { + /* We have only one controller of each type */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only one controller."), disk->dst); + goto cleanup; + } + + if (drive->target > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only target 0."), disk->dst); + goto cleanup; + } + + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_IDE: + if (drive->unit > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only units 0-1 for IDE bus."), disk->dst); + goto cleanup; + } + sdkbus = PMS_IDE_DEVICE; + idx = 2 * drive->bus + drive->unit; + dst = virIndexToDiskName(idx, "hd"); + break; + case VIR_DOMAIN_DISK_BUS_SCSI: + if (drive->bus > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only bus 0 for SCSI bus."), disk->dst); + goto cleanup; + } + sdkbus = PMS_SCSI_DEVICE; + idx = drive->unit; + dst = virIndexToDiskName(idx, "sd"); + break; + case VIR_DOMAIN_DISK_BUS_SATA: + if (drive->bus > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only bus 0 for SATA bus."), disk->dst); + goto cleanup; + } + sdkbus = PMS_SATA_DEVICE; + idx = drive->unit; + dst = virIndexToDiskName(idx, "sd"); + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified disk bus is not " + "supported by vz driver.")); + goto cleanup; + } + + if (!dst) + goto cleanup; + + if (STRNEQ(dst, disk->dst)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid drive " + "address of disk %s, vz driver supports " + "only defaults address to logical device name."), disk->dst); + goto cleanup; + } + + pret = PrlVmDev_SetIfaceType(sdkdisk, sdkbus); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetStackIndex(sdkdisk, idx); + prlsdkCheckRetGoto(pret, cleanup); + + switch (disk->cachemode) { + case VIR_DOMAIN_DISK_CACHE_DISABLE: + pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_FALSE); + prlsdkCheckRetGoto(pret, cleanup); + break; + case VIR_DOMAIN_DISK_CACHE_WRITEBACK: + pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_TRUE); + prlsdkCheckRetGoto(pret, cleanup); + break; + case VIR_DOMAIN_DISK_CACHE_DEFAULT: + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified disk cache mode is not " + "supported by vz driver.")); + goto cleanup; + } + + if (bootDisk == true) { + pret = PrlVmDev_GetIndex(sdkdisk, &devIndex); + prlsdkCheckRetGoto(pret, cleanup); + + if (prlsdkAddDeviceToBootList(sdkdom, devIndex, devType, 0) < 0) + goto cleanup; + + /* If we add physical device as a boot disk to container + * we have to specify mount point for it */ + if (isCt) { + pret = PrlVmDevHd_SetMountPoint(sdkdisk, "/"); + prlsdkCheckRetGoto(pret, cleanup); + } + } + + return 0; + cleanup: + PrlHandle_Free(sdkdisk); + VIR_FREE(dst); + return ret; +} + +int +prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk) +{ + int ret = -1; + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_BeginEdit(privdom->sdkdom); + if (PRL_FAILED(waitJob(job))) + goto cleanup; + + ret = prlsdkAddDisk(privdom->sdkdom, disk, false, IS_CT(dom->def)); + if (ret == 0) { + job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE); + if (PRL_FAILED(waitJob(job))) { + ret = -1; + goto cleanup; + } + } + + cleanup: + return ret; +} + +static int +prlsdkGetDiskIndex(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk) +{ + int idx = -1; + char *buf = NULL; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 hddCount; + PRL_UINT32 i; + PRL_HANDLE hdd = PRL_INVALID_HANDLE; + + pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); + prlsdkCheckRetGoto(pret, cleanup); + + for (i = 0; i < hddCount; ++i) { + + pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_GetFriendlyName(hdd, 0, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmDev_GetFriendlyName(hdd, buf, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (STRNEQ(disk->src->path, buf)) { + + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + VIR_FREE(buf); + continue; + } + + VIR_FREE(buf); + idx = i; + break; + } + + cleanup: + PrlHandle_Free(hdd); + return idx; +} + +int +prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk) +{ + int ret = -1, idx; + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + + idx = prlsdkGetDiskIndex(privdom->sdkdom, disk); + if (idx < 0) + goto cleanup; + + job = PrlVm_BeginEdit(privdom->sdkdom); + if (PRL_FAILED(waitJob(job))) + goto cleanup; + + ret = prlsdkDelDisk(privdom->sdkdom, idx); + if (ret == 0) { + job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE); + if (PRL_FAILED(waitJob(job))) { + ret = -1; + goto cleanup; + } + } + + cleanup: + return ret; +} + +static int +prlsdkAddFS(PRL_HANDLE sdkdom, virDomainFSDefPtr fs) +{ + PRL_RESULT pret; + PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; + int ret = -1; + + if (prlsdkCheckFSUnsupportedParams(fs) < 0) + return -1; + + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetEnabled(sdkdisk, 1); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetConnected(sdkdisk, 1); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetEmulatedType(sdkdisk, PDT_USE_IMAGE_FILE); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetSysName(sdkdisk, fs->src); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetImagePath(sdkdisk, fs->src); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetFriendlyName(sdkdisk, fs->src); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDevHd_SetMountPoint(sdkdisk, fs->dst); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(sdkdisk); + return ret; +} +static int +prlsdkDoApplyConfig(virConnectPtr conn, + PRL_HANDLE sdkdom, + virDomainDefPtr def, + virDomainDefPtr olddef) +{ + PRL_RESULT pret; + size_t i; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + bool needBoot = true; + char *mask = NULL; + + if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0) + return -1; + + if (def->description) { + pret = PrlVmCfg_SetDescription(sdkdom, def->description); + prlsdkCheckRetGoto(pret, error); + } + + if (def->name) { + pret = PrlVmCfg_SetName(sdkdom, def->name); + prlsdkCheckRetGoto(pret, error); + } + + if (def->uuid) { + prlsdkUUIDFormat(def->uuid, uuidstr); + + pret = PrlVmCfg_SetUuid(sdkdom, uuidstr); + prlsdkCheckRetGoto(pret, error); + } + + pret = PrlVmCfg_SetRamSize(sdkdom, virDomainDefGetMemoryActual(def) >> 10); + prlsdkCheckRetGoto(pret, error); + + pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus); + prlsdkCheckRetGoto(pret, error); + + if (!(mask = virBitmapFormat(def->cpumask))) + goto error; + + pret = PrlVmCfg_SetCpuMask(sdkdom, mask); + prlsdkCheckRetGoto(pret, error); + VIR_FREE(mask); + + switch (def->os.arch) { + case VIR_ARCH_X86_64: + pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_64); + break; + case VIR_ARCH_I686: + pret = PrlVmCfg_SetCpuMode(sdkdom, PCM_CPU_MODE_32); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU mode: %s"), + virArchToString(def->os.arch)); + goto error; + } + prlsdkCheckRetGoto(pret, error); + + if (prlsdkClearDevices(sdkdom) < 0) + goto error; + + if (prlsdkRemoveBootDevices(sdkdom) < 0) + goto error; + + if (olddef) { + for (i = 0; i < olddef->nnets; i++) + prlsdkDelNet(conn->privateData, olddef->nets[i]); + } + + for (i = 0; i < def->nnets; i++) { + if (prlsdkAddNet(sdkdom, conn->privateData, def->nets[i], IS_CT(def)) < 0) + goto error; + } + + if (prlsdkApplyGraphicsParams(sdkdom, def) < 0) + goto error; + + if (prlsdkApplyVideoParams(sdkdom, def) < 0) + goto error; + + for (i = 0; i < def->nserials; i++) { + if (prlsdkAddSerial(sdkdom, def->serials[i]) < 0) + goto error; + } + + for (i = 0; i < def->nfss; i++) { + if (STREQ(def->fss[i]->dst, "/")) + needBoot = false; + if (prlsdkAddFS(sdkdom, def->fss[i]) < 0) + goto error; + } + + for (i = 0; i < def->ndisks; i++) { + bool bootDisk = false; + + if (needBoot == true && + def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) { + + needBoot = false; + bootDisk = true; + } + if (prlsdkAddDisk(sdkdom, def->disks[i], bootDisk, IS_CT(def)) < 0) + goto error; + } + + return 0; + + error: + VIR_FREE(mask); + + for (i = 0; i < def->nnets; i++) + prlsdkDelNet(conn->privateData, def->nets[i]); + + return -1; +} + +int +prlsdkApplyConfig(virConnectPtr conn, + virDomainObjPtr dom, + virDomainDefPtr new) +{ + vzConnPtr privconn = conn->privateData; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + PRL_HANDLE job = PRL_INVALID_HANDLE; + int ret; + + sdkdom = prlsdkSdkDomainLookupByUUID(privconn, dom->def->uuid); + if (sdkdom == PRL_INVALID_HANDLE) + return -1; + + job = PrlVm_BeginEdit(sdkdom); + if (PRL_FAILED(waitJob(job))) + return -1; + + ret = prlsdkDoApplyConfig(conn, sdkdom, new, dom->def); + + if (ret == 0) { + job = PrlVm_CommitEx(sdkdom, PVCF_DETACH_HDD_BUNDLE); + if (PRL_FAILED(waitJob(job))) + ret = -1; + } + + PrlHandle_Free(sdkdom); + + return ret; +} + +int +prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def) +{ + vzConnPtr privconn = conn->privateData; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_HANDLE srvconf = PRL_INVALID_HANDLE; + PRL_RESULT pret; + int ret = -1; + + pret = PrlSrv_CreateVm(privconn->server, &sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + job = PrlSrv_GetSrvConfig(privconn->server); + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, &srvconf); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmCfg_SetDefaultConfig(sdkdom, srvconf, PVS_GUEST_VER_LIN_REDHAT, 0); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmCfg_SetOfflineManagementEnabled(sdkdom, 0); + prlsdkCheckRetGoto(pret, cleanup); + + ret = prlsdkDoApplyConfig(conn, sdkdom, def, NULL); + if (ret) + goto cleanup; + + job = PrlVm_Reg(sdkdom, "", 1); + if (PRL_FAILED(waitJob(job))) + ret = -1; + + cleanup: + PrlHandle_Free(sdkdom); + return ret; +} + +int +prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) +{ + vzConnPtr privconn = conn->privateData; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + PRL_GET_VM_CONFIG_PARAM_DATA confParam; + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_RESULT pret; + int ret = -1; + int useTemplate = 0; + size_t i; + + if (def->nfss > 1) { + /* Check all filesystems */ + for (i = 0; i < def->nfss; i++) { + if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_FILE) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Unsupported filesystem type.")); + return -1; + } + } + } else if (def->nfss == 1) { + if (def->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) { + useTemplate = 1; + } else if (def->fss[0]->type != VIR_DOMAIN_FS_TYPE_FILE) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Unsupported filesystem type.")); + return -1; + } + } + + confParam.nVmType = PVT_CT; + confParam.sConfigSample = "vswap.1024MB"; + confParam.nOsVersion = 0; + + job = PrlSrv_GetDefaultVmConfig(privconn->server, &confParam, 0); + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, &sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + if (useTemplate) { + pret = PrlVmCfg_SetOsTemplate(sdkdom, def->fss[0]->src); + prlsdkCheckRetGoto(pret, cleanup); + + } + + ret = prlsdkDoApplyConfig(conn, sdkdom, def, NULL); + if (ret) + goto cleanup; + + job = PrlVm_RegEx(sdkdom, "", + PACF_NON_INTERACTIVE_MODE | PRNVM_PRESERVE_DISK); + if (PRL_FAILED(waitJob(job))) + ret = -1; + + cleanup: + PrlHandle_Free(sdkdom); + return ret; +} + +int +prlsdkUnregisterDomain(vzConnPtr privconn, virDomainObjPtr dom) +{ + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job; + size_t i; + + for (i = 0; i < dom->def->nnets; i++) + prlsdkDelNet(privconn, dom->def->nets[i]); + + job = PrlVm_Unreg(privdom->sdkdom); + if (PRL_FAILED(waitJob(job))) + return -1; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) + return -1; + + virDomainObjListRemove(privconn->domains, dom); + return 0; +} + +int +prlsdkDomainManagedSaveRemove(virDomainObjPtr dom) +{ + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job; + + job = PrlVm_DropSuspendedState(privdom->sdkdom); + if (PRL_FAILED(waitJob(job))) + return -1; + + return 0; +} + +static int +prlsdkExtractStatsParam(PRL_HANDLE sdkstats, const char *name, long long *val) +{ + PRL_HANDLE param = PRL_INVALID_HANDLE; + PRL_RESULT pret; + PRL_INT64 pval = 0; + int ret = -1; + + pret = PrlEvent_GetParamByName(sdkstats, name, ¶m); + if (pret == PRL_ERR_NO_DATA) { + *val = -1; + ret = 0; + goto cleanup; + } else if (PRL_FAILED(pret)) { + logPrlError(pret); + goto cleanup; + } + pret = PrlEvtPrm_ToInt64(param, &pval); + prlsdkCheckRetGoto(pret, cleanup); + + *val = pval; + ret = 0; + + cleanup: + PrlHandle_Free(param); + return ret; +} + +#define PARALLELS_STATISTICS_TIMEOUT (60 * 1000) + +static int +prlsdkGetStatsParam(virDomainObjPtr dom, const char *name, long long *val) +{ + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + unsigned long long now; + + if (privdom->cache.stats != PRL_INVALID_HANDLE) { + // reset count to keep subscribtion + privdom->cache.count = 0; + return prlsdkExtractStatsParam(privdom->cache.stats, name, val); + } + + if (privdom->cache.count == -1) { + job = PrlVm_SubscribeToPerfStats(privdom->sdkdom, NULL); + if (PRL_FAILED(waitJob(job))) + goto error; + } + + // change state to subscribed in case of unsubscribed + // or reset count so we stop unsubscribe attempts + privdom->cache.count = 0; + + if (virTimeMillisNow(&now) < 0) { + virReportSystemError(errno, "%s", _("Unable to get current time")); + goto error; + } + + while (privdom->cache.stats == PRL_INVALID_HANDLE) { + if (virCondWaitUntil(&privdom->cache.cond, &dom->parent.lock, + now + PARALLELS_STATISTICS_TIMEOUT) < 0) { + if (errno == ETIMEDOUT) { + virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", + _("Timeout on waiting statistics event.")); + goto error; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to wait on monitor condition")); + goto error; + } + } + } + + return prlsdkExtractStatsParam(privdom->cache.stats, name, val); + error: + return -1; +} + +int +prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats) +{ + virDomainDeviceDriveAddressPtr address; + int idx; + const char *prefix; + int ret = -1; + char *name = NULL; + + address = &disk->info.addr.drive; + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_IDE: + prefix = "ide"; + idx = address->bus * 2 + address->unit; + break; + case VIR_DOMAIN_DISK_BUS_SATA: + prefix = "sata"; + idx = address->unit; + break; + case VIR_DOMAIN_DISK_BUS_SCSI: + prefix = "scsi"; + idx = address->unit; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown disk bus: %X"), disk->bus); + goto cleanup; + } + + +#define PRLSDK_GET_STAT_PARAM(VAL, TYPE, NAME) \ + if (virAsprintf(&name, "devices.%s%d.%s", prefix, idx, NAME) < 0) \ + goto cleanup; \ + if (prlsdkGetStatsParam(dom, name, &stats->VAL) < 0) \ + goto cleanup; \ + VIR_FREE(name); + + PARALLELS_BLOCK_STATS_FOREACH(PRLSDK_GET_STAT_PARAM) + +#undef PRLSDK_GET_STAT_PARAM + + ret = 0; + + cleanup: + + VIR_FREE(name); + return ret; +} diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h new file mode 100644 index 0000000000..dd4fecfef7 --- /dev/null +++ b/src/vz/vz_sdk.h @@ -0,0 +1,68 @@ +/* + * vz_sdk.h: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2014 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 + * . + * + */ + +#include + +#include "vz_utils.h" + +int prlsdkInit(void); +void prlsdkDeinit(void); +int prlsdkConnect(vzConnPtr privconn); +void prlsdkDisconnect(vzConnPtr privconn); +int +prlsdkLoadDomains(vzConnPtr privconn); +virDomainObjPtr +prlsdkAddDomain(vzConnPtr privconn, const unsigned char *uuid); +int prlsdkUpdateDomain(vzConnPtr privconn, virDomainObjPtr dom); +int prlsdkSubscribeToPCSEvents(vzConnPtr privconn); +void prlsdkUnsubscribeFromPCSEvents(vzConnPtr privconn); +PRL_RESULT prlsdkStart(PRL_HANDLE sdkdom); +PRL_RESULT prlsdkKill(PRL_HANDLE sdkdom); +PRL_RESULT prlsdkStop(PRL_HANDLE sdkdom); +PRL_RESULT prlsdkPause(PRL_HANDLE sdkdom); +PRL_RESULT prlsdkResume(PRL_HANDLE sdkdom); +PRL_RESULT prlsdkSuspend(PRL_HANDLE sdkdom); + +typedef PRL_RESULT (*prlsdkChangeStateFunc)(PRL_HANDLE sdkdom); +int +prlsdkDomainChangeState(virDomainPtr domain, + prlsdkChangeStateFunc chstate); +int +prlsdkDomainChangeStateLocked(vzConnPtr privconn, + virDomainObjPtr dom, + prlsdkChangeStateFunc chstate); +int +prlsdkApplyConfig(virConnectPtr conn, + virDomainObjPtr dom, + virDomainDefPtr new); +int prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def); +int prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def); +int +prlsdkUnregisterDomain(vzConnPtr privconn, virDomainObjPtr dom); +int +prlsdkDomainManagedSaveRemove(virDomainObjPtr dom); +int +prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk); +int +prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk); +int +prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats); diff --git a/src/vz/vz_storage.c b/src/vz/vz_storage.c new file mode 100644 index 0000000000..7183db4823 --- /dev/null +++ b/src/vz/vz_storage.c @@ -0,0 +1,1654 @@ +/* + * vz_storage.c: core driver functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2013-2014 Red Hat, Inc. + * 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 + * . + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "datatypes.h" +#include "dirname.h" +#include "viralloc.h" +#include "configmake.h" +#include "virstoragefile.h" +#include "virerror.h" +#include "virfile.h" +#include "vz_utils.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +#define vzPoolNotFoundError(pool_name) \ + virReportError(VIR_ERR_INVALID_ARG, \ + _("pool '%s' not found"), pool_name); + +static virStorageVolDefPtr +vzStorageVolDefineXML(virStoragePoolObjPtr pool, const char *xmldesc, + const char *xmlfile, bool is_new); +static virStorageVolPtr +vzStorageVolLookupByPath(virConnectPtr conn, const char *path); + +static int +vzStoragePoolGetAlloc(virStoragePoolDefPtr def); + +static void +vzStorageLock(virStorageDriverStatePtr driver) +{ + virMutexLock(&driver->lock); +} + +static void +vzStorageUnlock(virStorageDriverStatePtr driver) +{ + virMutexUnlock(&driver->lock); +} + +int +vzStorageClose(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + + if (!privconn) + return 0; + + virStorageDriverStatePtr storageState = privconn->storageState; + privconn->storageState = NULL; + + if (!storageState) + return 0; + + vzStorageLock(storageState); + virStoragePoolObjListFree(&privconn->pools); + VIR_FREE(storageState->configDir); + VIR_FREE(storageState->autostartDir); + vzStorageUnlock(storageState); + virMutexDestroy(&storageState->lock); + VIR_FREE(storageState); + + return 0; +} + +static int +vzFindVolumes(virStoragePoolObjPtr pool) +{ + DIR *dir; + struct dirent *ent; + char *path = NULL; + int ret = -1; + int direrr; + + if (!(dir = opendir(pool->def->target.path))) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + return -1; + } + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + if (!virFileHasSuffix(ent->d_name, ".xml")) + continue; + + if (!(path = virFileBuildPath(pool->def->target.path, + ent->d_name, NULL))) + goto cleanup; + if (!vzStorageVolDefineXML(pool, NULL, path, false)) + goto cleanup; + + VIR_FREE(path); + } + if (direrr < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_FREE(path); + closedir(dir); + return ret; + +} + +/* + * Generate unique pool name by path + */ +static char *vzMakePoolName(virConnectPtr conn, const char *path) +{ + vzConnPtr privconn = conn->privateData; + char *name; + size_t i; + + for (i = 0; i < UINT_MAX; i++) { + bool found = false; + size_t j; + + if ((!i && VIR_STRDUP(name, path) < 0) || + (i && virAsprintf(&name, "%s-%zu", path, i) < 0)) + return NULL; + + for (j = 0; j < strlen(name); j++) + if (name[j] == '/') + name[j] = '-'; + + for (j = 0; j < privconn->pools.count; j++) { + if (STREQ(name, privconn->pools.objs[j]->def->name)) { + found = true; + break; + } + } + + if (!found) + return name; + + VIR_FREE(name); + } + + return NULL; +} + +static virStoragePoolObjPtr +vzPoolCreateByPath(virConnectPtr conn, const char *path) +{ + vzConnPtr privconn = conn->privateData; + virStoragePoolObjListPtr pools = &privconn->pools; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool = NULL; + + if (VIR_ALLOC(def) < 0) + goto error; + + if (!(def->name = vzMakePoolName(conn, path))) + goto error; + + if (virUUIDGenerate(def->uuid)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Can't generate UUID")); + goto error; + } + + def->type = VIR_STORAGE_POOL_DIR; + if (VIR_STRDUP(def->target.path, path) < 0) + goto error; + + if (!(pool = virStoragePoolObjAssignDef(pools, def))) + goto error; + + if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) { + virStoragePoolObjRemove(pools, pool); + goto error; + } + + virStoragePoolObjUnlock(pool); + + return pool; + error: + virStoragePoolDefFree(def); + if (pool) + virStoragePoolObjUnlock(pool); + return NULL; +} + +/* + * Create pool of type VIR_STORAGE_POOL_DIR with + * path to the VM, if it does not exist. + */ +static virStoragePoolObjPtr +vzPoolAddByDomain(virConnectPtr conn, virDomainObjPtr dom) +{ + vzConnPtr privconn = conn->privateData; + vzDomObjPtr pdom = dom->privateData; + virStoragePoolObjListPtr pools = &privconn->pools; + char *poolPath; + virStoragePoolObjPtr pool = NULL; + size_t j; + + poolPath = mdir_name(pdom->home); + if (!poolPath) { + virReportOOMError(); + return NULL; + } + + for (j = 0; j < pools->count; j++) { + if (STREQ(poolPath, pools->objs[j]->def->target.path)) { + pool = pools->objs[j]; + break; + } + } + + if (!pool) + pool = vzPoolCreateByPath(conn, poolPath); + + VIR_FREE(poolPath); + return pool; +} + +static int vzDiskDescParseNode(xmlDocPtr xml, + xmlNodePtr root, + virStorageVolDefPtr def) +{ + xmlXPathContextPtr ctxt = NULL; + int ret = -1; + + if (STRNEQ((const char *)root->name, "Parallels_disk_image")) { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("unknown root element for storage pool")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(); + goto cleanup; + } + + ctxt->node = root; + + if (virXPathULongLong("string(./Disk_Parameters/Disk_size)", + ctxt, &def->target.capacity) < 0) { + virReportError(VIR_ERR_XML_ERROR, + "%s", _("failed to get disk size from " + "the disk descriptor xml")); + goto cleanup; + } + + def->target.capacity <<= 9; + def->target.allocation = def->target.capacity; + ret = 0; + cleanup: + xmlXPathFreeContext(ctxt); + return ret; + +} + +static int vzDiskDescParse(const char *path, virStorageVolDefPtr def) +{ + xmlDocPtr xml; + int ret = -1; + + if (!(xml = virXMLParse(path, NULL, NULL))) + return -1; + + ret = vzDiskDescParseNode(xml, xmlDocGetRootElement(xml), def); + xmlFreeDoc(xml); + return ret; +} + +static int vzAddDiskVolume(virStoragePoolObjPtr pool, + virDomainObjPtr dom, + const char *diskName, + const char *diskPath, + const char *diskDescPath) +{ + virStorageVolDefPtr def = NULL; + + if (VIR_ALLOC(def)) + goto error; + + if (virAsprintf(&def->name, "%s-%s", dom->def->name, diskName) < 0) + goto error; + + def->type = VIR_STORAGE_VOL_FILE; + + if (vzDiskDescParse(diskDescPath, def) < 0) + goto error; + + if (!(def->target.path = realpath(diskPath, NULL))) + goto no_memory; + + if (VIR_STRDUP(def->key, def->target.path) < 0) + goto error; + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, def) < 0) + goto error; + + return 0; + no_memory: + virReportOOMError(); + error: + virStorageVolDefFree(def); + return -1; +} + +static int vzFindVmVolumes(virStoragePoolObjPtr pool, + virDomainObjPtr dom) +{ + vzDomObjPtr pdom = dom->privateData; + DIR *dir; + struct dirent *ent; + char *diskPath = NULL, *diskDescPath = NULL; + struct stat sb; + int ret = -1; + int direrr; + + if (!(dir = opendir(pdom->home))) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pdom->home); + return ret; + } + + while ((direrr = virDirRead(dir, &ent, pdom->home)) > 0) { + VIR_FREE(diskPath); + VIR_FREE(diskDescPath); + + if (!(diskPath = virFileBuildPath(pdom->home, ent->d_name, NULL))) + goto cleanup; + + if (lstat(diskPath, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + ent->d_name); + goto cleanup; + } + + if (!S_ISDIR(sb.st_mode)) + continue; + + if (!(diskDescPath = virFileBuildPath(diskPath, + "DiskDescriptor", ".xml"))) + goto cleanup; + + if (!virFileExists(diskDescPath)) + continue; + + /* here we know, that ent->d_name is a disk image directory */ + + if (vzAddDiskVolume(pool, dom, ent->d_name, + diskPath, diskDescPath)) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_FREE(diskPath); + VIR_FREE(diskDescPath); + closedir(dir); + return ret; + +} + +static int +vzPoolsAdd(virDomainObjPtr dom, + void *opaque) +{ + virConnectPtr conn = opaque; + virStoragePoolObjPtr pool; + + if (!(pool = vzPoolAddByDomain(conn, dom))) + return -1; + + if (vzFindVmVolumes(pool, dom)) + return -1; + + return 0; +} + +static int vzLoadPools(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + virStorageDriverStatePtr storageState = privconn->storageState; + char *base = NULL; + size_t i; + + if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0) + goto error; + + /* Configuration path is /etc/libvirt/parallels-storage/... . */ + if (virAsprintf(&storageState->configDir, + "%s/parallels-storage", base) == -1) + goto error; + + if (virAsprintf(&storageState->autostartDir, + "%s/parallels-storage/autostart", base) == -1) + goto error; + + VIR_FREE(base); + + if (virStoragePoolLoadAllConfigs(&privconn->pools, + storageState->configDir, + storageState->autostartDir) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to load pool configs")); + goto error; + } + + if (virDomainObjListForEach(privconn->domains, vzPoolsAdd, conn) < 0) + goto error; + + for (i = 0; i < privconn->pools.count; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + virStoragePoolObjPtr pool; + + pool = privconn->pools.objs[i]; + pool->active = 1; + + if (vzStoragePoolGetAlloc(pool->def) < 0) + goto error; + + if (vzFindVolumes(pool) < 0) + goto error; + + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + + return 0; + + error: + VIR_FREE(base); + return -1; +} + +virDrvOpenStatus +vzStorageOpen(virConnectPtr conn, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + virStorageDriverStatePtr storageState; + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (STRNEQ(conn->driver->name, "vz") && + STRNEQ(conn->driver->name, "Parallels")) + return VIR_DRV_OPEN_DECLINED; + + if (VIR_ALLOC(storageState) < 0) + return VIR_DRV_OPEN_ERROR; + + if (virMutexInit(&storageState->lock) < 0) { + VIR_FREE(storageState); + return VIR_DRV_OPEN_ERROR; + } + + privconn->storageState = storageState; + vzStorageLock(storageState); + + if (vzLoadPools(conn)) + goto error; + + vzStorageUnlock(storageState); + + return VIR_DRV_OPEN_SUCCESS; + + error: + vzStorageUnlock(storageState); + vzStorageClose(conn); + return VIR_DRV_OPEN_ERROR; +} + +static int +vzConnectNumOfStoragePools(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + int numActive = 0; + size_t i; + + vzDriverLock(privconn); + for (i = 0; i < privconn->pools.count; i++) + if (virStoragePoolObjIsActive(privconn->pools.objs[i])) + numActive++; + vzDriverUnlock(privconn); + + return numActive; +} + +static int +vzConnectListStoragePools(virConnectPtr conn, char **const names, int nnames) +{ + vzConnPtr privconn = conn->privateData; + int n = 0; + size_t i; + + vzDriverLock(privconn); + memset(names, 0, sizeof(*names) * nnames); + for (i = 0; i < privconn->pools.count && n < nnames; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + if (virStoragePoolObjIsActive(privconn->pools.objs[i]) && + VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) { + virStoragePoolObjUnlock(privconn->pools.objs[i]); + goto error; + } + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + vzDriverUnlock(privconn); + + return n; + + error: + for (n = 0; n < nnames; n++) + VIR_FREE(names[n]); + vzDriverUnlock(privconn); + return -1; +} + +static int +vzConnectNumOfDefinedStoragePools(virConnectPtr conn) +{ + vzConnPtr privconn = conn->privateData; + int numInactive = 0; + size_t i; + + vzDriverLock(privconn); + for (i = 0; i < privconn->pools.count; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + if (!virStoragePoolObjIsActive(privconn->pools.objs[i])) + numInactive++; + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + vzDriverUnlock(privconn); + + return numInactive; +} + +static int +vzConnectListDefinedStoragePools(virConnectPtr conn, + char **const names, int nnames) +{ + vzConnPtr privconn = conn->privateData; + int n = 0; + size_t i; + + vzDriverLock(privconn); + memset(names, 0, sizeof(*names) * nnames); + for (i = 0; i < privconn->pools.count && n < nnames; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) && + VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) { + virStoragePoolObjUnlock(privconn->pools.objs[i]); + goto error; + } + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + vzDriverUnlock(privconn); + + return n; + + error: + for (n = 0; n < nnames; n++) + VIR_FREE(names[n]); + vzDriverUnlock(privconn); + return -1; +} + + +static int +vzStoragePoolIsActive(virStoragePoolPtr pool) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr obj; + int ret = -1; + + vzDriverLock(privconn); + obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid); + vzDriverUnlock(privconn); + if (!obj) { + virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); + goto cleanup; + } + ret = virStoragePoolObjIsActive(obj); + + cleanup: + if (obj) + virStoragePoolObjUnlock(obj); + return ret; +} + +static int +vzStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED) +{ + return 1; +} + +static virStoragePoolPtr +vzStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid) +{ + vzConnPtr privconn = conn->privateData; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret = NULL; + + vzDriverLock(privconn); + pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid); + vzDriverUnlock(privconn); + + if (pool == NULL) { + virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); + goto cleanup; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, + NULL, NULL); + + cleanup: + if (pool) + virStoragePoolObjUnlock(pool); + return ret; +} + +static virStoragePoolPtr +vzStoragePoolLookupByName(virConnectPtr conn, const char *name) +{ + vzConnPtr privconn = conn->privateData; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret = NULL; + + vzDriverLock(privconn); + pool = virStoragePoolObjFindByName(&privconn->pools, name); + vzDriverUnlock(privconn); + + if (pool == NULL) { + virReportError(VIR_ERR_NO_STORAGE_POOL, NULL); + goto cleanup; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, + NULL, NULL); + + cleanup: + if (pool) + virStoragePoolObjUnlock(pool); + return ret; +} + +static virStoragePoolPtr +vzStoragePoolLookupByVolume(virStorageVolPtr vol) +{ + return vzStoragePoolLookupByName(vol->conn, vol->pool); +} + +/* + * Fill capacity, available and allocation + * fields in pool definition. + */ +static int +vzStoragePoolGetAlloc(virStoragePoolDefPtr def) +{ + struct statvfs sb; + + if (statvfs(def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + def->target.path); + return -1; + } + + def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + def->allocation = def->capacity - def->available; + + return 0; +} + +static virStoragePoolPtr +vzStoragePoolDefineXML(virConnectPtr conn, + const char *xml, unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool = NULL; + virStoragePoolPtr ret = NULL; + + virCheckFlags(0, NULL); + + vzDriverLock(privconn); + if (!(def = virStoragePoolDefParseString(xml))) + goto cleanup; + + if (def->type != VIR_STORAGE_POOL_DIR) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("Only local directories are supported")); + goto cleanup; + } + + if (virStoragePoolObjIsDuplicate(&privconn->pools, def, 0) < 0) + goto cleanup; + + if (virStoragePoolSourceFindDuplicate(conn, &privconn->pools, def) < 0) + goto cleanup; + + if (vzStoragePoolGetAlloc(def)) + goto cleanup; + + if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def))) + goto cleanup; + + if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) { + virStoragePoolObjRemove(&privconn->pools, pool); + def = NULL; + goto cleanup; + } + def = NULL; + + if (VIR_STRDUP(pool->configFile, "\0") < 0) + goto cleanup; + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid, + NULL, NULL); + + cleanup: + virStoragePoolDefFree(def); + if (pool) + virStoragePoolObjUnlock(pool); + vzDriverUnlock(privconn); + return ret; +} + +static int +vzStoragePoolUndefine(virStoragePoolPtr pool) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is still active"), pool->name); + goto cleanup; + } + + if (virStoragePoolObjDeleteDef(privpool) < 0) + goto cleanup; + + VIR_FREE(privpool->configFile); + + virStoragePoolObjRemove(&privconn->pools, privpool); + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + vzDriverUnlock(privconn); + return ret; +} + +static int +vzStoragePoolCreate(virStoragePoolPtr pool, unsigned int flags) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + virCheckFlags(0, -1); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is already active"), pool->name); + goto cleanup; + } + + privpool->active = 1; + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static int +vzStoragePoolDestroy(virStoragePoolPtr pool) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + + if (privpool->configFile == NULL) { + virStoragePoolObjRemove(&privconn->pools, privpool); + privpool = NULL; + } + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + vzDriverUnlock(privconn); + return ret; +} + +static int +vzStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + virCheckFlags(0, -1); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + + +static int +vzStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + memset(info, 0, sizeof(virStoragePoolInfo)); + if (privpool->active) + info->state = VIR_STORAGE_POOL_RUNNING; + else + info->state = VIR_STORAGE_POOL_INACTIVE; + info->capacity = privpool->def->capacity; + info->allocation = privpool->def->allocation; + info->available = privpool->def->available; + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static char * +vzStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + char *ret = NULL; + + virCheckFlags(0, NULL); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + ret = virStoragePoolDefFormat(privpool->def); + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static int +vzStoragePoolGetAutostart(virStoragePoolPtr pool, int *autostart) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!privpool->configFile) { + *autostart = 0; + } else { + *autostart = privpool->autostart; + } + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static int +vzStoragePoolSetAutostart(virStoragePoolPtr pool, int autostart) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!privpool->configFile) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("pool has no config file")); + goto cleanup; + } + + privpool->autostart = (autostart != 0); + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static int +vzStoragePoolNumOfVolumes(virStoragePoolPtr pool) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + + ret = privpool->volumes.count; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static int +vzStoragePoolListVolumes(virStoragePoolPtr pool, + char **const names, int maxnames) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + int n = 0; + size_t i = 0; + + memset(names, 0, maxnames * sizeof(*names)); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto error; + } + + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto error; + } + + for (i = 0; i < privpool->volumes.count && n < maxnames; i++) { + if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0) + goto error; + } + + virStoragePoolObjUnlock(privpool); + return n; + + error: + for (n = 0; n < maxnames; n++) + VIR_FREE(names[i]); + + if (privpool) + virStoragePoolObjUnlock(privpool); + return -1; +} + +static virStorageVolPtr +vzStorageVolLookupByName(virStoragePoolPtr pool, + const char *name) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol; + virStorageVolPtr ret = NULL; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + + privvol = virStorageVolDefFindByName(privpool, name); + + if (!privvol) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), name); + goto cleanup; + } + + ret = virGetStorageVol(pool->conn, privpool->def->name, + privvol->name, privvol->key, + NULL, NULL); + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + + +static virStorageVolPtr +vzStorageVolLookupByKey(virConnectPtr conn, const char *key) +{ + vzConnPtr privconn = conn->privateData; + size_t i; + virStorageVolPtr ret = NULL; + + vzDriverLock(privconn); + for (i = 0; i < privconn->pools.count; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + if (virStoragePoolObjIsActive(privconn->pools.objs[i])) { + virStorageVolDefPtr privvol = + virStorageVolDefFindByKey(privconn->pools.objs[i], key); + + if (privvol) { + ret = virGetStorageVol(conn, + privconn->pools.objs[i]->def->name, + privvol->name, privvol->key, + NULL, NULL); + virStoragePoolObjUnlock(privconn->pools.objs[i]); + break; + } + } + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + vzDriverUnlock(privconn); + + if (!ret) + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching key '%s'"), key); + + return ret; +} + +virStorageVolPtr +vzStorageVolLookupByPathLocked(virConnectPtr conn, const char *path) +{ + vzConnPtr privconn = conn->privateData; + size_t i; + virStorageVolPtr ret = NULL; + + for (i = 0; i < privconn->pools.count; i++) { + virStoragePoolObjLock(privconn->pools.objs[i]); + if (virStoragePoolObjIsActive(privconn->pools.objs[i])) { + virStorageVolDefPtr privvol = + virStorageVolDefFindByPath(privconn->pools.objs[i], path); + + if (privvol) { + ret = virGetStorageVol(conn, + privconn->pools.objs[i]->def->name, + privvol->name, privvol->key, + NULL, NULL); + virStoragePoolObjUnlock(privconn->pools.objs[i]); + break; + } + } + virStoragePoolObjUnlock(privconn->pools.objs[i]); + } + + if (!ret) + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching path '%s'"), path); + + return ret; +} + +static virStorageVolPtr +vzStorageVolLookupByPath(virConnectPtr conn, const char *path) +{ + vzConnPtr privconn = conn->privateData; + virStorageVolPtr ret = NULL; + + vzDriverLock(privconn); + ret = vzStorageVolLookupByPathLocked(conn, path); + vzDriverUnlock(privconn); + + return ret; +} + +static virStorageVolDefPtr +vzStorageVolDefineXML(virStoragePoolObjPtr pool, + const char *xmldesc, + const char *xmlfile, bool is_new) +{ + virStorageVolDefPtr privvol = NULL; + virStorageVolDefPtr ret = NULL; + char *xml_path = NULL; + + if (xmlfile) + privvol = virStorageVolDefParseFile(pool->def, xmlfile, 0); + else + privvol = virStorageVolDefParseString(pool->def, xmldesc, 0); + + if (privvol == NULL) + goto cleanup; + + if (virStorageVolDefFindByName(pool, privvol->name)) { + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("storage vol already exists")); + goto cleanup; + } + + if (is_new) { + /* Make sure enough space */ + if ((pool->def->allocation + privvol->target.allocation) > + pool->def->capacity) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Not enough free space in pool for volume '%s'"), + privvol->name); + goto cleanup; + } + } + + if (virAsprintf(&privvol->target.path, "%s/%s", + pool->def->target.path, privvol->name) < 0) + goto cleanup; + + if (VIR_STRDUP(privvol->key, privvol->target.path) < 0) + goto cleanup; + + if (is_new) { + xml_path = vzAddFileExt(privvol->target.path, ".xml"); + if (!xml_path) + goto cleanup; + + if (virXMLSaveFile(xml_path, NULL, "volume-create", xmldesc)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Can't create file with volume description")); + goto cleanup; + } + + pool->def->allocation += privvol->target.allocation; + pool->def->available = (pool->def->capacity - + pool->def->allocation); + } + + if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, + pool->volumes.count, privvol) < 0) + goto cleanup; + + ret = privvol; + privvol = NULL; + + cleanup: + virStorageVolDefFree(privvol); + VIR_FREE(xml_path); + return ret; +} + +static virStorageVolPtr +vzStorageVolCreateXML(virStoragePoolPtr pool, + const char *xmldesc, unsigned int flags) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolPtr ret = NULL; + virStorageVolDefPtr privvol = NULL; + + virCheckFlags(0, NULL); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + + privvol = vzStorageVolDefineXML(privpool, xmldesc, NULL, true); + if (!privvol) + goto cleanup; + + ret = virGetStorageVol(pool->conn, privpool->def->name, + privvol->name, privvol->key, + NULL, NULL); + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static virStorageVolPtr +vzStorageVolCreateXMLFrom(virStoragePoolPtr pool, + const char *xmldesc, + virStorageVolPtr clonevol, + unsigned int flags) +{ + vzConnPtr privconn = pool->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol = NULL, origvol = NULL; + virStorageVolPtr ret = NULL; + + virCheckFlags(0, NULL); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(pool->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), pool->name); + goto cleanup; + } + + privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0); + if (privvol == NULL) + goto cleanup; + + if (virStorageVolDefFindByName(privpool, privvol->name)) { + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("storage vol already exists")); + goto cleanup; + } + + origvol = virStorageVolDefFindByName(privpool, clonevol->name); + if (!origvol) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), + clonevol->name); + goto cleanup; + } + + /* Make sure enough space */ + if ((privpool->def->allocation + privvol->target.allocation) > + privpool->def->capacity) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Not enough free space in pool for volume '%s'"), + privvol->name); + goto cleanup; + } + privpool->def->available = (privpool->def->capacity - + privpool->def->allocation); + + if (virAsprintf(&privvol->target.path, "%s/%s", + privpool->def->target.path, privvol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(privvol->key, privvol->target.path) < 0) + goto cleanup; + + privpool->def->allocation += privvol->target.allocation; + privpool->def->available = (privpool->def->capacity - + privpool->def->allocation); + + if (VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs, + privpool->volumes.count, privvol) < 0) + goto cleanup; + + ret = virGetStorageVol(pool->conn, privpool->def->name, + privvol->name, privvol->key, + NULL, NULL); + privvol = NULL; + + cleanup: + virStorageVolDefFree(privvol); + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +int vzStorageVolDefRemove(virStoragePoolObjPtr privpool, + virStorageVolDefPtr privvol) +{ + int ret = -1; + char *xml_path = NULL; + size_t i; + + privpool->def->allocation -= privvol->target.allocation; + privpool->def->available = (privpool->def->capacity - + privpool->def->allocation); + + for (i = 0; i < privpool->volumes.count; i++) { + if (privpool->volumes.objs[i] == privvol) { + xml_path = vzAddFileExt(privvol->target.path, ".xml"); + if (!xml_path) + goto cleanup; + + if (unlink(xml_path)) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Can't remove file '%s'"), xml_path); + goto cleanup; + } + + virStorageVolDefFree(privvol); + + VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count); + break; + } + } + + ret = 0; + cleanup: + VIR_FREE(xml_path); + return ret; +} + +static int +vzStorageVolDelete(virStorageVolPtr vol, unsigned int flags) +{ + vzConnPtr privconn = vol->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol; + int ret = -1; + + virCheckFlags(0, -1); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(vol->pool); + goto cleanup; + } + + + privvol = virStorageVolDefFindByName(privpool, vol->name); + + if (privvol == NULL) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), vol->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), vol->pool); + goto cleanup; + } + + + if (vzStorageVolDefRemove(privpool, privvol)) + goto cleanup; + + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + + +static int +vzStorageVolTypeForPool(int pooltype) +{ + + switch (pooltype) { + case VIR_STORAGE_POOL_DIR: + case VIR_STORAGE_POOL_FS: + case VIR_STORAGE_POOL_NETFS: + return VIR_STORAGE_VOL_FILE; + default: + return VIR_STORAGE_VOL_BLOCK; + } +} + +static int +vzStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) +{ + vzConnPtr privconn = vol->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol; + int ret = -1; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(vol->pool); + goto cleanup; + } + + privvol = virStorageVolDefFindByName(privpool, vol->name); + + if (privvol == NULL) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), vol->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), vol->pool); + goto cleanup; + } + + memset(info, 0, sizeof(*info)); + info->type = vzStorageVolTypeForPool(privpool->def->type); + info->capacity = privvol->target.capacity; + info->allocation = privvol->target.allocation; + ret = 0; + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static char * +vzStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags) +{ + vzConnPtr privconn = vol->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol; + char *ret = NULL; + + virCheckFlags(0, NULL); + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(vol->pool); + goto cleanup; + } + + privvol = virStorageVolDefFindByName(privpool, vol->name); + + if (privvol == NULL) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), vol->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), vol->pool); + goto cleanup; + } + + ret = virStorageVolDefFormat(privpool->def, privvol); + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +static char * +vzStorageVolGetPath(virStorageVolPtr vol) +{ + vzConnPtr privconn = vol->conn->privateData; + virStoragePoolObjPtr privpool; + virStorageVolDefPtr privvol; + char *ret = NULL; + + vzDriverLock(privconn); + privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool); + vzDriverUnlock(privconn); + + if (privpool == NULL) { + vzPoolNotFoundError(vol->pool); + goto cleanup; + } + + privvol = virStorageVolDefFindByName(privpool, vol->name); + + if (privvol == NULL) { + virReportError(VIR_ERR_NO_STORAGE_VOL, + _("no storage vol with matching name '%s'"), vol->name); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(privpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("storage pool '%s' is not active"), vol->pool); + goto cleanup; + } + + ignore_value(VIR_STRDUP(ret, privvol->target.path)); + + cleanup: + if (privpool) + virStoragePoolObjUnlock(privpool); + return ret; +} + +virStorageDriver vzStorageDriver = { + .name = "Parallels", + + .connectNumOfStoragePools = vzConnectNumOfStoragePools, /* 0.10.0 */ + .connectListStoragePools = vzConnectListStoragePools, /* 0.10.0 */ + .connectNumOfDefinedStoragePools = vzConnectNumOfDefinedStoragePools, /* 0.10.0 */ + .connectListDefinedStoragePools = vzConnectListDefinedStoragePools, /* 0.10.0 */ + .storagePoolLookupByName = vzStoragePoolLookupByName, /* 0.10.0 */ + .storagePoolLookupByUUID = vzStoragePoolLookupByUUID, /* 0.10.0 */ + .storagePoolLookupByVolume = vzStoragePoolLookupByVolume, /* 0.10.0 */ + .storagePoolDefineXML = vzStoragePoolDefineXML, /* 0.10.0 */ + .storagePoolUndefine = vzStoragePoolUndefine, /* 0.10.0 */ + .storagePoolCreate = vzStoragePoolCreate, /* 0.10.0 */ + .storagePoolDestroy = vzStoragePoolDestroy, /* 0.10.0 */ + .storagePoolRefresh = vzStoragePoolRefresh, /* 0.10.0 */ + .storagePoolGetInfo = vzStoragePoolGetInfo, /* 0.10.0 */ + .storagePoolGetXMLDesc = vzStoragePoolGetXMLDesc, /* 0.10.0 */ + .storagePoolGetAutostart = vzStoragePoolGetAutostart, /* 0.10.0 */ + .storagePoolSetAutostart = vzStoragePoolSetAutostart, /* 0.10.0 */ + .storagePoolNumOfVolumes = vzStoragePoolNumOfVolumes, /* 0.10.0 */ + .storagePoolListVolumes = vzStoragePoolListVolumes, /* 0.10.0 */ + + .storageVolLookupByName = vzStorageVolLookupByName, /* 0.10.0 */ + .storageVolLookupByKey = vzStorageVolLookupByKey, /* 0.10.0 */ + .storageVolLookupByPath = vzStorageVolLookupByPath, /* 0.10.0 */ + .storageVolCreateXML = vzStorageVolCreateXML, /* 0.10.0 */ + .storageVolCreateXMLFrom = vzStorageVolCreateXMLFrom, /* 0.10.0 */ + .storageVolDelete = vzStorageVolDelete, /* 0.10.0 */ + .storageVolGetInfo = vzStorageVolGetInfo, /* 0.10.0 */ + .storageVolGetXMLDesc = vzStorageVolGetXMLDesc, /* 0.10.0 */ + .storageVolGetPath = vzStorageVolGetPath, /* 0.10.0 */ + .storagePoolIsActive = vzStoragePoolIsActive, /* 0.10.0 */ + .storagePoolIsPersistent = vzStoragePoolIsPersistent, /* 0.10.0 */ +}; diff --git a/src/vz/vz_utils.c b/src/vz/vz_utils.c new file mode 100644 index 0000000000..08b7f5af86 --- /dev/null +++ b/src/vz/vz_utils.c @@ -0,0 +1,203 @@ +/* + * vz_utils.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 + * . + * + */ + +#include + +#include + +#include "vircommand.h" +#include "virerror.h" +#include "viralloc.h" +#include "virjson.h" +#include "vz_utils.h" +#include "virstring.h" +#include "datatypes.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +/** + * vzDomObjFromDomain: + * @domain: Domain pointer that has to be looked up + * + * This function looks up @domain and returns the appropriate virDomainObjPtr + * that has to be unlocked by virObjectUnlock(). + * + * Returns the domain object without incremented reference counter which is locked + * on success, NULL otherwise. + */ +virDomainObjPtr +vzDomObjFromDomain(virDomainPtr domain) +{ + virDomainObjPtr vm; + vzConnPtr privconn = domain->conn->privateData; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + vm = virDomainObjListFindByUUID(privconn->domains, domain->uuid); + if (!vm) { + virUUIDFormat(domain->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s' (%s)"), + uuidstr, domain->name); + return NULL; + } + + return vm; + +} + +/** + * vzDomObjFromDomainRef: + * @domain: Domain pointer that has to be looked up + * + * This function looks up @domain and returns the appropriate virDomainObjPtr + * that has to be released by calling virDomainObjEndAPI(). + * + * Returns the domain object with incremented reference counter which is locked + * on success, NULL otherwise. + */ +virDomainObjPtr +vzDomObjFromDomainRef(virDomainPtr domain) +{ + virDomainObjPtr vm; + vzConnPtr privconn = domain->conn->privateData; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + vm = virDomainObjListFindByUUIDRef(privconn->domains, domain->uuid); + if (!vm) { + virUUIDFormat(domain->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s' (%s)"), + uuidstr, domain->name); + return NULL; + } + + return vm; +} + +static int +vzDoCmdRun(char **outbuf, const char *binary, va_list list) +{ + virCommandPtr cmd = virCommandNewVAList(binary, list); + int ret = -1; + + if (outbuf) + virCommandSetOutputBuffer(cmd, outbuf); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCommandFree(cmd); + if (ret && outbuf) + VIR_FREE(*outbuf); + return ret; +} + +/* + * Run command and parse its JSON output, return + * pointer to virJSONValue or NULL in case of error. + */ +virJSONValuePtr +vzParseOutput(const char *binary, ...) +{ + char *outbuf; + virJSONValuePtr jobj = NULL; + va_list list; + int ret; + + va_start(list, binary); + ret = vzDoCmdRun(&outbuf, binary, list); + va_end(list); + if (ret) + return NULL; + + jobj = virJSONValueFromString(outbuf); + if (!jobj) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid output from prlctl: %s"), outbuf); + + VIR_FREE(outbuf); + return jobj; +} + +/* + * Run command and return its output, pointer to + * buffer or NULL in case of error. Caller os responsible + * for freeing the buffer. + */ +char * +vzGetOutput(const char *binary, ...) +{ + char *outbuf; + va_list list; + int ret; + + va_start(list, binary); + ret = vzDoCmdRun(&outbuf, binary, list); + va_end(list); + if (ret) + return NULL; + + return outbuf; +} + +/* + * Run prlctl command and check for errors + * + * Return value is 0 in case of success, else - -1 + */ +int +vzCmdRun(const char *binary, ...) +{ + int ret; + va_list list; + + va_start(list, binary); + ret = vzDoCmdRun(NULL, binary, list); + va_end(list); + + return ret; +} + +/* + * Return new file path in malloced string created by + * concatenating first and second function arguments. + */ +char * +vzAddFileExt(const char *path, const char *ext) +{ + char *new_path = NULL; + size_t len = strlen(path) + strlen(ext) + 1; + + if (VIR_ALLOC_N(new_path, len) < 0) + return NULL; + + if (!virStrcpy(new_path, path, len)) { + VIR_FREE(new_path); + return NULL; + } + strcat(new_path, ext); + + return new_path; +} diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h new file mode 100644 index 0000000000..9b46bf9ed1 --- /dev/null +++ b/src/vz/vz_utils.h @@ -0,0 +1,128 @@ +/* + * vz_utils.h: 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 + * . + * + */ + +#ifndef PARALLELS_UTILS_H +# define PARALLELS_UTILS_H + +# include + +# include "driver.h" +# include "conf/domain_conf.h" +# include "conf/storage_conf.h" +# include "conf/domain_event.h" +# include "conf/network_conf.h" +# include "virthread.h" +# include "virjson.h" + +# define vzParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + +# define IS_CT(def) (def->os.type == VIR_DOMAIN_OSTYPE_EXE) + +# define vzDomNotFoundError(domain) \ + do { \ + char uuidstr[VIR_UUID_STRING_BUFLEN]; \ + virUUIDFormat(domain->uuid, uuidstr); \ + virReportError(VIR_ERR_NO_DOMAIN, \ + _("no domain with matching uuid '%s'"), uuidstr); \ + } while (0) + +# define PARALLELS_DOMAIN_ROUTED_NETWORK_NAME "Routed" +# define PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME "Bridged" + +# define PARALLELS_REQUIRED_HOSTONLY_NETWORK "Host-Only" +# define PARALLELS_HOSTONLY_NETWORK_TYPE "host-only" +# define PARALLELS_REQUIRED_BRIDGED_NETWORK "Bridged" +# define PARALLELS_BRIDGED_NETWORK_TYPE "bridged" + +struct _vzConn { + virMutex lock; + + /* Immutable pointer, self-locking APIs */ + virDomainObjListPtr domains; + + PRL_HANDLE server; + virStoragePoolObjList pools; + virNetworkObjListPtr networks; + virCapsPtr caps; + virDomainXMLOptionPtr xmlopt; + virObjectEventStatePtr domainEventState; + virStorageDriverStatePtr storageState; + const char *drivername; +}; + +typedef struct _vzConn vzConn; +typedef struct _vzConn *vzConnPtr; + +struct _vzCountersCache { + PRL_HANDLE stats; + virCond cond; + // -1 - unsubscribed + // > -1 - subscribed + int count; +}; + +typedef struct _vzCountersCache vzCountersCache; + +struct vzDomObj { + int id; + char *uuid; + char *home; + PRL_HANDLE sdkdom; + vzCountersCache cache; +}; + +typedef struct vzDomObj *vzDomObjPtr; + +virDrvOpenStatus vzStorageOpen(virConnectPtr conn, unsigned int flags); +int vzStorageClose(virConnectPtr conn); +extern virStorageDriver vzStorageDriver; + +virDrvOpenStatus vzNetworkOpen(virConnectPtr conn, unsigned int flags); +int vzNetworkClose(virConnectPtr conn); +extern virNetworkDriver vzNetworkDriver; + +virDomainObjPtr vzDomObjFromDomain(virDomainPtr domain); +virDomainObjPtr vzDomObjFromDomainRef(virDomainPtr domain); + +virJSONValuePtr vzParseOutput(const char *binary, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; +char * vzGetOutput(const char *binary, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; +int vzCmdRun(const char *binary, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; +char * vzAddFileExt(const char *path, const char *ext); +void vzDriverLock(vzConnPtr driver); +void vzDriverUnlock(vzConnPtr driver); +virStorageVolPtr vzStorageVolLookupByPathLocked(virConnectPtr conn, + const char *path); +int vzStorageVolDefRemove(virStoragePoolObjPtr privpool, + virStorageVolDefPtr privvol); + +# define PARALLELS_BLOCK_STATS_FOREACH(OP) \ + OP(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ, "read_requests") \ + OP(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "read_total") \ + OP(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "write_requests") \ + OP(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "write_total") + +#endif