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
$(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) \
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 \
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
$(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) \
# 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"
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/poll.h>
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <pwd.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/statvfs.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef PARALLELS_DRIVER_H
-# define PARALLELS_DRIVER_H
-
-int vzRegister(void);
-
-#endif
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#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 */
-};
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-#include <stdarg.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <Parallels.h>
-
-#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);
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#include <stdlib.h>
-#include <dirent.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#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 */
-};
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#include <stdarg.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef PARALLELS_UTILS_H
-# define PARALLELS_UTILS_H
-
-# include <Parallels.h>
-
-# 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
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/statvfs.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PARALLELS_DRIVER_H
+# define PARALLELS_DRIVER_H
+
+int vzRegister(void);
+
+#endif
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#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 */
+};
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include <stdarg.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <Parallels.h>
+
+#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);
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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 */
+};
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <stdarg.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PARALLELS_UTILS_H
+# define PARALLELS_UTILS_H
+
+# include <Parallels.h>
+
+# 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