[libvirt] [PATCH 00/12] parallels: use SDK in parallels_driver.c

This patch series replaces all code, which used prlctl command to interact with parallels cloud server with calls to parallels sdk functions. The model of this driver remain almost the same - in creates a list of virDomainObj objects on connect and then functions, which returns different information get info from this list. But functions, which modify domains (change state, define or undefine domain) don't modify this list directly. On connect driver subscribes to event from PCS and modify the list from that events handler. So cached list of domains will be always up-to-date either after modifications from currect connection or after modifications by another tools (like prlctl) or libvirt connections. Alexander Burluka (4): parallels: get domain info with SDK parallels: handle events from parallels server parallels: added function virDomainIsActive() parallels: Add domainCreateWithFlags() function. Dmitry Guryanov (8): parallels: move IS_CT macro to parallels_utils.h parallels: move parallelsDomNotFoundError to parallels_utils.h parallels: reimplement functions, which change domain state parallels: rewrite parallelsApplyConfig with SDK parallels: create VMs and containers with sdk parallels: fix parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags src/parallels/parallels_driver.c | 2448 +++++++------------------------------ src/parallels/parallels_sdk.c | 2456 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 19 + src/parallels/parallels_utils.h | 11 + 4 files changed, 2939 insertions(+), 1995 deletions(-) -- 1.9.3

This macro will be used in paralles_sdk.c so move it to common header. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 2 -- src/parallels/parallels_utils.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 04c4bb3..1760d08 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -72,8 +72,6 @@ VIR_LOG_INIT("parallels.parallels_driver"); _("no domain with matching uuid '%s'"), uuidstr); \ } while (0) -#define IS_CT(def) (STREQ_NULLABLE(def->os.type, "exe")) - static int parallelsConnectClose(virConnectPtr conn); static const char * parallelsGetDiskBusName(int bus) { diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index aef590f..269020a 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -37,6 +37,8 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output")) +#define IS_CT(def) (STREQ_NULLABLE(def->os.type, "exe")) + # define PARALLELS_ROUTED_NETWORK_NAME "Routed" struct _parallelsConn { -- 1.9.3

