libvirt/src/parallels/parallels_driver.c
Peter Krempa bffb9163a1 conf: Add support for parsing and formatting max memory and slot count
Add a XML element that will allow to specify maximum supportable memory
and the count of memory slots to use with memory hotplug.

To avoid possible confusion and misuse of the new element this patch
also explicitly forbids the use of the maxMemory setting in individual
drivers's post parse callbacks. This limitation will be lifted when the
support is implemented.
2015-03-23 14:25:14 +01:00

1080 lines
29 KiB
C

/*
* 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 "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 parallelsConnectClose(virConnectPtr conn);
void
parallelsDriverLock(parallelsConnPtr driver)
{
virMutexLock(&driver->lock);
}
void
parallelsDriverUnlock(parallelsConnPtr driver)
{
virMutexUnlock(&driver->lock);
}
static virCapsPtr
parallelsBuildCapabilities(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, "hvm",
VIR_ARCH_X86_64,
"parallels",
NULL, 0, NULL)) == NULL)
goto error;
if ((guest = virCapabilitiesAddGuest(caps, "hvm",
VIR_ARCH_I686,
"parallels",
NULL, 0, NULL)) == NULL)
goto error;
if (virCapabilitiesAddGuestDomain(guest,
"parallels", NULL, NULL, 0, NULL) == NULL)
goto error;
if ((guest = virCapabilitiesAddGuest(caps, "exe",
VIR_ARCH_X86_64,
"parallels",
NULL, 0, NULL)) == NULL)
goto error;
if (virCapabilitiesAddGuestDomain(guest,
"parallels", 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 *
parallelsConnectGetCapabilities(virConnectPtr conn)
{
parallelsConnPtr privconn = conn->privateData;
char *xml;
parallelsDriverLock(privconn);
xml = virCapabilitiesFormatXML(privconn->caps);
parallelsDriverUnlock(privconn);
return xml;
}
static int
parallelsDomainDefPostParse(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
parallelsDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
const virDomainDef *def ATTRIBUTE_UNUSED,
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 &&
VIR_STRDUP(dev->data.net->model, "e1000") < 0)
goto cleanup;
ret = 0;
cleanup:
return ret;
}
virDomainDefParserConfig parallelsDomainDefParserConfig = {
.macPrefix = {0x42, 0x1C, 0x00},
.devicesPostParseCallback = parallelsDomainDeviceDefPostParse,
.domainPostParseCallback = parallelsDomainDefPostParse,
};
static int
parallelsOpenDefault(virConnectPtr conn)
{
parallelsConnPtr 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;
}
if (prlsdkInit(privconn)) {
VIR_DEBUG("%s", _("Can't initialize Parallels SDK"));
goto err_free;
}
if (prlsdkConnect(privconn) < 0)
goto err_free;
if (!(privconn->caps = parallelsBuildCapabilities()))
goto error;
if (!(privconn->xmlopt = virDomainXMLOptionNew(&parallelsDomainDefParserConfig,
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
parallelsConnectOpen(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 || STRNEQ(conn->uri->scheme, "parallels"))
return VIR_DRV_OPEN_DECLINED;
/* Remote driver should handle these. */
if (conn->uri->server)
return VIR_DRV_OPEN_DECLINED;
/* From this point on, the connection is for us. */
if (!STREQ_NULLABLE(conn->uri->path, "/system")) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected Parallels URI path '%s', try parallels:///system"),
conn->uri->path);
return VIR_DRV_OPEN_ERROR;
}
if ((ret = parallelsOpenDefault(conn)) != VIR_DRV_OPEN_SUCCESS ||
(ret = parallelsStorageOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS ||
(ret = parallelsNetworkOpen(conn, flags)) != VIR_DRV_OPEN_SUCCESS) {
parallelsConnectClose(conn);
return ret;
}
return VIR_DRV_OPEN_SUCCESS;
}
static int
parallelsConnectClose(virConnectPtr conn)
{
parallelsConnPtr privconn = conn->privateData;
if (!privconn)
return 0;
parallelsNetworkClose(conn);
parallelsStorageClose(conn);
parallelsDriverLock(privconn);
prlsdkUnsubscribeFromPCSEvents(privconn);
virObjectUnref(privconn->caps);
virObjectUnref(privconn->xmlopt);
virObjectUnref(privconn->domains);
virObjectEventStateFree(privconn->domainEventState);
prlsdkDisconnect(privconn);
conn->privateData = NULL;
prlsdkDeinit();
parallelsDriverUnlock(privconn);
virMutexDestroy(&privconn->lock);
VIR_FREE(privconn);
return 0;
}
static int
parallelsConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
{
char *output, *sVer, *tmp;
const char *searchStr = "prlsrvctl version ";
int ret = -1;
output = parallelsGetOutput(PRLSRVCTL, "--help", NULL);
if (!output) {
parallelsParseError();
goto cleanup;
}
if (!(sVer = strstr(output, searchStr))) {
parallelsParseError();
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, '.'))) {
parallelsParseError();
goto cleanup;
}
if (!(tmp = strchr(tmp + 1, '.'))) {
parallelsParseError();
goto cleanup;
}
tmp[0] = '\0';
if (virParseVersionString(sVer, hvVer, true) < 0) {
parallelsParseError();
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(output);
return ret;
}
static char *parallelsConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return virGetHostname();
}
static int
parallelsConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
parallelsConnPtr privconn = conn->privateData;
int n;
parallelsDriverLock(privconn);
n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
NULL, NULL);
parallelsDriverUnlock(privconn);
return n;
}
static int
parallelsConnectNumOfDomains(virConnectPtr conn)
{
parallelsConnPtr privconn = conn->privateData;
int count;
parallelsDriverLock(privconn);
count = virDomainObjListNumOfDomains(privconn->domains, true,
NULL, NULL);
parallelsDriverUnlock(privconn);
return count;
}
static int
parallelsConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
{
parallelsConnPtr privconn = conn->privateData;
int n;
parallelsDriverLock(privconn);
memset(names, 0, sizeof(*names) * maxnames);
n = virDomainObjListGetInactiveNames(privconn->domains, names,
maxnames, NULL, NULL);
parallelsDriverUnlock(privconn);
return n;
}
static int
parallelsConnectNumOfDefinedDomains(virConnectPtr conn)
{
parallelsConnPtr privconn = conn->privateData;
int count;
parallelsDriverLock(privconn);
count = virDomainObjListNumOfDomains(privconn->domains, false,
NULL, NULL);
parallelsDriverUnlock(privconn);
return count;
}
static int
parallelsConnectListAllDomains(virConnectPtr conn,
virDomainPtr **domains,
unsigned int flags)
{
parallelsConnPtr privconn = conn->privateData;
int ret = -1;
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
parallelsDriverLock(privconn);
ret = virDomainObjListExport(privconn->domains, conn, domains,
NULL, flags);
parallelsDriverUnlock(privconn);
return ret;
}
static virDomainPtr
parallelsDomainLookupByID(virConnectPtr conn, int id)
{
parallelsConnPtr privconn = conn->privateData;
virDomainPtr ret = NULL;
virDomainObjPtr dom;
parallelsDriverLock(privconn);
dom = virDomainObjListFindByID(privconn->domains, id);
parallelsDriverUnlock(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
parallelsDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
parallelsConnPtr privconn = conn->privateData;
virDomainPtr ret = NULL;
virDomainObjPtr dom;
parallelsDriverLock(privconn);
dom = virDomainObjListFindByUUID(privconn->domains, uuid);
parallelsDriverUnlock(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
parallelsDomainLookupByName(virConnectPtr conn, const char *name)
{
parallelsConnPtr privconn = conn->privateData;
virDomainPtr ret = NULL;
virDomainObjPtr dom;
parallelsDriverLock(privconn);
dom = virDomainObjListFindByName(privconn->domains, name);
parallelsDriverUnlock(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:
if (dom)
virObjectUnlock(dom);
return ret;
}
static int
parallelsDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
int ret = -1;
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
parallelsDriverUnlock(privconn);
if (privdom == NULL) {
parallelsDomNotFoundError(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 *
parallelsDomainGetOSType(virDomainPtr domain)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
char *ret = NULL;
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
if (privdom == NULL) {
parallelsDomNotFoundError(domain);
goto cleanup;
}
ignore_value(VIR_STRDUP(ret, privdom->def->os.type));
cleanup:
if (privdom)
virObjectUnlock(privdom);
parallelsDriverUnlock(privconn);
return ret;
}
static int
parallelsDomainIsPersistent(virDomainPtr domain)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
int ret = -1;
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
if (privdom == NULL) {
parallelsDomNotFoundError(domain);
goto cleanup;
}
ret = 1;
cleanup:
if (privdom)
virObjectUnlock(privdom);
parallelsDriverUnlock(privconn);
return ret;
}
static int
parallelsDomainGetState(virDomainPtr domain,
int *state, int *reason, unsigned int flags)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
int ret = -1;
virCheckFlags(0, -1);
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
parallelsDriverUnlock(privconn);
if (privdom == NULL) {
parallelsDomNotFoundError(domain);
goto cleanup;
}
*state = virDomainObjGetState(privdom, reason);
ret = 0;
cleanup:
if (privdom)
virObjectUnlock(privdom);
return ret;
}
static char *
parallelsDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainDefPtr def;
virDomainObjPtr privdom;
char *ret = NULL;
/* Flags checked by virDomainDefFormat */
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
parallelsDriverUnlock(privconn);
if (privdom == NULL) {
parallelsDomNotFoundError(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
parallelsDomainGetAutostart(virDomainPtr domain, int *autostart)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
int ret = -1;
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
parallelsDriverUnlock(privconn);
if (privdom == NULL) {
parallelsDomNotFoundError(domain);
goto cleanup;
}
*autostart = privdom->autostart;
ret = 0;
cleanup:
if (privdom)
virObjectUnlock(privdom);
return ret;
}
static virDomainPtr
parallelsDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
{
parallelsConnPtr 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;
parallelsDriverLock(privconn);
if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
1 << VIR_DOMAIN_VIRT_PARALLELS,
parse_flags)) == NULL)
goto cleanup;
olddom = virDomainObjListFindByUUID(privconn->domains, def->uuid);
if (olddom == NULL) {
virResetLastError();
if (STREQ(def->os.type, "hvm")) {
if (prlsdkCreateVm(conn, def))
goto cleanup;
} else if (STREQ(def->os.type, "exe")) {
if (prlsdkCreateCt(conn, def))
goto cleanup;
} else {
virReportError(VIR_ERR_INVALID_ARG,
_("Unsupported OS type: %s"), def->os.type);
goto cleanup;
}
olddom = prlsdkAddDomain(privconn, def->uuid);
if (!olddom)
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);
parallelsDriverUnlock(privconn);
return retdom;
}
static virDomainPtr
parallelsDomainDefineXML(virConnectPtr conn, const char *xml)
{
return parallelsDomainDefineXMLFlags(conn, xml, 0);
}
static int
parallelsNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeInfoPtr nodeinfo)
{
return nodeGetInfo(nodeinfo);
}
static int parallelsConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Encryption is not relevant / applicable to way we talk to PCS */
return 0;
}
static int parallelsConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* We run CLI tools directly so this is secure */
return 1;
}
static int parallelsConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return 1;
}
static char *
parallelsConnectBaselineCPU(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
parallelsDomainGetVcpus(virDomainPtr domain,
virVcpuInfoPtr info,
int maxinfo,
unsigned char *cpumaps,
int maplen)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom = NULL;
size_t i;
int v, maxcpu, hostcpus;
int ret = -1;
parallelsDriverLock(privconn);
privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
parallelsDriverUnlock(privconn);
if (privdom == NULL) {
parallelsDomNotFoundError(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
parallelsNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags)
{
return nodeGetCPUMap(cpumap, online, flags);
}
static int
parallelsConnectDomainEventRegisterAny(virConnectPtr conn,
virDomainPtr domain,
int eventID,
virConnectDomainEventGenericCallback callback,
void *opaque,
virFreeCallback freecb)
{
int ret = -1;
parallelsConnPtr privconn = conn->privateData;
if (virDomainEventStateRegisterID(conn,
privconn->domainEventState,
domain, eventID,
callback, opaque, freecb, &ret) < 0)
ret = -1;
return ret;
}
static int
parallelsConnectDomainEventDeregisterAny(virConnectPtr conn,
int callbackID)
{
parallelsConnPtr privconn = conn->privateData;
int ret = -1;
if (virObjectEventStateDeregisterID(conn,
privconn->domainEventState,
callbackID) < 0)
goto cleanup;
ret = 0;
cleanup:
return ret;
}
static int parallelsDomainSuspend(virDomainPtr domain)
{
return prlsdkDomainChangeState(domain, prlsdkPause);
}
static int parallelsDomainResume(virDomainPtr domain)
{
return prlsdkDomainChangeState(domain, prlsdkResume);
}
static int parallelsDomainCreate(virDomainPtr domain)
{
return prlsdkDomainChangeState(domain, prlsdkStart);
}
static int parallelsDomainDestroy(virDomainPtr domain)
{
return prlsdkDomainChangeState(domain, prlsdkKill);
}
static int parallelsDomainShutdown(virDomainPtr domain)
{
return prlsdkDomainChangeState(domain, prlsdkStop);
}
static int parallelsDomainIsActive(virDomainPtr domain)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr dom = NULL;
int ret = -1;
dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
if (dom == NULL) {
parallelsDomNotFoundError(domain);
return -1;
}
ret = virDomainObjIsActive(dom);
virObjectUnlock(dom);
return ret;
}
static int
parallelsDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
{
/* we don't support any create flags */
virCheckFlags(0, -1);
return parallelsDomainCreate(domain);
}
static int
parallelsDomainUndefineFlags(virDomainPtr domain,
unsigned int flags)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr dom = NULL;
int ret;
virCheckFlags(0, -1);
dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
if (dom == NULL) {
parallelsDomNotFoundError(domain);
return -1;
}
ret = prlsdkUnregisterDomain(privconn, dom);
if (ret)
virObjectUnlock(dom);
return ret;
}
static int
parallelsDomainUndefine(virDomainPtr domain)
{
return parallelsDomainUndefineFlags(domain, 0);
}
static int
parallelsDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
{
parallelsConnPtr privconn = domain->conn->privateData;
virDomainObjPtr dom = NULL;
virCheckFlags(0, -1);
dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
if (dom == NULL) {
parallelsDomNotFoundError(domain);
return -1;
}
virObjectUnlock(dom);
return 0;
}
static virHypervisorDriver parallelsDriver = {
.name = "Parallels",
.connectOpen = parallelsConnectOpen, /* 0.10.0 */
.connectClose = parallelsConnectClose, /* 0.10.0 */
.connectGetVersion = parallelsConnectGetVersion, /* 0.10.0 */
.connectGetHostname = parallelsConnectGetHostname, /* 0.10.0 */
.nodeGetInfo = parallelsNodeGetInfo, /* 0.10.0 */
.connectGetCapabilities = parallelsConnectGetCapabilities, /* 0.10.0 */
.connectBaselineCPU = parallelsConnectBaselineCPU, /* 1.2.6 */
.connectListDomains = parallelsConnectListDomains, /* 0.10.0 */
.connectNumOfDomains = parallelsConnectNumOfDomains, /* 0.10.0 */
.connectListDefinedDomains = parallelsConnectListDefinedDomains, /* 0.10.0 */
.connectNumOfDefinedDomains = parallelsConnectNumOfDefinedDomains, /* 0.10.0 */
.connectListAllDomains = parallelsConnectListAllDomains, /* 0.10.0 */
.domainLookupByID = parallelsDomainLookupByID, /* 0.10.0 */
.domainLookupByUUID = parallelsDomainLookupByUUID, /* 0.10.0 */
.domainLookupByName = parallelsDomainLookupByName, /* 0.10.0 */
.domainGetOSType = parallelsDomainGetOSType, /* 0.10.0 */
.domainGetInfo = parallelsDomainGetInfo, /* 0.10.0 */
.domainGetState = parallelsDomainGetState, /* 0.10.0 */
.domainGetXMLDesc = parallelsDomainGetXMLDesc, /* 0.10.0 */
.domainIsPersistent = parallelsDomainIsPersistent, /* 0.10.0 */
.domainGetAutostart = parallelsDomainGetAutostart, /* 0.10.0 */
.domainGetVcpus = parallelsDomainGetVcpus, /* 1.2.6 */
.domainSuspend = parallelsDomainSuspend, /* 0.10.0 */
.domainResume = parallelsDomainResume, /* 0.10.0 */
.domainDestroy = parallelsDomainDestroy, /* 0.10.0 */
.domainShutdown = parallelsDomainShutdown, /* 0.10.0 */
.domainCreate = parallelsDomainCreate, /* 0.10.0 */
.domainCreateWithFlags = parallelsDomainCreateWithFlags, /* 1.2.10 */
.domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */
.domainDefineXMLFlags = parallelsDomainDefineXMLFlags, /* 1.2.12 */
.domainUndefine = parallelsDomainUndefine, /* 1.2.10 */
.domainUndefineFlags = parallelsDomainUndefineFlags, /* 1.2.10 */
.domainIsActive = parallelsDomainIsActive, /* 1.2.10 */
.connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */
.connectDomainEventDeregisterAny = parallelsConnectDomainEventDeregisterAny, /* 1.2.10 */
.nodeGetCPUMap = parallelsNodeGetCPUMap, /* 1.2.8 */
.connectIsEncrypted = parallelsConnectIsEncrypted, /* 1.2.5 */
.connectIsSecure = parallelsConnectIsSecure, /* 1.2.5 */
.connectIsAlive = parallelsConnectIsAlive, /* 1.2.5 */
.domainHasManagedSaveImage = parallelsDomainHasManagedSaveImage, /* 1.2.13 */
};
static virConnectDriver parallelsConnectDriver = {
.hypervisorDriver = &parallelsDriver,
.storageDriver = &parallelsStorageDriver,
.networkDriver = &parallelsNetworkDriver,
};
/**
* parallelsRegister:
*
* Registers the parallels driver
*/
int
parallelsRegister(void)
{
char *prlctl_path;
prlctl_path = virFindFileInPath(PRLCTL);
if (!prlctl_path) {
VIR_DEBUG("%s", _("Can't find prlctl command in the PATH env"));
return 0;
}
VIR_FREE(prlctl_path);
if (virRegisterConnectDriver(&parallelsConnectDriver, false) < 0)
return -1;
return 0;
}