From: Alexander Burluka <aburluka@parallels.com> Obtain information about domains using parallels sdk instead of prlctl. prlsdkLoadDomains functions behaves as former parallelsLoadDomains with NULL as second parameter (name) - it fills parallelsConn.domains list. prlsdkLoadDomain is now able update specified domain by given virDomainObjPtr. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 747 +--------------------------- src/parallels/parallels_sdk.c | 1002 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 4 + src/parallels/parallels_utils.h | 1 + 4 files changed, 1013 insertions(+), 741 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 1760d08..7a60401 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -49,7 +49,6 @@ #include "virfile.h" #include "virstoragefile.h" #include "nodeinfo.h" -#include "c-ctype.h" #include "virstring.h" #include "cpu/cpu.h" @@ -99,21 +98,6 @@ parallelsDriverUnlock(parallelsConnPtr driver) virMutexUnlock(&driver->lock); } - -static void -parallelsDomObjFreePrivate(void *p) -{ - parallelsDomObjPtr pdom = p; - - if (!pdom) - return; - - virBitmapFree(pdom->cpumask); - VIR_FREE(pdom->uuid); - VIR_FREE(pdom->home); - VIR_FREE(p); -}; - static virCapsPtr parallelsBuildCapabilities(void) { @@ -191,729 +175,6 @@ parallelsConnectGetCapabilities(virConnectPtr conn) } static int -parallelsGetSerialInfo(virDomainChrDefPtr chr, - const char *name, virJSONValuePtr value) -{ - const char *tmp; - - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; - if (virStrToLong_i(name + strlen("serial"), - NULL, 10, &chr->target.port) < 0) { - parallelsParseError(); - return -1; - } - - if (virJSONValueObjectHasKey(value, "output")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_FILE; - - tmp = virJSONValueObjectGetString(value, "output"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.file.path, tmp) < 0) - return -1; - } else if (virJSONValueObjectHasKey(value, "socket")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_UNIX; - - tmp = virJSONValueObjectGetString(value, "socket"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.nix.path, tmp) < 0) - return -1; - chr->source.data.nix.listen = false; - } else if (virJSONValueObjectHasKey(value, "real")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_DEV; - - tmp = virJSONValueObjectGetString(value, "real"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.file.path, tmp) < 0) - return -1; - } else { - parallelsParseError(); - return -1; - } - - return 0; -} - -static int -parallelsAddSerialInfo(virDomainChrDefPtr **serials, size_t *nserials, - const char *key, virJSONValuePtr value) -{ - virDomainChrDefPtr chr = NULL; - - if (!(chr = virDomainChrDefNew())) - goto cleanup; - - if (parallelsGetSerialInfo(chr, key, value)) - goto cleanup; - - if (VIR_APPEND_ELEMENT(*serials, *nserials, chr) < 0) - goto cleanup; - - return 0; - - cleanup: - virDomainChrDefFree(chr); - return -1; -} - -static int -parallelsAddVideoInfo(virDomainDefPtr def, virJSONValuePtr value) -{ - virDomainVideoDefPtr video = NULL; - virDomainVideoAccelDefPtr accel = NULL; - const char *tmp; - char *endptr; - unsigned long mem; - - if (!(tmp = virJSONValueObjectGetString(value, "size"))) { - parallelsParseError(); - goto error; - } - - if (virStrToLong_ul(tmp, &endptr, 10, &mem) < 0) { - parallelsParseError(); - goto error; - } - - if (!STREQ(endptr, "Mb")) { - parallelsParseError(); - goto 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 = mem << 20; - video->heads = 1; - video->accel = accel; - - return 0; - - error: - VIR_FREE(accel); - virDomainVideoDefFree(video); - return -1; -} - -static int -parallelsGetHddInfo(virDomainDefPtr def, - virDomainDiskDefPtr disk, - const char *key, - virJSONValuePtr value) -{ - const char *tmp; - unsigned int idx; - - disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; - - if (virJSONValueObjectHasKey(value, "real") == 1) { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); - - if (!(tmp = virJSONValueObjectGetString(value, "real"))) { - parallelsParseError(); - return -1; - } - - if (virDomainDiskSetSource(disk, tmp) < 0) - return -1; - } else { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); - - if (!(tmp = virJSONValueObjectGetString(value, "image"))) { - parallelsParseError(); - return -1; - } - - if (virDomainDiskSetSource(disk, tmp) < 0) - return -1; - - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); - } - - tmp = virJSONValueObjectGetString(value, "port"); - if (!tmp && !IS_CT(def)) { - parallelsParseError(); - return -1; - } - - if (tmp) { - if (STRPREFIX(tmp, "ide")) { - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - } else if (STRPREFIX(tmp, "sata")) { - disk->bus = VIR_DOMAIN_DISK_BUS_SATA; - } else if (STRPREFIX(tmp, "scsi")) { - disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; - } else { - parallelsParseError(); - return -1; - } - - char *colonp; - unsigned int pos; - - if (!(colonp = strchr(tmp, ':'))) { - parallelsParseError(); - return -1; - } - - if (virStrToLong_ui(colonp + 1, NULL, 10, &pos) < 0) { - parallelsParseError(); - return -1; - } - - disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; - disk->info.addr.drive.target = pos; - } else { - /* Actually there are no disk devices in containers, but in - * in Parallels Cloud Server we mount disk images as container's - * root fs during start, so it looks like a disk device. */ - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - } - - if (virStrToLong_ui(key + strlen("hdd"), NULL, 10, &idx) < 0) { - parallelsParseError(); - return -1; - } - - if (!(disk->dst = virIndexToDiskName(idx, "sd"))) - return -1; - - return 0; -} - -static int -parallelsAddHddInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) -{ - virDomainDiskDefPtr disk = NULL; - - if (!(disk = virDomainDiskDefNew())) - goto error; - - if (parallelsGetHddInfo(def, disk, key, value)) - goto error; - - if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) - goto error; - - return 0; - - error: - virDomainDiskDefFree(disk); - return -1; -} - -static inline unsigned char hex2int(char c) -{ - if (c <= '9') - return c - '0'; - else - return 10 + c - 'A'; -} - -/* - * Parse MAC address in format XXXXXXXXXXXX. - */ -static int -parallelsMacAddrParse(const char *str, virMacAddrPtr addr) -{ - size_t i; - - if (strlen(str) != 12) - goto error; - - for (i = 0; i < 6; i++) { - if (!c_isxdigit(str[2 * i]) || !c_isxdigit(str[2 * i + 1])) - goto error; - - addr->addr[i] = (hex2int(str[2 * i]) << 4) + hex2int(str[2 * i + 1]); - } - - return 0; - error: - virReportError(VIR_ERR_INVALID_ARG, - _("Invalid MAC address format '%s'"), str); - return -1; -} - -static int -parallelsGetNetInfo(virDomainNetDefPtr net, - const char *key, - virJSONValuePtr value) -{ - const char *tmp; - - /* use device name, shown by prlctl as target device - * for identifying network adapter in virDomainDefineXML */ - if (VIR_STRDUP(net->ifname, key) < 0) - goto error; - - net->type = VIR_DOMAIN_NET_TYPE_NETWORK; - - if (!(tmp = virJSONValueObjectGetString(value, "mac"))) { - parallelsParseError(); - return -1; - } - - if (parallelsMacAddrParse(tmp, &net->mac) < 0) { - parallelsParseError(); - goto error; - } - - - if (virJSONValueObjectHasKey(value, "network")) { - if (!(tmp = virJSONValueObjectGetString(value, "network"))) { - parallelsParseError(); - goto error; - } - - if (VIR_STRDUP(net->data.network.name, tmp) < 0) - goto error; - } else if (virJSONValueObjectHasKey(value, "type")) { - if (!(tmp = virJSONValueObjectGetString(value, "type"))) { - parallelsParseError(); - goto error; - } - - if (!STREQ(tmp, "routed")) { - parallelsParseError(); - goto error; - } - - if (VIR_STRDUP(net->data.network.name, - PARALLELS_ROUTED_NETWORK_NAME) < 0) - goto error; - } else { - parallelsParseError(); - goto error; - } - - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; - if ((tmp = virJSONValueObjectGetString(value, "state")) && - STREQ(tmp, "disconnected")) { - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; - } - - return 0; - - error: - return -1; -} - -static int -parallelsAddNetInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) -{ - virDomainNetDefPtr net = NULL; - - if (VIR_ALLOC(net) < 0) - goto error; - - if (parallelsGetNetInfo(net, key, value)) - goto error; - - if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) - goto error; - - def->nets[def->nnets - 1] = net; - - return 0; - - error: - virDomainNetDefFree(net); - return -1; -} - -static int -parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) -{ - int n; - size_t i; - virJSONValuePtr value; - const char *key; - - n = virJSONValueObjectKeysNumber(jobj); - if (n < 1) - goto cleanup; - - for (i = 0; i < n; i++) { - key = virJSONValueObjectGetKey(jobj, i); - value = virJSONValueObjectGetValue(jobj, i); - - if (STRPREFIX(key, "serial")) { - if (parallelsAddSerialInfo(&def->serials, - &def->nserials, key, value)) - goto cleanup; - if (def->nconsoles == 0) { - if (parallelsAddSerialInfo(&def->consoles, - &def->nconsoles, key, value)) - goto cleanup; - } - } else if (STREQ(key, "video")) { - if (parallelsAddVideoInfo(def, value)) - goto cleanup; - } else if (STRPREFIX(key, "hdd")) { - if (parallelsAddHddInfo(def, key, value)) - goto cleanup; - } else if (STRPREFIX(key, "net")) { - if (parallelsAddNetInfo(def, key, value)) - goto cleanup; - } - } - - return 0; - - cleanup: - return -1; -} - -static int -parallelsAddVNCInfo(virDomainDefPtr def, virJSONValuePtr jobj_root) -{ - const char *tmp; - unsigned int port; - virJSONValuePtr jobj; - int ret = -1; - virDomainGraphicsDefPtr gr = NULL; - - jobj = virJSONValueObjectGet(jobj_root, "Remote display"); - if (!jobj) { - parallelsParseError(); - goto cleanup; - } - - tmp = virJSONValueObjectGetString(jobj, "mode"); - if (!tmp) { - parallelsParseError(); - goto cleanup; - } - - if (STREQ(tmp, "off")) { - ret = 0; - goto cleanup; - } - - if (VIR_ALLOC(gr) < 0) - goto cleanup; - - if (STREQ(tmp, "auto")) { - if (virJSONValueObjectGetNumberUint(jobj, "port", &port) < 0) - port = 0; - gr->data.vnc.autoport = true; - } else { - if (virJSONValueObjectGetNumberUint(jobj, "port", &port) < 0) { - parallelsParseError(); - goto cleanup; - } - gr->data.vnc.autoport = false; - } - - 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 (!(tmp = virJSONValueObjectGetString(jobj, "address"))) { - parallelsParseError(); - goto cleanup; - } - - if (VIR_ALLOC(gr->listens) < 0) - goto cleanup; - - gr->nListens = 1; - - if (VIR_STRDUP(gr->listens[0].address, tmp) < 0) - goto cleanup; - - gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; - - if (VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr) < 0) - goto cleanup; - - return 0; - - cleanup: - virDomainGraphicsDefFree(gr); - return ret; -} - -/* - * Must be called with privconn->lock held - */ -static virDomainObjPtr -parallelsLoadDomain(parallelsConnPtr privconn, virJSONValuePtr jobj) -{ - virDomainObjPtr dom = NULL; - virDomainDefPtr def = NULL; - parallelsDomObjPtr pdom = NULL; - virJSONValuePtr jobj2, jobj3; - const char *tmp; - char *endptr; - unsigned long mem; - unsigned int x; - const char *autostart; - const char *state; - int hostcpus; - - if (VIR_ALLOC(def) < 0) - goto cleanup; - - if (VIR_ALLOC(pdom) < 0) - goto cleanup; - - def->virtType = VIR_DOMAIN_VIRT_PARALLELS; - def->id = -1; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Name"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(def->name, tmp) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj, "ID"))) { - parallelsParseError(); - goto cleanup; - } - - if (virUUIDParse(tmp, def->uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("UUID in config file malformed")); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj, "Description"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(def->description, tmp) < 0) - goto cleanup; - - if (!(jobj2 = virJSONValueObjectGet(jobj, "Hardware"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(jobj3 = virJSONValueObjectGet(jobj2, "cpu"))) { - parallelsParseError(); - goto cleanup; - } - - if (virJSONValueObjectGetNumberUint(jobj3, "cpus", &x) == 0) { - def->vcpus = x; - def->maxvcpus = x; - } else if ((tmp = virJSONValueObjectGetString(jobj3, "cpus"))) { - if (STREQ(tmp, "unlimited")) { - virNodeInfo nodeinfo; - - if (nodeGetInfo(&nodeinfo) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Can't get node info")); - goto cleanup; - } - - def->vcpus = nodeinfo.cpus; - def->maxvcpus = def->vcpus; - } else { - parallelsParseError(); - goto cleanup; - } - } else { - parallelsParseError(); - goto cleanup; - } - - if ((hostcpus = nodeGetCPUCount()) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj3, "mask"))) { - /* Absence of this field means that all domains cpus are available */ - if (!(pdom->cpumask = virBitmapNew(hostcpus))) - goto cleanup; - virBitmapSetAll(pdom->cpumask); - } else { - if (virBitmapParse(tmp, 0, &pdom->cpumask, hostcpus) < 0) - goto cleanup; - } - - if (!(jobj3 = virJSONValueObjectGet(jobj2, "memory"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj3, "size"))) { - parallelsParseError(); - goto cleanup; - } - - if (virStrToLong_ul(tmp, &endptr, 10, &mem) < 0) { - parallelsParseError(); - goto cleanup; - } - - if (!STREQ(endptr, "Mb")) { - parallelsParseError(); - goto cleanup; - } - - def->mem.max_balloon = mem; - def->mem.max_balloon <<= 10; - def->mem.cur_balloon = def->mem.max_balloon; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { - parallelsParseError(); - goto cleanup; - } - - if (STREQ(tmp, "CT")) { - if (VIR_STRDUP(def->os.type, "exe") < 0) - goto cleanup; - if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) - goto cleanup; - } else if (STREQ(tmp, "VM")) { - if (VIR_STRDUP(def->os.type, "hvm") < 0) - goto cleanup; - } - - def->os.arch = VIR_ARCH_X86_64; - - if (virJSONValueObjectGetNumberUint(jobj, "EnvID", &x) < 0) - goto cleanup; - pdom->id = x; - if (!(tmp = virJSONValueObjectGetString(jobj, "ID"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(pdom->uuid, tmp) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Home"))) { - parallelsParseError(); - goto cleanup; - } - - if (VIR_STRDUP(pdom->home, tmp) < 0) - goto cleanup; - - if (!(state = virJSONValueObjectGetString(jobj, "State"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(autostart = virJSONValueObjectGetString(jobj, "Autostart"))) { - parallelsParseError(); - goto cleanup; - } - - if (parallelsAddDomainHardware(def, jobj2) < 0) - goto cleanup; - - if (parallelsAddVNCInfo(def, jobj) < 0) - goto cleanup; - - if (!(dom = virDomainObjListAdd(privconn->domains, def, - privconn->xmlopt, - 0, NULL))) - goto cleanup; - /* dom is locked here */ - - dom->privateDataFreeFunc = parallelsDomObjFreePrivate; - dom->privateData = pdom; - dom->persistent = 1; - - /* TODO: handle all possible states */ - if (STREQ(state, "running")) { - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_BOOTED); - def->id = pdom->id; - } - - if (STREQ(autostart, "on")) - dom->autostart = 1; - else - dom->autostart = 0; - - virObjectUnlock(dom); - - return dom; - - cleanup: - virDomainDefFree(def); - parallelsDomObjFreePrivate(pdom); - return NULL; -} - -/* - * Must be called with privconn->lock held - * - * if domain_name is NULL - load information about all - * registered domains. - */ -static int -parallelsLoadDomains(parallelsConnPtr privconn, const char *domain_name) -{ - int count; - size_t i; - virJSONValuePtr jobj; - virJSONValuePtr jobj2; - virDomainObjPtr dom = NULL; - int ret = -1; - - jobj = parallelsParseOutput(PRLCTL, "list", "-j", "-a", "-i", "-H", - "--vmtype", "all", domain_name, NULL); - if (!jobj) { - parallelsParseError(); - goto cleanup; - } - - count = virJSONValueArraySize(jobj); - if (count < 0) { - parallelsParseError(); - goto cleanup; - } - - for (i = 0; i < count; i++) { - jobj2 = virJSONValueArrayGet(jobj, i); - if (!jobj2) { - parallelsParseError(); - goto cleanup; - } - - dom = parallelsLoadDomain(privconn, jobj2); - if (!dom) - goto cleanup; - } - - ret = 0; - - cleanup: - virJSONValueFree(jobj); - return ret; -} - - -static int parallelsDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED, virCapsPtr caps ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) @@ -972,7 +233,7 @@ parallelsOpenDefault(virConnectPtr conn) conn->privateData = privconn; - if (parallelsLoadDomains(privconn, NULL)) + if (prlsdkLoadDomains(privconn)) goto error; return VIR_DRV_OPEN_SUCCESS; @@ -2292,6 +1553,7 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) virDomainPtr ret = NULL; virDomainDefPtr def; virDomainObjPtr olddom = NULL; + virDomainObjPtr dom = NULL; parallelsDriverLock(privconn); if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, @@ -2316,7 +1578,10 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) _("Unsupported OS type: %s"), def->os.type); goto cleanup; } - if (parallelsLoadDomains(privconn, def->name)) + dom = prlsdkAddDomain(privconn, def->uuid); + if (dom) + virObjectUnlock(dom); + else goto cleanup; olddom = virDomainObjListFindByName(privconn->domains, def->name); if (!olddom) { diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 1c77d27..a05cdb3 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -24,6 +24,9 @@ #include "virerror.h" #include "viralloc.h" +#include "virstring.h" +#include "nodeinfo.h" +#include "virlog.h" #include "parallels_sdk.h" @@ -32,6 +35,8 @@ PRL_UINT32 defaultJobTimeout = JOB_INFINIT_WAIT_TIMEOUT; +VIR_LOG_INIT("parallels.sdk"); + /* * Log error description */ @@ -72,6 +77,14 @@ logPrlErrorHelper(PRL_RESULT err, const char *filename, 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) @@ -239,3 +252,992 @@ prlsdkDisconnect(parallelsConnPtr privconn) PrlHandle_Free(privconn->server); } + +int +prlsdkSdkDomainLookup(parallelsConnPtr 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 (!(result = getJobResult(job, privconn->jobTimeout))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(result); + return ret; +} + +PRL_HANDLE +prlsdkSdkDomainLookupByUUID(parallelsConnPtr privconn, const unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + + virUUIDFormat(uuid, uuidstr + 1); + + uuidstr[0] = '{'; + uuidstr[VIR_UUID_STRING_BUFLEN] = '}'; + uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0'; + + 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(parallelsConnPtr privconn, + 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 (!(result = getJobResult(job, privconn->jobTimeout))) + 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) +{ + parallelsDomObjPtr pdom = p; + + if (!pdom) + return; + + PrlHandle_Free(pdom->sdkdom); + virBitmapFree(pdom->cpumask); + 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) +{ + char *buf = NULL; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 emulatedType; + PRL_UINT32 ifType; + PRL_UINT32 pos; + PRL_UINT32 prldiskIndex; + int ret = -1; + + pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType); + prlsdkCheckRetGoto(pret, cleanup); + if (emulatedType == PDT_USE_IMAGE_FILE) { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); + } else { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); + } + + 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; + + pret = PrlVmDev_GetIfaceType(prldisk, &ifType); + prlsdkCheckRetGoto(pret, cleanup); + switch (ifType) { + case PMS_IDE_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + break; + case PMS_SCSI_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; + break; + case PMS_SATA_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SATA; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown disk bus: %X"), ifType); + goto cleanup; + break; + } + + pret = PrlVmDev_GetStackIndex(prldisk, &pos); + prlsdkCheckRetGoto(pret, cleanup); + + disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + disk->info.addr.drive.target = pos; + + pret = PrlVmDev_GetIndex(prldisk, &prldiskIndex); + prlsdkCheckRetGoto(pret, cleanup); + + if (!(disk->dst = virIndexToDiskName(prldiskIndex, "sd"))) + goto cleanup; + + 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; + + pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < hddCount; ++i) { + pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); + prlsdkCheckRetGoto(pret, error); + + if (IS_CT(def)) { + /* TODO: convert info about disks in container + * to virDomainFSDef structs */ + VIR_WARN("Skipping disk information for container"); + + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + } else { + if (!(disk = virDomainDiskDefNew())) + goto error; + + if (prlsdkGetDiskInfo(hdd, disk) < 0) + goto error; + + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + goto error; + } + } + + return 0; + + error: + PrlHandle_Free(hdd); + 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 = PrlVmDev_GetIndex(netAdapter, &netAdapterIndex); + prlsdkCheckRetGoto(pret, cleanup); + + 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); + + 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_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_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); + } + + 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 (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; + + 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, + parallelsDomObjPtr pdom) +{ + 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 (!(pdom->cpumask = virBitmapNew(hostcpus))) + goto cleanup; + virBitmapSetAll(pdom->cpumask); + } else { + if (virBitmapParse(buf, 0, &pdom->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: + if (VIR_STRDUP(def->os.type, "hvm") < 0) + return -1; + break; + case PVT_CT: + if (VIR_STRDUP(def->os.type, "exe") < 0) + return -1; + 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(parallelsConnPtr privconn, + PRL_HANDLE sdkdom, + virDomainObjPtr olddom) +{ + virDomainObjPtr dom = NULL; + virDomainDefPtr def = NULL; + parallelsDomObjPtr 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 (VIR_ALLOC(def) < 0) + goto error; + + if (!olddom) { + if (VIR_ALLOC(pdom) < 0) + goto error; + } else { + pdom = olddom->privateData; + } + + 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; + + if (prlsdkGetDomainIds(sdkdom, &def->name, def->uuid) < 0) + goto error; + + /* get RAM parameters */ + pret = PrlVmCfg_GetRamSize(sdkdom, &ram); + prlsdkCheckRetGoto(pret, error); + def->mem.max_balloon = ram << 10; /* RAM size obtained in Mbytes, + convert to Kbytes */ + def->mem.cur_balloon = def->mem.max_balloon; + + if (prlsdkConvertCpuInfo(sdkdom, def, pdom) < 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); + + 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); + virDomainDefFree(dom->newDef); + dom->def = def; + dom->newDef = 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; + + if (prlsdkGetDomainState(privconn, sdkdom, &domainState) < 0) + goto error; + + if (prlsdkConvertDomainState(domainState, envId, dom) < 0) + goto error; + + pret = PrlVmCfg_GetAutoStart(sdkdom, &autostart); + prlsdkCheckRetGoto(pret, error); + + 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 (!pdom->sdkdom) { + pret = PrlHandle_AddRef(sdkdom); + prlsdkCheckRetGoto(pret, error); + pdom->sdkdom = sdkdom; + } + + return dom; + error: + if (dom && !olddom) + virDomainObjListRemove(privconn->domains, dom); + virDomainDefFree(def); + prlsdkDomObjFreePrivate(pdom); + return NULL; +} + +int +prlsdkLoadDomains(parallelsConnPtr 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 (!(result = getJobResult(job, privconn->jobTimeout))) + 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); + PrlHandle_Free(job); + return -1; +} + +virDomainObjPtr +prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid) +{ + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + virDomainObjPtr dom; + + sdkdom = prlsdkSdkDomainLookupByUUID(privconn, uuid); + if (sdkdom == PRL_INVALID_HANDLE) + return NULL; + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + return dom; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index cefe67d..d9461ca 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -28,3 +28,7 @@ int prlsdkInit(parallelsConnPtr privconn); void prlsdkDeinit(void); int prlsdkConnect(parallelsConnPtr privconn); void prlsdkDisconnect(parallelsConnPtr privconn); +int +prlsdkLoadDomains(parallelsConnPtr privconn); +virDomainObjPtr +prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 269020a..95206d6 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -61,6 +61,7 @@ struct parallelsDomObj { char *uuid; char *home; virBitmapPtr cpumask; + PRL_HANDLE sdkdom; }; typedef struct parallelsDomObj *parallelsDomObjPtr; -- 1.9.3

From: Alexander Burluka <aburluka@parallels.com> Subscribe to events from parallels server. It's needed for 2 things: to update cached domains list and to send corresponding libvirt events. Parallels server sends a lot of different events, in this patch we handle only some of them. In the future we can handle for example, changes in host network configuration or devices states. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 46 ++++++ src/parallels/parallels_sdk.c | 293 ++++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 2 + 3 files changed, 339 insertions(+), 2 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 7a60401..98e8bcb 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -231,6 +231,12 @@ parallelsOpenDefault(virConnectPtr conn) if (!(privconn->domains = virDomainObjListNew())) goto error; + if (!(privconn->domainEventState = virObjectEventStateNew())) + goto error; + + if (prlsdkSubscribeToPCSEvents(privconn)) + goto error; + conn->privateData = privconn; if (prlsdkLoadDomains(privconn)) @@ -242,6 +248,7 @@ parallelsOpenDefault(virConnectPtr conn) virObjectUnref(privconn->domains); virObjectUnref(privconn->caps); virStoragePoolObjListFree(&privconn->pools); + virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); prlsdkDeinit(); err_free: @@ -288,9 +295,11 @@ parallelsConnectClose(virConnectPtr conn) parallelsConnPtr privconn = conn->privateData; parallelsDriverLock(privconn); + prlsdkUnsubscribeFromPCSEvents(privconn); virObjectUnref(privconn->caps); virObjectUnref(privconn->xmlopt); virObjectUnref(privconn->domains); + virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); conn->privateData = NULL; prlsdkDeinit(); @@ -1725,6 +1734,41 @@ parallelsNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED, 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 virDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, @@ -1757,6 +1801,8 @@ static virDriver parallelsDriver = { .domainShutdown = parallelsDomainShutdown, /* 0.10.0 */ .domainCreate = parallelsDomainCreate, /* 0.10.0 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ + .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 */ diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index a05cdb3..dfc2220 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -27,6 +27,7 @@ #include "virstring.h" #include "nodeinfo.h" #include "virlog.h" +#include "datatypes.h" #include "parallels_sdk.h" @@ -1130,9 +1131,7 @@ prlsdkLoadDomain(parallelsConnPtr privconn, * for state and domain name */ dom = olddom; virDomainDefFree(dom->def); - virDomainDefFree(dom->newDef); dom->def = def; - dom->newDef = def; } else { if (!(dom = virDomainObjListAdd(privconn->domains, def, privconn->xmlopt, @@ -1241,3 +1240,293 @@ prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid) PrlHandle_Free(sdkdom); return dom; } + +static int +prlsdkUpdateDomain(parallelsConnPtr privconn, virDomainObjPtr dom) +{ + PRL_HANDLE job; + virDomainObjPtr retdom = NULL; + parallelsDomObjPtr pdom = dom->privateData; + + job = PrlVm_RefreshConfig(pdom->sdkdom); + if (waitJob(job, privconn->jobTimeout)) + return -1; + + retdom = prlsdkLoadDomain(privconn, pdom->sdkdom, dom); + return retdom ? 0 : -1; +} + +static int prlsdkSendEvent(parallelsConnPtr 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 PRL_RESULT +prlsdkHandleVmStateEvent(parallelsConnPtr 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; + parallelsDomObjPtr pdom; + virDomainEventType lvEventType; + int lvEventTypeDetails; + + pret = PrlEvent_GetParamByName(prlEvent, "vminfo_vm_state", &eventParam); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlEvtPrm_ToInt32(eventParam, &domainState); + prlsdkCheckRetGoto(pret, cleanup); + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) { + pret = PRL_ERR_VM_UUID_NOT_FOUND; + goto cleanup; + } + + pdom = dom->privateData; + if (prlsdkConvertDomainState(domainState, pdom->id, dom) < 0) + goto cleanup; + + prlsdkNewStateToEvent(domainState, + &lvEventType, + &lvEventTypeDetails); + + if (prlsdkSendEvent(privconn, dom, lvEventType, lvEventTypeDetails) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmConfigEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + PRL_RESULT pret = PRL_ERR_FAILURE; + virDomainObjPtr dom = NULL; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) { + pret = PRL_ERR_VM_UUID_NOT_FOUND; + goto cleanup; + } + + if (prlsdkUpdateDomain(privconn, dom) < 0) + goto cleanup; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_UPDATED) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + pret = PRL_ERR_SUCCESS; + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmAddedEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + PRL_RESULT pret; + virDomainObjPtr dom = NULL; + + dom = prlsdkAddDomain(privconn, uuid); + if (!dom) + return PRL_ERR_FAILURE; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_ADDED) < 0) { + pret = PRL_ERR_OUT_OF_MEMORY; + goto cleanup; + } + + pret = PRL_ERR_SUCCESS; + cleanup: + if (dom) + virObjectUnlock(dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmRemovedEvent(parallelsConnPtr privconn, + unsigned char *uuid) +{ + virDomainObjPtr dom = NULL; + PRL_RESULT pret = PRL_ERR_SUCCESS; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom == NULL) + return PRL_ERR_VM_UUID_NOT_FOUND; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) + pret = PRL_ERR_OUT_OF_MEMORY; + + virDomainObjListRemove(privconn->domains, dom); + return pret; +} + +static PRL_RESULT +prlsdkHandleVmEvent(parallelsConnPtr privconn, PRL_HANDLE prlEvent) +{ + PRL_RESULT pret; + 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, error); + + pret = PrlEvent_GetIssuerId(prlEvent, uuidstr, &bufsize); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + return PRL_ERR_FAILURE; + + switch (prlEventType) { + case PET_DSP_EVT_VM_STATE_CHANGED: + return prlsdkHandleVmStateEvent(privconn, prlEvent, uuid); + case PET_DSP_EVT_VM_CONFIG_CHANGED: + return prlsdkHandleVmConfigEvent(privconn, uuid); + case PET_DSP_EVT_VM_CREATED: + case PET_DSP_EVT_VM_ADDED: + return prlsdkHandleVmAddedEvent(privconn, uuid); + case PET_DSP_EVT_VM_DELETED: + case PET_DSP_EVT_VM_UNREGISTERED: + return prlsdkHandleVmRemovedEvent(privconn, uuid); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't handle event of type %d"), prlEventType); + return PRL_ERR_FAILURE; + } + + error: + return PRL_ERR_FAILURE; +} + +static PRL_RESULT +prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) +{ + parallelsConnPtr privconn = opaque; + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + PRL_HANDLE_TYPE handleType; + PRL_EVENT_TYPE prlEventType; + + pret = PrlHandle_GetType(prlEvent, &handleType); + prlsdkCheckRetGoto(pret, cleanup); + + if (handleType != PHT_EVENT) { + /* Currently, there is no need to handle anything but events */ + pret = PRL_ERR_SUCCESS; + goto cleanup; + } + + if (privconn == NULL) { + pret = PRL_ERR_INVALID_ARG; + goto cleanup; + } + + PrlEvent_GetType(prlEvent, &prlEventType); + prlsdkCheckRetGoto(pret, cleanup); + + switch (prlEventType) { + case PET_DSP_EVT_VM_STATE_CHANGED: + case PET_DSP_EVT_VM_CONFIG_CHANGED: + case PET_DSP_EVT_VM_CREATED: + case PET_DSP_EVT_VM_ADDED: + case PET_DSP_EVT_VM_DELETED: + case PET_DSP_EVT_VM_UNREGISTERED: + pret = prlsdkHandleVmEvent(privconn, prlEvent); + break; + default: + VIR_DEBUG("Skipping event of type %d", prlEventType); + } + + pret = PRL_ERR_SUCCESS; + cleanup: + PrlHandle_Free(prlEvent); + return pret; +} + +int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn) +{ + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + + pret = PrlSrv_RegEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + prlsdkCheckRetGoto(pret, error); + return 0; + + error: + return -1; +} + +void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn) +{ + PRL_RESULT ret = PRL_ERR_UNINITIALIZED; + ret = PrlSrv_UnregEventHandler(privconn->server, + prlsdkEventsHandler, + privconn); + if (PRL_FAILED(ret)) { + logPrlError(ret); + } +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index d9461ca..5ffbf53 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -32,3 +32,5 @@ int prlsdkLoadDomains(parallelsConnPtr privconn); virDomainObjPtr prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); +int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn); +void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn); -- 1.9.3

Move macro parallelsDomNotFoundError to file parallels_utils.h, because it will be used in parallels_sdk.c. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 8 -------- src/parallels/parallels_utils.h | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 98e8bcb..2d73bd6 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -63,14 +63,6 @@ VIR_LOG_INIT("parallels.parallels_driver"); #define PRLCTL "prlctl" #define PRLSRVCTL "prlsrvctl" -#define parallelsDomNotFoundError(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) - static int parallelsConnectClose(virConnectPtr conn); static const char * parallelsGetDiskBusName(int bus) { diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 95206d6..18d8bc6 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -39,6 +39,14 @@ #define IS_CT(def) (STREQ_NULLABLE(def->os.type, "exe")) +#define parallelsDomNotFoundError(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_ROUTED_NETWORK_NAME "Routed" struct _parallelsConn { -- 1.9.3

Change domain state using parallels SDK functions instead of prlctl command. We don't need to send events and update domains in privconn->domains list in these functions anymore, because it's done in prlsdkEventsHandler. Each time we do something with domain, parallels server sends an event, prlsdkEventsHandler is called and we update cached state accordingly Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 124 ++------------------------------------- src/parallels/parallels_sdk.c | 92 +++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 5 ++ 3 files changed, 102 insertions(+), 119 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 2d73bd6..a01249d 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -670,120 +670,6 @@ parallelsDomainGetAutostart(virDomainPtr domain, int *autostart) return ret; } -typedef int (*parallelsChangeStateFunc)(virDomainObjPtr privdom); -#define PARALLELS_UUID(x) (((parallelsDomObjPtr)(x->privateData))->uuid) - -static int -parallelsDomainChangeState(virDomainPtr domain, - virDomainState req_state, const char *req_state_name, - parallelsChangeStateFunc chstate, - virDomainState new_state, int reason) -{ - parallelsConnPtr privconn = domain->conn->privateData; - virDomainObjPtr privdom; - int state; - int ret = -1; - - parallelsDriverLock(privconn); - privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); - parallelsDriverUnlock(privconn); - - if (privdom == NULL) { - parallelsDomNotFoundError(domain); - goto cleanup; - } - - state = virDomainObjGetState(privdom, NULL); - if (state != req_state) { - virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not %s"), - privdom->def->name, req_state_name); - goto cleanup; - } - - if (chstate(privdom)) - goto cleanup; - - virDomainObjSetState(privdom, new_state, reason); - - ret = 0; - - cleanup: - if (privdom) - virObjectUnlock(privdom); - - return ret; -} - -static int parallelsPause(virDomainObjPtr privdom) -{ - return parallelsCmdRun(PRLCTL, "pause", PARALLELS_UUID(privdom), NULL); -} - -static int -parallelsDomainSuspend(virDomainPtr domain) -{ - return parallelsDomainChangeState(domain, - VIR_DOMAIN_RUNNING, "running", - parallelsPause, - VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); -} - -static int parallelsResume(virDomainObjPtr privdom) -{ - return parallelsCmdRun(PRLCTL, "resume", PARALLELS_UUID(privdom), NULL); -} - -static int -parallelsDomainResume(virDomainPtr domain) -{ - return parallelsDomainChangeState(domain, - VIR_DOMAIN_PAUSED, "paused", - parallelsResume, - VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED); -} - -static int parallelsStart(virDomainObjPtr privdom) -{ - return parallelsCmdRun(PRLCTL, "start", PARALLELS_UUID(privdom), NULL); -} - -static int -parallelsDomainCreate(virDomainPtr domain) -{ - return parallelsDomainChangeState(domain, - VIR_DOMAIN_SHUTOFF, "stopped", - parallelsStart, - VIR_DOMAIN_RUNNING, VIR_DOMAIN_EVENT_STARTED_BOOTED); -} - -static int parallelsKill(virDomainObjPtr privdom) -{ - return parallelsCmdRun(PRLCTL, "stop", PARALLELS_UUID(privdom), "--kill", NULL); -} - -static int -parallelsDomainDestroy(virDomainPtr domain) -{ - return parallelsDomainChangeState(domain, - VIR_DOMAIN_RUNNING, "running", - parallelsKill, - VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED); -} - -static int parallelsStop(virDomainObjPtr privdom) -{ - return parallelsCmdRun(PRLCTL, "stop", PARALLELS_UUID(privdom), NULL); -} - -static int -parallelsDomainShutdown(virDomainPtr domain) -{ - return parallelsDomainChangeState(domain, - VIR_DOMAIN_RUNNING, "running", - parallelsStop, - VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_SHUTDOWN); -} - static int parallelsApplyGraphicsParams(virDomainGraphicsDefPtr *oldgraphics, int nold, virDomainGraphicsDefPtr *newgraphics, int nnew) @@ -1787,11 +1673,11 @@ static virDriver parallelsDriver = { .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 */ + .domainSuspend = prlsdkDomainSuspend, /* 0.10.0 */ + .domainResume = prlsdkDomainResume, /* 0.10.0 */ + .domainDestroy = prlsdkDomainDestroy, /* 0.10.0 */ + .domainShutdown = prlsdkDomainShutdown, /* 0.10.0 */ + .domainCreate = prlsdkDomainCreate, /* 0.10.0 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ .connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */ .connectDomainEventDeregisterAny = parallelsConnectDomainEventDeregisterAny, /* 1.2.10 */ diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index dfc2220..78caa6c 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1530,3 +1530,95 @@ void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn) logPrlError(ret); } } + +static int prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_StartEx(sdkdom, PSM_VM_START, 0); + return waitJob(job, privconn->jobTimeout); +} + +static int prlsdkStopEx(parallelsConnPtr privconn, + PRL_HANDLE sdkdom, + PRL_UINT32 mode) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_StopEx(sdkdom, mode, 0); + return waitJob(job, privconn->jobTimeout); +} + +static int prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(privconn, sdkdom, PSM_KILL); +} + +static int prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(privconn, sdkdom, PSM_SHUTDOWN); +} + +static int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Pause(sdkdom, false); + return waitJob(job, privconn->jobTimeout); +} + +static int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Resume(sdkdom); + return waitJob(job, privconn->jobTimeout); +} + +typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdom); + +static int +prlsdkDomainChangeState(virDomainPtr domain, + prlsdkChangeStateFunc chstate) +{ + parallelsConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom; + parallelsDomObjPtr pdom; + int ret = -1; + + dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); + if (dom == NULL) { + parallelsDomNotFoundError(domain); + return -1; + } + + pdom = dom->privateData; + ret = chstate(privconn, pdom->sdkdom); + virObjectUnlock(dom); + return ret; +} + +int prlsdkDomainSuspend(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkPause); +} + +int prlsdkDomainResume(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkResume); +} + +int prlsdkDomainCreate(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStart); +} + +int prlsdkDomainDestroy(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkKill); +} + +int prlsdkDomainShutdown(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStop); +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 5ffbf53..61c2a81 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -34,3 +34,8 @@ virDomainObjPtr prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn); void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn); +int prlsdkDomainSuspend(virDomainPtr domain); +int prlsdkDomainResume(virDomainPtr domain); +int prlsdkDomainCreate(virDomainPtr domain); +int prlsdkDomainDestroy(virDomainPtr domain); +int prlsdkDomainShutdown(virDomainPtr domain); -- 1.9.3

Rewrite code, which applies domain configuration given to virDomainDefineXML function to the VM of container registered in PCS. This code first check if there are unsupported parameters in domain XML and if yes - reports error. Some of such parameters are not supported by PCS, for some - it's not obvious, how to convert them into PCS's corresponding params, so let's put off it, and implement only basic params in this patch. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 737 +------------------------------ src/parallels/parallels_sdk.c | 928 +++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 4 + 3 files changed, 933 insertions(+), 736 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index a01249d..66a3100 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -65,19 +65,6 @@ VIR_LOG_INIT("parallels.parallels_driver"); static int parallelsConnectClose(virConnectPtr conn); -static const char * parallelsGetDiskBusName(int bus) { - switch (bus) { - case VIR_DOMAIN_DISK_BUS_IDE: - return "ide"; - case VIR_DOMAIN_DISK_BUS_SATA: - return "sata"; - case VIR_DOMAIN_DISK_BUS_SCSI: - return "scsi"; - default: - return NULL; - } -} - void parallelsDriverLock(parallelsConnPtr driver) { @@ -671,728 +658,6 @@ parallelsDomainGetAutostart(virDomainPtr domain, int *autostart) } static int -parallelsApplyGraphicsParams(virDomainGraphicsDefPtr *oldgraphics, int nold, - virDomainGraphicsDefPtr *newgraphics, int nnew) -{ - virDomainGraphicsDefPtr new, old; - - /* parallels server supports only 1 VNC display per VM */ - if (nold != nnew || nnew > 1) - goto error; - - if (nnew == 0) - return 0; - - if (newgraphics[0]->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) - goto error; - - old = oldgraphics[0]; - new = newgraphics[0]; - - if (old->data.vnc.port != new->data.vnc.port && - (old->data.vnc.port != 0 && new->data.vnc.port != 0)) { - - goto error; - } else if (old->data.vnc.autoport != new->data.vnc.autoport || - new->data.vnc.keymap != NULL || - new->data.vnc.socket != NULL || - !STREQ_NULLABLE(old->data.vnc.auth.passwd, new->data.vnc.auth.passwd) || - old->data.vnc.auth.expires != new->data.vnc.auth.expires || - old->data.vnc.auth.validTo != new->data.vnc.auth.validTo || - old->data.vnc.auth.connected != new->data.vnc.auth.connected) { - - goto error; - } else if (old->nListens != new->nListens || - new->nListens > 1 || - old->listens[0].type != new->listens[0].type || - !STREQ_NULLABLE(old->listens[0].address, new->listens[0].address) || - !STREQ_NULLABLE(old->listens[0].network, new->listens[0].network)) { - - goto error; - } - - return 0; - error: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing display parameters is not supported " - "by parallels driver")); - return -1; -} - -static int -parallelsApplySerialParams(virDomainChrDefPtr *oldserials, int nold, - virDomainChrDefPtr *newserials, int nnew) -{ - size_t i, j; - - if (nold != nnew) - goto error; - - for (i = 0; i < nold; i++) { - virDomainChrDefPtr oldserial = oldserials[i]; - virDomainChrDefPtr newserial = NULL; - - for (j = 0; j < nnew; j++) { - if (newserials[j]->target.port == oldserial->target.port) { - newserial = newserials[j]; - break; - } - } - - if (!newserial) - goto error; - - if (oldserial->source.type != newserial->source.type) - goto error; - - if ((newserial->source.type == VIR_DOMAIN_CHR_TYPE_DEV || - newserial->source.type == VIR_DOMAIN_CHR_TYPE_FILE) && - !STREQ_NULLABLE(oldserial->source.data.file.path, - newserial->source.data.file.path)) - goto error; - if (newserial->source.type == VIR_DOMAIN_CHR_TYPE_UNIX && - (!STREQ_NULLABLE(oldserial->source.data.nix.path, - newserial->source.data.nix.path) || - oldserial->source.data.nix.listen == newserial->source.data.nix.listen)) { - - goto error; - } - } - - return 0; - error: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing serial device parameters is " - "not supported by parallels driver")); - return -1; -} - -static int -parallelsApplyVideoParams(parallelsDomObjPtr pdom, - virDomainVideoDefPtr *oldvideos, int nold, - virDomainVideoDefPtr *newvideos, int nnew) -{ - virDomainVideoDefPtr old, new; - char str_vram[32]; - - if (nold != 1 || nnew != 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only one video device is " - "supported by parallels driver")); - return -1; - } - - old = oldvideos[0]; - new = newvideos[0]; - if (new->type != VIR_DOMAIN_VIDEO_TYPE_VGA) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only VGA video device is " - "supported by parallels driver")); - return -1; - } - - if (new->heads != 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only one monitor is supported by parallels driver")); - return -1; - } - - /* old->accel must be always non-NULL */ - if (new->accel == NULL || - old->accel->support2d != new->accel->support2d || - old->accel->support3d != new->accel->support3d) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing video acceleration parameters is " - "not supported by parallels driver")); - return -1; - - } - - if (old->vram != new->vram) { - if (new->vram % (1 << 10) != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Video RAM size should be multiple of 1Mb.")); - return -1; - } - - snprintf(str_vram, 31, "%dK", new->vram); - str_vram[31] = '\0'; - - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--videosize", str_vram, NULL)) - return -1; - } - return 0; -} - -static int parallelsAddHdd(parallelsDomObjPtr pdom, - virDomainDiskDefPtr disk) -{ - int ret = -1; - const char *src = virDomainDiskGetSource(disk); - int type = virDomainDiskGetType(disk); - const char *strbus; - - virCommandPtr cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, - "--device-add", "hdd", NULL); - - if (type == VIR_STORAGE_TYPE_FILE) { - int format = virDomainDiskGetFormat(disk); - - if (format != VIR_STORAGE_FILE_PLOOP) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Invalid disk format: %d"), type); - goto cleanup; - } - - virCommandAddArg(cmd, "--image"); - } else if (VIR_STORAGE_TYPE_BLOCK) { - virCommandAddArg(cmd, "--device"); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Invalid disk type: %d"), type); - goto cleanup; - } - - virCommandAddArg(cmd, src); - - if (!(strbus = parallelsGetDiskBusName(disk->bus))) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Invalid disk bus: %d"), disk->bus); - goto cleanup; - } - - virCommandAddArgFormat(cmd, "--iface=%s", strbus); - - if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) - virCommandAddArgFormat(cmd, "--position=%d", - disk->info.addr.drive.target); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - - cleanup: - virCommandFree(cmd); - return ret; -} - -static int parallelsRemoveHdd(parallelsDomObjPtr pdom, - virDomainDiskDefPtr disk) -{ - char prlname[16]; - - prlname[15] = '\0'; - snprintf(prlname, 15, "hdd%d", virDiskNameToIndex(disk->dst)); - - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--device-del", prlname, - "--detach-only", NULL)) - return -1; - - return 0; -} - -static int -parallelsApplyDisksParams(parallelsDomObjPtr pdom, - virDomainDiskDefPtr *olddisks, int nold, - virDomainDiskDefPtr *newdisks, int nnew) -{ - size_t i, j; - - for (i = 0; i < nold; i++) { - virDomainDiskDefPtr newdisk = NULL; - virDomainDiskDefPtr olddisk = olddisks[i]; - for (j = 0; j < nnew; j++) { - if (STREQ_NULLABLE(newdisks[j]->dst, olddisk->dst)) { - newdisk = newdisks[j]; - break; - } - } - - if (!newdisk) { - if (parallelsRemoveHdd(pdom, olddisk)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Can't remove disk '%s' " - "in the specified config"), olddisks[i]->serial); - return -1; - } - - continue; - } - - if (olddisk->bus != newdisk->bus || - olddisk->info.addr.drive.target != newdisk->info.addr.drive.target || - !STREQ_NULLABLE(virDomainDiskGetSource(olddisk), - virDomainDiskGetSource(newdisk))) { - - char prlname[16]; - char strpos[16]; - const char *strbus; - - prlname[15] = '\0'; - snprintf(prlname, 15, "hdd%d", virDiskNameToIndex(newdisk->dst)); - - strpos[15] = '\0'; - snprintf(strpos, 15, "%d", newdisk->info.addr.drive.target); - - if (!(strbus = parallelsGetDiskBusName(newdisk->bus))) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported disk bus: %d"), newdisk->bus); - return -1; - } - - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--device-set", prlname, - "--iface", strbus, - "--position", strpos, - "--image", newdisk->src, NULL)) - return -1; - } - } - - for (i = 0; i < nnew; i++) { - virDomainDiskDefPtr newdisk = newdisks[i]; - bool found = false; - for (j = 0; j < nold; j++) - if (STREQ_NULLABLE(olddisks[j]->dst, newdisk->dst)) - found = true; - if (found) - continue; - - if (parallelsAddHdd(pdom, newdisk)) - return -1; - } - - return 0; -} - -static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom, - virDomainNetDefPtr oldnet, - virDomainNetDefPtr newnet) -{ - bool create = false; - bool is_changed = false; - virCommandPtr cmd = NULL; - char strmac[VIR_MAC_STRING_BUFLEN]; - size_t i; - int ret = -1; - - if (!oldnet) { - create = true; - if (VIR_ALLOC(oldnet) < 0) - return -1; - } - - if (!create && oldnet->type != newnet->type) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing network type is not supported")); - goto cleanup; - } - - if (!STREQ_NULLABLE(oldnet->model, newnet->model)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing network device model is not supported")); - goto cleanup; - } - - if (!STREQ_NULLABLE(oldnet->data.network.portgroup, - newnet->data.network.portgroup)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing network portgroup is not supported")); - goto cleanup; - } - - if (!virNetDevVPortProfileEqual(oldnet->virtPortProfile, - newnet->virtPortProfile)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing virtual port profile is not supported")); - goto cleanup; - } - - if (newnet->tune.sndbuf_specified) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting send buffer size is not supported")); - goto cleanup; - } - - if (!STREQ_NULLABLE(oldnet->script, newnet->script)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting startup script is not supported")); - goto cleanup; - } - - if (!STREQ_NULLABLE(oldnet->filter, newnet->filter)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Changing filter params is not supported")); - goto cleanup; - } - - if (newnet->bandwidth != NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting bandwidth params is not supported")); - goto cleanup; - } - - for (i = 0; i < sizeof(newnet->vlan); i++) { - if (((char *)&newnet->vlan)[i] != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Setting vlan params is not supported")); - goto cleanup; - } - } - - /* Here we know, that there are no differences, that are forbidden. - * Check is something changed, if no - do nothing */ - - if (create) { - cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, - "--device-add", "net", NULL); - } else { - cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, - "--device-set", newnet->ifname, NULL); - } - - if (virMacAddrCmp(&oldnet->mac, &newnet->mac)) { - virMacAddrFormat(&newnet->mac, strmac); - virCommandAddArgFormat(cmd, "--mac=%s", strmac); - is_changed = true; - } - - if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) { - if (STREQ_NULLABLE(newnet->data.network.name, - PARALLELS_ROUTED_NETWORK_NAME)) { - virCommandAddArgFormat(cmd, "--type=routed"); - } else { - virCommandAddArgFormat(cmd, "--network=%s", - newnet->data.network.name); - } - - is_changed = true; - } - - if (oldnet->linkstate != newnet->linkstate) { - if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP) { - virCommandAddArgFormat(cmd, "--connect"); - } else if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) { - virCommandAddArgFormat(cmd, "--disconnect"); - } - is_changed = true; - } - - if (!create && !is_changed) { - /* nothing changed - no need to run prlctl */ - ret = 0; - goto cleanup; - } - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - - cleanup: - if (create) - VIR_FREE(oldnet); - virCommandFree(cmd); - return ret; -} - -static int -parallelsApplyIfacesParams(parallelsDomObjPtr pdom, - virDomainNetDefPtr *oldnets, int nold, - virDomainNetDefPtr *newnets, int nnew) -{ - size_t i, j; - virDomainNetDefPtr newnet; - virDomainNetDefPtr oldnet; - bool found; - - for (i = 0; i < nold; i++) { - newnet = NULL; - oldnet = oldnets[i]; - for (j = 0; j < nnew; j++) { - if (STREQ_NULLABLE(newnets[j]->ifname, oldnet->ifname)) { - newnet = newnets[j]; - break; - } - } - - if (!newnet) { - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--device-del", oldnet->ifname, NULL) < 0) - return -1; - - continue; - } - - if (parallelsApplyIfaceParams(pdom, oldnet, newnet) < 0) - return -1; - } - - for (i = 0; i < nnew; i++) { - newnet = newnets[i]; - found = false; - - for (j = 0; j < nold; j++) - if (STREQ_NULLABLE(oldnets[j]->ifname, newnet->ifname)) - found = true; - if (found) - continue; - - if (parallelsApplyIfaceParams(pdom, NULL, newnet)) - return -1; - } - - return 0; -} - -static int -parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new) -{ - char buf[32]; - size_t i; - - virDomainDefPtr old = dom->def; - parallelsDomObjPtr pdom = dom->privateData; - - if (new->description && !STREQ_NULLABLE(old->description, new->description)) { - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--description", new->description, NULL)) - return -1; - } - - if (new->name && !STREQ_NULLABLE(old->name, new->name)) { - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--name", new->name, NULL)) - return -1; - } - - if (new->title && !STREQ_NULLABLE(old->title, new->title)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("titles are not supported by parallels driver")); - return -1; - } - - if (new->blkio.ndevices > 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("blkio parameters are not supported " - "by parallels driver")); - return -1; - } - - if (old->mem.max_balloon != new->mem.max_balloon) { - if (new->mem.max_balloon != new->mem.cur_balloon) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing balloon parameters is not supported " - "by parallels driver")); - return -1; - } - - if (new->mem.max_balloon % (1 << 10) != 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Memory size should be multiple of 1Mb.")); - return -1; - } - - snprintf(buf, 31, "%llu", new->mem.max_balloon >> 10); - buf[31] = '\0'; - - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--memsize", buf, NULL)) - return -1; - } - - if (old->mem.nhugepages != new->mem.nhugepages || - old->mem.hard_limit != new->mem.hard_limit || - old->mem.soft_limit != new->mem.soft_limit || - old->mem.min_guarantee != new->mem.min_guarantee || - old->mem.swap_hard_limit != new->mem.swap_hard_limit) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Memory parameter is not supported " - "by parallels driver")); - return -1; - } - - if (old->vcpus != new->vcpus) { - if (new->vcpus != new->maxvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("current vcpus must be equal to maxvcpus")); - return -1; - } - - snprintf(buf, 31, "%d", new->vcpus); - buf[31] = '\0'; - - if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, - "--cpus", buf, NULL)) - return -1; - } - - if (old->placement_mode != new->placement_mode) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing cpu placement mode is not supported " - "by parallels driver")); - return -1; - } - - if ((old->cpumask != NULL || new->cpumask != NULL) && - (old->cpumask == NULL || new->cpumask == NULL || - !virBitmapEqual(old->cpumask, new->cpumask))) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing cpu mask is not supported " - "by parallels driver")); - return -1; - } - - if (old->cputune.shares != new->cputune.shares || - old->cputune.sharesSpecified != new->cputune.sharesSpecified || - old->cputune.period != new->cputune.period || - old->cputune.quota != new->cputune.quota || - old->cputune.nvcpupin != new->cputune.nvcpupin) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("cputune is not supported by parallels driver")); - return -1; - } - - if (!virDomainNumatuneEquals(old->numatune, new->numatune)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("numa parameters are not supported " - "by parallels driver")); - return -1; - } - - if (old->onReboot != new->onReboot || - old->onPoweroff != new->onPoweroff || - old->onCrash != new->onCrash) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("on_reboot, on_poweroff and on_crash parameters " - "are not supported by parallels driver")); - return -1; - } - - /* we fill only type and arch fields in parallelsLoadDomain 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 (!STREQ_NULLABLE(old->os.type, new->os.type) || - old->os.arch != new->os.arch || - new->os.machine != NULL || new->os.bootmenu != 0 || - new->os.kernel != NULL || new->os.initrd != NULL || - new->os.cmdline != NULL || new->os.root != NULL || - new->os.loader != NULL || new->os.bootloader != NULL || - new->os.bootloaderArgs != NULL || new->os.smbios_mode != 0 || - new->os.bios.useserial != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by parallels driver")); - return -1; - } - if (STREQ(new->os.type, "hvm")) { - if (new->os.nBootDevs != 1 || - new->os.bootDevs[0] != VIR_DOMAIN_BOOT_DISK || - new->os.init != NULL || new->os.initargv != NULL) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by parallels driver")); - return -1; - } - } else { - if (new->os.nBootDevs != 0 || - !STREQ_NULLABLE(old->os.init, new->os.init) || - (new->os.initargv != NULL && new->os.initargv[0] != NULL)) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing OS parameters is not supported " - "by parallels driver")); - return -1; - } - } - - - if (!STREQ_NULLABLE(old->emulator, new->emulator)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing emulator is not supported " - "by parallels driver")); - return -1; - } - - for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) { - if (old->features[i] != new->features[i]) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing features is not supported " - "by parallels driver")); - return -1; - } - } - - if (new->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC || - new->clock.ntimers != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing clock parameters is not supported " - "by parallels driver")); - return -1; - } - - if (parallelsApplyGraphicsParams(old->graphics, old->ngraphics, - new->graphics, new->ngraphics) < 0) - return -1; - - if (new->nfss != 0 || - new->nsounds != 0 || new->nhostdevs != 0 || - new->nredirdevs != 0 || new->nsmartcards != 0 || - new->nparallels || new->nchannels != 0 || - new->nleases != 0 || new->nhubs != 0) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing devices parameters is not supported " - "by parallels driver")); - return -1; - } - - /* there may be one auto-input */ - if (new->ninputs > 1 || - (new->ninputs > 1 && - (new->inputs[0]->type != VIR_DOMAIN_INPUT_TYPE_MOUSE || - new->inputs[0]->bus != VIR_DOMAIN_INPUT_BUS_PS2))) { - - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("changing input devices parameters is not supported " - "by parallels driver")); - } - - - if (parallelsApplySerialParams(old->serials, old->nserials, - new->serials, new->nserials) < 0) - return -1; - - if (parallelsApplySerialParams(old->consoles, old->nconsoles, - new->consoles, new->nconsoles) < 0) - return -1; - - if (parallelsApplyVideoParams(pdom, old->videos, old->nvideos, - new->videos, new->nvideos) < 0) - return -1; - if (parallelsApplyDisksParams(pdom, old->disks, old->ndisks, - new->disks, new->ndisks) < 0) - return -1; - if (parallelsApplyIfacesParams(pdom, old->nets, old->nnets, - new->nets, new->nnets) < 0) - return -1; - - return 0; -} - -static int parallelsCreateVm(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def) { char uuidstr[VIR_UUID_STRING_BUFLEN]; @@ -1479,7 +744,7 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) } } - if (parallelsApplyChanges(olddom, def) < 0) { + if (prlsdkApplyConfig(conn, olddom, def) < 0) { virObjectUnlock(olddom); goto cleanup; } diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 78caa6c..0125fd3 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -28,6 +28,7 @@ #include "nodeinfo.h" #include "virlog.h" #include "datatypes.h" +#include "domain_conf.h" #include "parallels_sdk.h" @@ -1622,3 +1623,930 @@ int prlsdkDomainShutdown(virDomainPtr domain) { return prlsdkDomainChangeState(domain, prlsdkStop); } + +static int +prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + size_t i; + PRL_VM_TYPE vmType; + PRL_RESULT pret; + + if (def->title) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("titles are not supported by parallels driver")); + return -1; + } + + if (def->blkio.ndevices > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("blkio parameters are not supported " + "by parallels driver")); + return -1; + } + + if (def->mem.max_balloon != def->mem.cur_balloon) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing balloon parameters is not supported " + "by parallels driver")); + return -1; + } + + if (def->mem.max_balloon % (1 << 10) != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Memory size should be multiple of 1Mb.")); + return -1; + } + + if (def->mem.nhugepages || + def->mem.hard_limit || + def->mem.soft_limit || + def->mem.min_guarantee || + def->mem.swap_hard_limit) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Memory parameter is not supported " + "by parallels 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 parallels driver")); + return -1; + } + + if (def->cpumask != NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing cpu mask is not supported " + "by parallels driver")); + return -1; + } + + if (def->cputune.shares || + def->cputune.sharesSpecified || + def->cputune.period || + def->cputune.quota || + def->cputune.nvcpupin) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cputune is not supported by parallels driver")); + return -1; + } + + if (def->numatune) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("numa parameters are not supported " + "by parallels driver")); + return -1; + } + + if (def->onReboot || + def->onPoweroff || + def->onCrash) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("on_reboot, on_poweroff and on_crash parameters " + "are not supported by parallels driver")); + return -1; + } + + /* we fill only type and arch fields in parallelsLoadDomain 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 parallels driver")); + return -1; + } + + pret = PrlVmCfg_GetVmType(sdkdom, &vmType); + if (PRL_FAILED(pret)) { + logPrlError(pret); + return -1; + } + + if (!(vmType == PVT_VM && STREQ(def->os.type, "hvm")) && + !(vmType == PVT_CT && STREQ(def->os.type, "exe"))) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing OS type is not supported " + "by parallels driver")); + return -1; + } + + if (STREQ(def->os.type, "hvm")) { + 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 parallels 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 parallels driver")); + return -1; + } + } + + if (def->emulator) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("changing emulator is not supported " + "by parallels 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 parallels 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 parallels driver")); + return -1; + } + + if (def->nfss != 0 || + 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 parallels 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 parallels 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 prlsdkCheckGraphicsUnsupportedParams(virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr; + + if (def->ngraphics == 0) + return 0; + + if (def->ngraphics >1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server 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", + _("Parallels Cloud Server supports only " + "VNC graphics.")); + return -1; + } + + if (gr->data.vnc.websocket != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server doesn't support " + "websockets for VNC graphics.")); + return -1; + } + + if (gr->data.vnc.keymap != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server 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", + _("Parallels Cloud Server doesn't support " + "exclusive share policy for VNC graphics.")); + return -1; + } + + if (gr->data.vnc.socket) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server 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", + _("Parallels Cloud Server doesn't support " + "given action in case of password change.")); + return -1; + } + + if (gr->data.vnc.auth.expires) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server doesn't support " + "setting password expire time.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckVideoUnsupportedParams(virDomainDefPtr def) +{ + bool isCt = STREQ(def->os.type, "exe"); + virDomainVideoDefPtr v; + + if (isCt) { + 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", + _("Parallels Cloud Server 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", + _("Parallels Cloud Server supports " + "only VGA video adapters.")); + return -1; + } + + if (v->heads != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server doesn't support " + "multihead video adapters.")); + return -1; + } + + if (v->accel == NULL || v->accel->support2d || v->accel->support3d) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Parallels Cloud Server 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 parallels driver.")); + return -1; + } + + if (chr->targetTypeAttr) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified character device target type is not " + "supported by parallels 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 Parallels Cloud Server.")); + 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 parallels driver.")); + return -1; + } + + if (chr->nseclabels > 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting security labels is not " + "supported by parallels driver.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckNetUnsupportedParams(virDomainNetDefPtr net) +{ + if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified network adapter type is not " + "supported by Parallels Cloud Server.")); + return -1; + } + + if (net->backend.tap || net->backend.vhost) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Interface backend parameters are not " + "supported by parallels driver.")); + return -1; + } + + if (net->data.network.portgroup) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Virtual network portgroups are not " + "supported by Parallels Cloud Server.")); + return -1; + } + + if (net->tune.sndbuf_specified) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting interface sndbuf is not " + "supported by parallels driver.")); + return -1; + } + + if (net->script) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting interface script is not " + "supported by parallels driver.")); + return -1; + } + + if (net->ifname_guest) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting guest interface name is not " + "supported by parallels 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 parallels driver.")); + return -1; + } + + if (net->filter) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting network filter is not " + "supported by parallels driver.")); + return -1; + } + + if (net->bandwidth) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting network bandwidth is not " + "supported by parallels driver.")); + return -1; + } + + if (net->vlan.trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up vlans is not " + "supported by parallels driver.")); + return -1; + } + + return 0; +} + +static int prlsdkCheckDiskUnsupportedParams(virDomainDiskDefPtr disk) +{ + if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only hard disks are supported " + "supported by parallels 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 parallels 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 parallels driver yet.")); + return -1; + } + + if (disk->serial) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk serial number is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->wwn) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk wwn id is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->vendor) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk vendor is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->product) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk product id is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk cache mode is not " + "supported by parallels driver yet.")); + 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 parallels driver.")); + return -1; + } + + if (disk->iomode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting disk io mode is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->copy_on_read) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Disk copy_on_read is not " + "supported by parallels 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 parallels driver.")); + return -1; + } + + if (disk->transient) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Transient disks are not " + "supported by parallels driver.")); + return -1; + } + + if (disk->discard) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up disk discard parameter is not " + "supported by parallels driver.")); + return -1; + } + + if (disk->iothread) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Setting up disk io thread # is not " + "supported by parallels 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 parallels driver.")); + return -1; + + } + + return 0; +} + +static int prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr; + PRL_RESULT pret; + int ret = -1; + + 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); + } + + 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; + 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", + _("Parallels Cloud Server 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 + +const char * prlsdkFormatMac(virMacAddrPtr mac, char *macstr) +{ + snprintf(macstr, VIR_MAC_STRING_BUFLEN, + "%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, virDomainNetDefPtr net) +{ + PRL_RESULT pret; + PRL_HANDLE sdknet = 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); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname); + prlsdkCheckRetGoto(pret, cleanup); + + prlsdkFormatMac(&net->mac, macstr); + pret = PrlVmDevNet_SetMacAddress(sdknet, macstr); + prlsdkCheckRetGoto(pret, cleanup); + + if (STREQ(net->data.network.name, PARALLELS_ROUTED_NETWORK_NAME)) { + pret = PrlVmDev_SetEmulatedType(sdknet, PNA_ROUTED); + prlsdkCheckRetGoto(pret, cleanup); + } else { + 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(sdknet); + return ret; +} + +static int prlsdkAddDisk(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk) +{ + PRL_RESULT pret; + PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE; + int ret = -1; + PRL_VM_DEV_EMULATION_TYPE emutype; + PRL_MASS_STORAGE_INTERFACE_TYPE sdkbus; + + if (prlsdkCheckDiskUnsupportedParams(disk) < 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); + + if (disk->src->type == VIR_STORAGE_TYPE_FILE) { + if (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid disk format: %d"), disk->src->type); + goto cleanup; + } + + emutype = PDT_USE_IMAGE_FILE; + } else { + 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); + + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_IDE: + sdkbus = PMS_IDE_DEVICE; + break; + case VIR_DOMAIN_DISK_BUS_SCSI: + sdkbus = PMS_SCSI_DEVICE; + break; + case VIR_DOMAIN_DISK_BUS_SATA: + sdkbus = PMS_SATA_DEVICE; + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified disk bus is not " + "supported by Parallels Cloud Server.")); + goto cleanup; + } + + pret = PrlVmDev_SetIfaceType(sdkdisk, sdkbus); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDev_SetStackIndex(sdkdisk, disk->info.addr.drive.target); + prlsdkCheckRetGoto(pret, cleanup); + + return 0; + cleanup: + PrlHandle_Free(sdkdisk); + return ret; +} + +static int +prlsdkDoApplyConfig(PRL_HANDLE sdkdom, + virDomainDefPtr def) +{ + PRL_RESULT pret; + size_t i; + + 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); + } + + pret = PrlVmCfg_SetRamSize(sdkdom, def->mem.max_balloon >> 10); + prlsdkCheckRetGoto(pret, error); + + pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkClearDevices(sdkdom) < 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->nnets; i++) { + if (prlsdkAddNet(sdkdom, def->nets[i]) < 0) + goto error; + } + + for (i = 0; i < def->ndisks; i++) { + if (prlsdkAddDisk(sdkdom, def->disks[i]) < 0) + goto error; + } + + return 0; + + error: + return -1; + +} + +int +prlsdkApplyConfig(virConnectPtr conn, + virDomainObjPtr dom, + virDomainDefPtr new) +{ + parallelsConnPtr 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 (waitJob(job, privconn->jobTimeout) < 0) + return -1; + + ret = prlsdkDoApplyConfig(sdkdom, new); + + job = PrlVm_Commit(sdkdom); + ret = waitJob(job, privconn->jobTimeout); + + PrlHandle_Free(sdkdom); + + return ret; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 61c2a81..91a829e 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -39,3 +39,7 @@ int prlsdkDomainResume(virDomainPtr domain); int prlsdkDomainCreate(virDomainPtr domain); int prlsdkDomainDestroy(virDomainPtr domain); int prlsdkDomainShutdown(virDomainPtr domain); +int +prlsdkApplyConfig(virConnectPtr conn, + virDomainObjPtr dom, + virDomainDefPtr new); -- 1.9.3

This patch replaces code, which creates domains by running prlctl command. prlsdkCreateVm/Ct will do prlsdkApplyConfig, because we send request to the server only once in this case. But prlsdkApplyConfig will be called also from parallelsDomainDefineXML function. There is no problem with it, parallelsDomainDefineXML will be refactored later. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 45 +--------------------- src/parallels/parallels_sdk.c | 81 +++++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 2 + 3 files changed, 84 insertions(+), 44 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 66a3100..c9da259 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -657,47 +657,6 @@ parallelsDomainGetAutostart(virDomainPtr domain, int *autostart) return ret; } -static int -parallelsCreateVm(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - - virUUIDFormat(def->uuid, uuidstr); - - if (parallelsCmdRun(PRLCTL, "create", def->name, "--no-hdd", - "--uuid", uuidstr, NULL) < 0) - return -1; - - return 0; -} - -static int -parallelsCreateCt(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - - virUUIDFormat(def->uuid, uuidstr); - - if (def->nfss != 1 || - def->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE) { - - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("There must be only 1 template FS for " - "container creation")); - goto error; - } - - if (parallelsCmdRun(PRLCTL, "create", def->name, "--vmtype", "ct", - "--uuid", uuidstr, - "--ostemplate", def->fss[0]->src, NULL) < 0) - goto error; - - return 0; - - error: - return -1; -} - static virDomainPtr parallelsDomainDefineXML(virConnectPtr conn, const char *xml) { @@ -720,10 +679,10 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) if (olddom == NULL) { virResetLastError(); if (STREQ(def->os.type, "hvm")) { - if (parallelsCreateVm(conn, def)) + if (prlsdkCreateVm(conn, def)) goto cleanup; } else if (STREQ(def->os.type, "exe")) { - if (parallelsCreateCt(conn, def)) + if (prlsdkCreateCt(conn, def)) goto cleanup; } else { virReportError(VIR_ERR_INVALID_ARG, diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 0125fd3..cc796ee 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -2520,7 +2520,6 @@ prlsdkDoApplyConfig(PRL_HANDLE sdkdom, error: return -1; - } int @@ -2550,3 +2549,83 @@ prlsdkApplyConfig(virConnectPtr conn, return ret; } + +int +prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def) +{ + parallelsConnPtr 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 (!(result = getJobResult(job, privconn->jobTimeout))) + 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); + + ret = prlsdkDoApplyConfig(sdkdom, def); + + job = PrlVm_Reg(sdkdom, "", 1); + ret = waitJob(job, privconn->jobTimeout); + + cleanup: + PrlHandle_Free(sdkdom); + return ret; +} + +int +prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) +{ + parallelsConnPtr 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; + + if (def->nfss != 1 || + def->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE) { + + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("There must be only 1 template FS for " + "container creation")); + return -1; + } + + confParam.nVmType = PVT_CT; + confParam.sConfigSample = "vswap.1024MB"; + confParam.nOsVersion = 0; + + job = PrlSrv_GetDefaultVmConfig(privconn->server, &confParam, 0); + if (!(result = getJobResult(job, privconn->jobTimeout))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, &sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmCfg_SetOsTemplate(sdkdom, def->fss[0]->src); + prlsdkCheckRetGoto(pret, cleanup); + + ret = prlsdkDoApplyConfig(sdkdom, def); + if (ret) + return ret; + + job = PrlVm_Reg(sdkdom, "", 1); + ret = waitJob(job, privconn->jobTimeout); + + cleanup: + PrlHandle_Free(sdkdom); + return ret; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 91a829e..193d8ee 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -43,3 +43,5 @@ int prlsdkApplyConfig(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr new); +int prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def); +int prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def); -- 1.9.3

First, we don't need to call prlsdkApplyConfig after creating new VM or containers, because it's done in functions prlsdkCreateVm and prlsdkCreateCt. Also we don't need to calls prlsdkAddDomain here, because new domain will be added to domains list from the events handler. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index c9da259..5633eab 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -661,10 +661,9 @@ static virDomainPtr parallelsDomainDefineXML(virConnectPtr conn, const char *xml) { parallelsConnPtr privconn = conn->privateData; - virDomainPtr ret = NULL; + virDomainPtr retdom = NULL; virDomainDefPtr def; virDomainObjPtr olddom = NULL; - virDomainObjPtr dom = NULL; parallelsDriverLock(privconn); if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, @@ -689,34 +688,23 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) _("Unsupported OS type: %s"), def->os.type); goto cleanup; } - dom = prlsdkAddDomain(privconn, def->uuid); - if (dom) - virObjectUnlock(dom); - else - goto cleanup; - olddom = virDomainObjListFindByName(privconn->domains, def->name); - if (!olddom) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Domain for '%s' is not defined after creation"), - def->name ? def->name : _("(unnamed)")); - goto cleanup; - } - } + } else { + int ret; - if (prlsdkApplyConfig(conn, olddom, def) < 0) { + ret = prlsdkApplyConfig(conn, olddom, def); virObjectUnlock(olddom); - goto cleanup; + if (ret) + goto cleanup; } - virObjectUnlock(olddom); - ret = virGetDomain(conn, def->name, def->uuid); - if (ret) - ret->id = def->id; + retdom = virGetDomain(conn, def->name, def->uuid); + if (retdom) + retdom->id = def->id; cleanup: virDomainDefFree(def); parallelsDriverUnlock(privconn); - return ret; + return retdom; } static int -- 1.9.3

From: Alexander Burluka <aburluka@parallels.com> That function is necessary for proper domain removal in openstack/nova. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 5633eab..a3d9980 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -860,6 +860,24 @@ parallelsConnectDomainEventDeregisterAny(virConnectPtr conn, return ret; } +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 virDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -891,6 +909,7 @@ static virDriver parallelsDriver = { .domainShutdown = prlsdkDomainShutdown, /* 0.10.0 */ .domainCreate = prlsdkDomainCreate, /* 0.10.0 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ + .domainIsActive = parallelsDomainIsActive, /* 1.2.10 */ .connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */ .connectDomainEventDeregisterAny = parallelsConnectDomainEventDeregisterAny, /* 1.2.10 */ .nodeGetCPUMap = parallelsNodeGetCPUMap, /* 1.2.8 */ -- 1.9.3

From: Alexander Burluka <aburluka@parallels.com> domainCreateWithFlags function is used by OpenStack/Nova to boot an instance. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index a3d9980..e0bd5ea 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -878,6 +878,15 @@ static int parallelsDomainIsActive(virDomainPtr domain) return ret; } +static int +parallelsDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) +{ + /* we don't support any create flags */ + virCheckFlags(0, -1); + + return prlsdkDomainCreate(domain); +} + static virDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -908,6 +917,7 @@ static virDriver parallelsDriver = { .domainDestroy = prlsdkDomainDestroy, /* 0.10.0 */ .domainShutdown = prlsdkDomainShutdown, /* 0.10.0 */ .domainCreate = prlsdkDomainCreate, /* 0.10.0 */ + .domainCreateWithFlags = parallelsDomainCreateWithFlags, /* 1.2.10 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ .domainIsActive = parallelsDomainIsActive, /* 1.2.10 */ .connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */ -- 1.9.3

Get cdrom devices list from parallels server in prlsdkLoadDomains and add ability to define a domain with cdroms. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_sdk.c | 70 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index cc796ee..8836a1b 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -446,7 +446,8 @@ prlsdkAddDomainVideoInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) static int prlsdkGetDiskInfo(PRL_HANDLE prldisk, - virDomainDiskDefPtr disk) + virDomainDiskDefPtr disk, + bool isCdrom) { char *buf = NULL; PRL_UINT32 buflen = 0; @@ -461,11 +462,19 @@ prlsdkGetDiskInfo(PRL_HANDLE prldisk, prlsdkCheckRetGoto(pret, cleanup); if (emulatedType == PDT_USE_IMAGE_FILE) { virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); + if (isCdrom) + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_AUTO); + else + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); } else { virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); } + if (isCdrom) + disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + else + disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; + pret = PrlVmDev_GetFriendlyName(prldisk, NULL, &buflen); prlsdkCheckRetGoto(pret, cleanup); @@ -543,7 +552,7 @@ prlsdkAddDomainHardDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) if (!(disk = virDomainDiskDefNew())) goto error; - if (prlsdkGetDiskInfo(hdd, disk) < 0) + if (prlsdkGetDiskInfo(hdd, disk, false) < 0) goto error; PrlHandle_Free(hdd); @@ -563,6 +572,43 @@ prlsdkAddDomainHardDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) } 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())) + goto error; + + if (prlsdkGetDiskInfo(cdrom, disk, true) < 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]; @@ -781,6 +827,9 @@ prlsdkAddDomainHardware(PRL_HANDLE sdkdom, virDomainDefPtr def) if (prlsdkAddDomainHardDisksInfo(sdkdom, def) < 0) goto error; + if (prlsdkAddDomainOpticalDisksInfo(sdkdom, def) < 0) + goto error; + if (prlsdkAddDomainNetInfo(sdkdom, def) < 0) goto error; @@ -2095,9 +2144,11 @@ static int prlsdkCheckNetUnsupportedParams(virDomainNetDefPtr net) static int prlsdkCheckDiskUnsupportedParams(virDomainDiskDefPtr disk) { - if (disk->device != VIR_DOMAIN_DISK_DEVICE_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 are supported " + _("Only hard disks and cdroms are supported " "supported by parallels driver.")); return -1; } @@ -2407,7 +2458,10 @@ static int prlsdkAddDisk(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk) if (prlsdkCheckDiskUnsupportedParams(disk) < 0) return -1; - pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk); + if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk); + else + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_OPTICAL_DISK, &sdkdisk); prlsdkCheckRetGoto(pret, cleanup); pret = PrlVmDev_SetEnabled(sdkdisk, 1); @@ -2417,7 +2471,9 @@ static int prlsdkAddDisk(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk) prlsdkCheckRetGoto(pret, cleanup); if (disk->src->type == VIR_STORAGE_TYPE_FILE) { - if (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) { + if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && + virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Invalid disk format: %d"), disk->src->type); goto cleanup; -- 1.9.3

Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 30 ++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.c | 10 ++++++++++ src/parallels/parallels_sdk.h | 2 ++ 3 files changed, 42 insertions(+) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index e0bd5ea..e35b55a 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -887,6 +887,34 @@ parallelsDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) return prlsdkDomainCreate(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); + virObjectUnlock(dom); + + return ret; +} + +static int +parallelsDomainUndefine(virDomainPtr domain) +{ + return parallelsDomainUndefineFlags(domain, 0); +} + static virDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -919,6 +947,8 @@ static virDriver parallelsDriver = { .domainCreate = prlsdkDomainCreate, /* 0.10.0 */ .domainCreateWithFlags = parallelsDomainCreateWithFlags, /* 1.2.10 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ + .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 */ diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 8836a1b..4921523 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -2685,3 +2685,13 @@ prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) PrlHandle_Free(sdkdom); return ret; } + +int +prlsdkUnregisterDomain(parallelsConnPtr privconn, virDomainObjPtr dom) +{ + parallelsDomObjPtr privdom = dom->privateData; + PRL_HANDLE job; + + job = PrlVm_Unreg(privdom->sdkdom); + return waitJob(job, privconn->jobTimeout); +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 193d8ee..825d98e 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -45,3 +45,5 @@ prlsdkApplyConfig(virConnectPtr conn, virDomainDefPtr new); int prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def); int prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def); +int +prlsdkUnregisterDomain(parallelsConnPtr privconn, virDomainObjPtr dom); -- 1.9.3

On Thursday 23 October 2014 19:58:04 Dmitry Guryanov wrote:
This patch series replaces all code, which used prlctl command to interact with parallels cloud server with calls to parallels sdk functions.
The model of this driver remain almost the same - in creates a list of virDomainObj objects on connect and then functions, which returns different information get info from this list.
But functions, which modify domains (change state, define or undefine domain) don't modify this list directly. On connect driver subscribes to event from PCS and modify the list from that events handler.
It isn't correct, for example you call first virConnectDefineXML to define a new domain and virDomainLookupByName after that. Lookup function may fail, because event from PCS appear slightly later. There are two possible solutions: first is to update privconn->domains in parallelsDomainDefineXML, parallelsDomainCreate, parallelsDomainDestroy e.t.c. So that this list will be up-to-date after modifications, done from the current connections. Disadvantage is that after local modification the list will be updated twice. The second solution is to introduce "dirty" flag in virDomainObj and in the whole list. Functions, which change domain state should set this flag virDomainObj and lookup functions like virDomainObjListFindByUUID should wait until this flag become cleared. It can be done with condition variables. This method is more complex and requires modifications in common libvirt code. So I've implemented the first method.
So cached list of domains will be always up-to-date either after modifications from currect connection or after modifications by another tools (like prlctl) or libvirt connections.
Alexander Burluka (4): parallels: get domain info with SDK parallels: handle events from parallels server parallels: added function virDomainIsActive() parallels: Add domainCreateWithFlags() function.
Dmitry Guryanov (8): parallels: move IS_CT macro to parallels_utils.h parallels: move parallelsDomNotFoundError to parallels_utils.h parallels: reimplement functions, which change domain state parallels: rewrite parallelsApplyConfig with SDK parallels: create VMs and containers with sdk parallels: fix parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags
src/parallels/parallels_driver.c | 2448 +++++++------------------------------ src/parallels/parallels_sdk.c | 2456 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 19 + src/parallels/parallels_utils.h | 11 + 4 files changed, 2939 insertions(+), 1995 deletions(-)
-- Dmitry Guryanov
participants (1)
-
Dmitry Guryanov