[libvirt] [PATCH v4 00/15] parallels: rewrite driver with parallels SDK

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. Changes in v2: * Rebase to latest libvirt sources * Use only "parallels" prefix for functions in parallelsDriver, so that make check will pass * Update privconn->domains in case we change something from current connection. Changes in v3: * in parallels: get domain info with SDK: replace + case VIR_ARCH_X86_64: with + case PCM_CPU_MODE_64: Changes in v4: * handle onReboot, onPoweroff and onCrash properly * handle disks cache mode * don't set net interface name if virDomainNetDef.ifname is NULL * improve error handling 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 (11): 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: refactor parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags parallels: return PRL_RESULT from waitJob and getJobResult parallels: fix getJobResultHelper parallels: report proper error in Create/Destroy/Suspend e.t.c. src/parallels/parallels_driver.c | 2456 +++++++----------------------------- src/parallels/parallels_sdk.c | 2544 +++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 25 + src/parallels/parallels_utils.h | 11 + 4 files changed, 3033 insertions(+), 2003 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 808dc4a..0085c8f 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 0d770c5..163d99b 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 to 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 | 1018 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 4 + src/parallels/parallels_utils.h | 1 + 4 files changed, 1029 insertions(+), 741 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 0085c8f..8db4997 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..a500e4c 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,1008 @@ 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; +} + +static void +prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr) +{ + virUUIDFormat(uuid, uuidstr + 1); + + uuidstr[0] = '{'; + uuidstr[VIR_UUID_STRING_BUFLEN] = '}'; + uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0'; +} + +PRL_HANDLE +prlsdkSdkDomainLookupByUUID(parallelsConnPtr privconn, const unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + + prlsdkUUIDFormat(uuid, uuidstr); + + if (prlsdkSdkDomainLookup(privconn, uuidstr, + PGVC_SEARCH_BY_UUID, &sdkdom) < 0) { + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + return PRL_INVALID_HANDLE; + } + + return sdkdom; +} + +static int +prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid) +{ + char *tmp = NULL; + int ret = -1; + + virCheckNonNullArgGoto(uuidstr, error); + virCheckNonNullArgGoto(uuid, error); + + if (VIR_STRDUP(tmp, uuidstr) < 0) + goto error; + + tmp[strlen(tmp) - 1] = '\0'; + + /* trim curly braces */ + if (virUUIDParse(tmp + 1, uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("UUID in config file malformed")); + ret = -1; + goto error; + } + + ret = 0; + error: + VIR_FREE(tmp); + return ret; +} + +static int +prlsdkGetDomainIds(PRL_HANDLE sdkdom, + char **name, + unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 len; + PRL_RESULT pret; + + len = 0; + /* get name length */ + pret = PrlVmCfg_GetName(sdkdom, NULL, &len); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(*name, len) < 0) + goto error; + + PrlVmCfg_GetName(sdkdom, *name, &len); + prlsdkCheckRetGoto(pret, error); + + len = sizeof(uuidstr); + PrlVmCfg_GetUuid(sdkdom, uuidstr, &len); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + goto error; + + return 0; + + error: + VIR_FREE(*name); + return -1; +} + +static int +prlsdkGetDomainState(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; + + def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; + def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; + def->onCrash = VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY; + + /* get RAM parameters */ + pret = PrlVmCfg_GetRamSize(sdkdom, &ram); + prlsdkCheckRetGoto(pret, error); + 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; + + dom = virDomainObjListFindByUUID(privconn->domains, uuid); + if (dom) { + /* domain is already in the list */ + return dom; + } + + sdkdom = prlsdkSdkDomainLookupByUUID(privconn, uuid); + if (sdkdom == PRL_INVALID_HANDLE) + return NULL; + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + return dom; +} 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 163d99b..e054b08 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -62,6 +62,7 @@ struct parallelsDomObj { char *uuid; char *home; virBitmapPtr cpumask; + PRL_HANDLE sdkdom; }; typedef struct parallelsDomObj *parallelsDomObjPtr; -- 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 8db4997..83995d5 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 e054b08..5c19e2f 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

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 a 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 | 295 ++++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 2 + 3 files changed, 341 insertions(+), 2 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 83995d5..e145766 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -223,6 +223,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)) @@ -234,6 +240,7 @@ parallelsOpenDefault(virConnectPtr conn) virObjectUnref(privconn->domains); virObjectUnref(privconn->caps); virStoragePoolObjListFree(&privconn->pools); + virObjectEventStateFree(privconn->domainEventState); prlsdkDisconnect(privconn); prlsdkDeinit(); err_free: @@ -280,9 +287,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(); @@ -1717,6 +1726,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 virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, @@ -1749,6 +1793,8 @@ static virHypervisorDriver 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 a500e4c..21a4770 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" @@ -1140,9 +1141,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, @@ -1257,3 +1256,295 @@ 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) { + /* domain was removed from the list from the libvirt + * API function in current connection */ + return PRL_ERR_SUCCESS; + } + + 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

Change domain state using parallels SDK functions instead of prlctl command. We don't need to send events from these functions now, becase events handler will send them. But we still need to update virDomainObj in privconn->domains. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 139 +++++++-------------------------------- src/parallels/parallels_sdk.c | 70 ++++++++++++++++++++ src/parallels/parallels_sdk.h | 10 +++ 3 files changed, 105 insertions(+), 114 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index e145766..658969f 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) @@ -1762,6 +1648,31 @@ parallelsConnectDomainEventDeregisterAny(virConnectPtr conn, return ret; } +static int parallelsDomainSuspend(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkPause); +} + +static int parallelsDomainResume(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkResume); +} + +static int parallelsDomainCreate(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStart); +} + +static int parallelsDomainDestroy(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkKill); +} + +static int parallelsDomainShutdown(virDomainPtr domain) +{ + return prlsdkDomainChangeState(domain, prlsdkStop); +} + static virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 21a4770..1a1e767 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1548,3 +1548,73 @@ void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn) if (PRL_FAILED(ret)) logPrlError(ret); } + +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); +} + +int prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(privconn, sdkdom, PSM_KILL); +} + +int prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + return prlsdkStopEx(privconn, sdkdom, PSM_SHUTDOWN); +} + +int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Pause(sdkdom, false); + return waitJob(job, privconn->jobTimeout); +} + +int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + + job = PrlVm_Resume(sdkdom); + return waitJob(job, privconn->jobTimeout); +} + +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; + if ((ret = chstate(privconn, pdom->sdkdom))) + goto cleanup; + + ret = prlsdkUpdateDomain(privconn, dom); + + cleanup: + virObjectUnlock(dom); + return ret; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 5ffbf53..1e26672 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -34,3 +34,13 @@ virDomainObjPtr prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn); void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn); +int prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +int prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +int prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom); + +typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +int +prlsdkDomainChangeState(virDomainPtr domain, + prlsdkChangeStateFunc chstate); -- 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 | 952 +++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 4 + 3 files changed, 957 insertions(+), 736 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 658969f..55ee003 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 1a1e767..ae220e6 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" @@ -1618,3 +1619,954 @@ prlsdkDomainChangeState(virDomainPtr domain, virObjectUnlock(dom); return ret; } + +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 != VIR_DOMAIN_LIFECYCLE_RESTART || + def->onPoweroff != VIR_DOMAIN_LIFECYCLE_DESTROY || + def->onCrash != VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY) { + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("on_reboot, on_poweroff and on_crash parameters " + "are not supported by 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->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 = + PSP_SERIAL_SOCKET_SERVER; + char *path; + int ret = -1; + + if (prlsdkCheckSerialUnsupportedParams(chr) < 0) + return -1; + + pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_SERIAL_PORT, &sdkchr); + prlsdkCheckRetGoto(pret, cleanup); + + switch (chr->source.type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + emutype = PDT_USE_REAL_DEVICE; + path = chr->source.data.file.path; + break; + case VIR_DOMAIN_CHR_TYPE_FILE: + emutype = PDT_USE_OUTPUT_FILE; + path = chr->source.data.file.path; + break; + case VIR_DOMAIN_CHR_TYPE_UNIX: + emutype = PDT_USE_SERIAL_PORT_SOCKET_MODE; + path = chr->source.data.nix.path; + if (chr->source.data.nix.listen) + socket_mode = PSP_SERIAL_SOCKET_SERVER; + else + socket_mode = PSP_SERIAL_SOCKET_CLIENT; + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("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); + + if (net->ifname) { + pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname); + prlsdkCheckRetGoto(pret, cleanup); + } + + prlsdkFormatMac(&net->mac, macstr); + pret = PrlVmDevNet_SetMacAddress(sdknet, macstr); + prlsdkCheckRetGoto(pret, cleanup); + + if (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); + + switch (disk->cachemode) { + case VIR_DOMAIN_DISK_CACHE_DISABLE: + pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_FALSE); + prlsdkCheckRetGoto(pret, cleanup); + break; + case VIR_DOMAIN_DISK_CACHE_WRITEBACK: + pret = PrlVmCfg_SetDiskCacheWriteBack(sdkdom, PRL_TRUE); + prlsdkCheckRetGoto(pret, cleanup); + break; + case VIR_DOMAIN_DISK_CACHE_DEFAULT: + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Specified disk cache mode is not " + "supported by Parallels Cloud Server.")); + goto cleanup; + } + + return 0; + cleanup: + PrlHandle_Free(sdkdisk); + return ret; +} + +static int +prlsdkDoApplyConfig(PRL_HANDLE sdkdom, + virDomainDefPtr def) +{ + PRL_RESULT pret; + size_t i; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + + if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0) + return -1; + + if (def->description) { + pret = PrlVmCfg_SetDescription(sdkdom, def->description); + prlsdkCheckRetGoto(pret, error); + } + + if (def->name) { + pret = PrlVmCfg_SetName(sdkdom, def->name); + prlsdkCheckRetGoto(pret, error); + } + + if (def->uuid) { + prlsdkUUIDFormat(def->uuid, uuidstr); + + pret = PrlVmCfg_SetUuid(sdkdom, uuidstr); + prlsdkCheckRetGoto(pret, error); + } + + pret = PrlVmCfg_SetRamSize(sdkdom, 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); + + if (ret == 0) { + 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 1e26672..8de077c 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -44,3 +44,7 @@ typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdo int prlsdkDomainChangeState(virDomainPtr domain, prlsdkChangeStateFunc chstate); +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 | 85 +++++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 2 + 3 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 55ee003..582ffdb 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 ae220e6..1cd2291 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -2538,7 +2538,6 @@ prlsdkDoApplyConfig(PRL_HANDLE sdkdom, error: return -1; - } int @@ -2570,3 +2569,87 @@ 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); + if (ret) + goto cleanup; + + 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 && (def->nfss > 1 || + def->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE)) { + + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("There must be no more than 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); + + if (def->nfss == 1) { + pret = PrlVmCfg_SetOsTemplate(sdkdom, def->fss[0]->src); + prlsdkCheckRetGoto(pret, cleanup); + } + + ret = prlsdkDoApplyConfig(sdkdom, def); + if (ret) + goto cleanup; + + job = PrlVm_RegEx(sdkdom, "", PACF_NON_INTERACTIVE_MODE); + 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 8de077c..b654c2a 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -48,3 +48,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. No need to check, if domain exists in the list after prlsdkAddDomain. Also organize code, so that we can call virObjectUnlock in one place. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 35 ++++++++++++++--------------------- src/parallels/parallels_sdk.c | 2 +- src/parallels/parallels_sdk.h | 1 + 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 582ffdb..955516a 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,28 @@ 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 + + olddom = prlsdkAddDomain(privconn, def->uuid); + if (!olddom) 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)")); + } else { + if (prlsdkApplyConfig(conn, olddom, def)) goto cleanup; - } - } - if (prlsdkApplyConfig(conn, olddom, def) < 0) { - virObjectUnlock(olddom); - goto cleanup; + if (prlsdkUpdateDomain(privconn, olddom)) + 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: + if (olddom) + virObjectUnlock(olddom); virDomainDefFree(def); parallelsDriverUnlock(privconn); - return ret; + return retdom; } static int diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 1cd2291..967c94a 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1258,7 +1258,7 @@ prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid) return dom; } -static int +int prlsdkUpdateDomain(parallelsConnPtr privconn, virDomainObjPtr dom) { PRL_HANDLE job; diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index b654c2a..1fdef1a 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -32,6 +32,7 @@ int prlsdkLoadDomains(parallelsConnPtr privconn); virDomainObjPtr prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); +int prlsdkUpdateDomain(parallelsConnPtr privconn, virDomainObjPtr dom); int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn); void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn); int prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom); -- 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 955516a..998f9ae 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -890,6 +890,24 @@ static int parallelsDomainShutdown(virDomainPtr domain) return prlsdkDomainChangeState(domain, prlsdkStop); } +static int parallelsDomainIsActive(virDomainPtr domain) +{ + parallelsConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom = NULL; + int ret = -1; + + dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); + if (dom == NULL) { + parallelsDomNotFoundError(domain); + return -1; + } + + ret = virDomainObjIsActive(dom); + virObjectUnlock(dom); + + return ret; +} + static virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -921,6 +939,7 @@ static virHypervisorDriver parallelsDriver = { .domainShutdown = parallelsDomainShutdown, /* 0.10.0 */ .domainCreate = parallelsDomainCreate, /* 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 998f9ae..522c39f 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -908,6 +908,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 parallelsDomainCreate(domain); +} + static virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -938,6 +947,7 @@ static virHypervisorDriver parallelsDriver = { .domainDestroy = parallelsDomainDestroy, /* 0.10.0 */ .domainShutdown = parallelsDomainShutdown, /* 0.10.0 */ .domainCreate = parallelsDomainCreate, /* 0.10.0 */ + .domainCreateWithFlags = parallelsDomainCreateWithFlags, /* 1.2.10 */ .domainDefineXML = parallelsDomainDefineXML, /* 0.10.0 */ .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 967c94a..7680b74 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -452,7 +452,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; @@ -467,11 +468,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); @@ -549,7 +558,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); @@ -569,6 +578,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]; @@ -787,6 +833,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; @@ -2091,9 +2140,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; } @@ -2399,7 +2450,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); @@ -2409,7 +2463,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 | 26 ++++++++++++++++++++++++++ src/parallels/parallels_sdk.c | 18 ++++++++++++++++++ src/parallels/parallels_sdk.h | 2 ++ 3 files changed, 46 insertions(+) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 522c39f..08d2e30 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -917,6 +917,30 @@ parallelsDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) return parallelsDomainCreate(domain); } +static int +parallelsDomainUndefineFlags(virDomainPtr domain, + unsigned int flags) +{ + parallelsConnPtr privconn = domain->conn->privateData; + virDomainObjPtr dom = NULL; + + virCheckFlags(0, -1); + + dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); + if (dom == NULL) { + parallelsDomNotFoundError(domain); + return -1; + } + + return prlsdkUnregisterDomain(privconn, dom); +} + +static int +parallelsDomainUndefine(virDomainPtr domain) +{ + return parallelsDomainUndefineFlags(domain, 0); +} + static virHypervisorDriver parallelsDriver = { .no = VIR_DRV_PARALLELS, .name = "Parallels", @@ -949,6 +973,8 @@ static virHypervisorDriver parallelsDriver = { .domainCreate = parallelsDomainCreate, /* 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 7680b74..d8d9eae 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -2709,3 +2709,21 @@ 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); + if (waitJob(job, privconn->jobTimeout)) + return -1; + + if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) < 0) + return -1; + + virDomainObjListRemove(privconn->domains, dom); + return 0; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index 1fdef1a..dee9359 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -51,3 +51,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

Return error code, returned by parallels SDK from waitJob and getJobResult, so that caller can handle different errors. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_sdk.c | 67 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index d8d9eae..ad0bda1 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -131,13 +131,12 @@ logPrlEventErrorHelper(PRL_HANDLE event, const char *filename, logPrlEventErrorHelper(event, __FILE__, \ __FUNCTION__, __LINE__) -static PRL_HANDLE -getJobResultHelper(PRL_HANDLE job, unsigned int timeout, +static PRL_RESULT +getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result, const char *filename, const char *funcname, size_t linenr) { PRL_RESULT ret, retCode; - PRL_HANDLE result = NULL; if ((ret = PrlJob_Wait(job, timeout))) { logPrlErrorHelper(ret, filename, funcname, linenr); @@ -163,36 +162,37 @@ getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PrlHandle_Free(err_handle); } else { - ret = PrlJob_GetResult(job, &result); + ret = PrlJob_GetResult(job, result); if (PRL_FAILED(ret)) { logPrlErrorHelper(ret, filename, funcname, linenr); - PrlHandle_Free(result); - result = NULL; + PrlHandle_Free(*result); + *result = NULL; goto cleanup; } - } + } + ret = PRL_ERR_SUCCESS; cleanup: PrlHandle_Free(job); - return result; + return ret; } -#define getJobResult(job, timeout) \ - getJobResultHelper(job, timeout, __FILE__, \ +#define getJobResult(job, timeout, result) \ + getJobResultHelper(job, timeout, result, __FILE__, \ __FUNCTION__, __LINE__) -static int +static PRL_RESULT waitJobHelper(PRL_HANDLE job, unsigned int timeout, const char *filename, const char *funcname, size_t linenr) { - PRL_HANDLE result = NULL; - - result = getJobResultHelper(job, timeout, filename, funcname, linenr); - if (result) - PrlHandle_Free(result); + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_RESULT ret; - return result ? 0 : -1; + ret = getJobResultHelper(job, timeout, &result, + filename, funcname, linenr); + PrlHandle_Free(result); + return ret; } #define waitJob(job, timeout) \ @@ -267,7 +267,7 @@ prlsdkSdkDomainLookup(parallelsConnPtr privconn, int ret = -1; job = PrlSrv_GetVmConfig(privconn->server, id, flags); - if (!(result = getJobResult(job, privconn->jobTimeout))) + if (PRL_FAILED(getJobResult(job, privconn->jobTimeout, &result))) goto cleanup; pret = PrlResult_GetParamByIndex(result, 0, sdkdom); @@ -384,7 +384,7 @@ prlsdkGetDomainState(parallelsConnPtr privconn, job = PrlVm_GetState(sdkdom); - if (!(result = getJobResult(job, privconn->jobTimeout))) + if (PRL_FAILED(getJobResult(job, privconn->jobTimeout, &result))) goto cleanup; pret = PrlResult_GetParamByIndex(result, 0, &vmInfo); @@ -1254,7 +1254,7 @@ prlsdkLoadDomains(parallelsConnPtr privconn) job = PrlSrv_GetVmListEx(privconn->server, PVTF_VM | PVTF_CT); - if (!(result = getJobResult(job, privconn->jobTimeout))) + if (PRL_FAILED(getJobResult(job, privconn->jobTimeout, &result))) return -1; pret = PrlResult_GetParamsCount(result, ¶msCount); @@ -1604,7 +1604,7 @@ 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); + return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; } static int prlsdkStopEx(parallelsConnPtr privconn, @@ -1614,7 +1614,7 @@ static int prlsdkStopEx(parallelsConnPtr privconn, PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_StopEx(sdkdom, mode, 0); - return waitJob(job, privconn->jobTimeout); + return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; } int prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom) @@ -1632,7 +1632,7 @@ int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom) PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_Pause(sdkdom, false); - return waitJob(job, privconn->jobTimeout); + return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; } int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) @@ -1640,7 +1640,7 @@ int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_Resume(sdkdom); - return waitJob(job, privconn->jobTimeout); + return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; } int @@ -2611,14 +2611,15 @@ prlsdkApplyConfig(virConnectPtr conn, return -1; job = PrlVm_BeginEdit(sdkdom); - if (waitJob(job, privconn->jobTimeout) < 0) + if (PRL_FAILED(waitJob(job, privconn->jobTimeout))) return -1; ret = prlsdkDoApplyConfig(sdkdom, new); if (ret == 0) { job = PrlVm_Commit(sdkdom); - ret = waitJob(job, privconn->jobTimeout); + if (PRL_FAILED(waitJob(job, privconn->jobTimeout))) + ret = -1; } PrlHandle_Free(sdkdom); @@ -2641,7 +2642,7 @@ prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def) prlsdkCheckRetGoto(pret, cleanup); job = PrlSrv_GetSrvConfig(privconn->server); - if (!(result = getJobResult(job, privconn->jobTimeout))) + if (PRL_FAILED(getJobResult(job, privconn->jobTimeout, &result))) goto cleanup; pret = PrlResult_GetParamByIndex(result, 0, &srvconf); @@ -2655,7 +2656,8 @@ prlsdkCreateVm(virConnectPtr conn, virDomainDefPtr def) goto cleanup; job = PrlVm_Reg(sdkdom, "", 1); - ret = waitJob(job, privconn->jobTimeout); + if (PRL_FAILED(waitJob(job, privconn->jobTimeout))) + ret = -1; cleanup: PrlHandle_Free(sdkdom); @@ -2687,7 +2689,7 @@ prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) confParam.nOsVersion = 0; job = PrlSrv_GetDefaultVmConfig(privconn->server, &confParam, 0); - if (!(result = getJobResult(job, privconn->jobTimeout))) + if (PRL_FAILED(getJobResult(job, privconn->jobTimeout, &result))) goto cleanup; pret = PrlResult_GetParamByIndex(result, 0, &sdkdom); @@ -2703,11 +2705,12 @@ prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def) goto cleanup; job = PrlVm_RegEx(sdkdom, "", PACF_NON_INTERACTIVE_MODE); - ret = waitJob(job, privconn->jobTimeout); + if (PRL_FAILED(waitJob(job, privconn->jobTimeout))) + ret = -1; cleanup: PrlHandle_Free(sdkdom); - return ret; + return -1; } int @@ -2717,7 +2720,7 @@ prlsdkUnregisterDomain(parallelsConnPtr privconn, virDomainObjPtr dom) PRL_HANDLE job; job = PrlVm_Unreg(privdom->sdkdom); - if (waitJob(job, privconn->jobTimeout)) + if (PRL_FAILED(waitJob(job, privconn->jobTimeout))) return -1; if (prlsdkSendEvent(privconn, dom, VIR_DOMAIN_EVENT_UNDEFINED, -- 1.9.3

When PrlJob_GetRetCode sets second argument to error value it means sdk function failed and we must return error from getJobResultHelper. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_sdk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index ad0bda1..d183994 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -161,6 +161,7 @@ getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result, logPrlErrorHelper(retCode, filename, funcname, linenr); PrlHandle_Free(err_handle); + ret = retCode; } else { ret = PrlJob_GetResult(job, result); if (PRL_FAILED(ret)) { @@ -169,8 +170,9 @@ getJobResultHelper(PRL_HANDLE job, unsigned int timeout, PRL_HANDLE *result, *result = NULL; goto cleanup; } + + ret = PRL_ERR_SUCCESS; } - ret = PRL_ERR_SUCCESS; cleanup: PrlHandle_Free(job); -- 1.9.3

If we want to perform some operation and domain state is not suitable for that operation, we should report error VIR_ERR_OPERATION_INVALID. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_sdk.c | 37 +++++++++++++++++++++++++++---------- src/parallels/parallels_sdk.h | 2 +- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index d183994..579a163 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -1601,7 +1601,7 @@ void prlsdkUnsubscribeFromPCSEvents(parallelsConnPtr privconn) logPrlError(ret); } -int prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +PRL_RESULT prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom) { PRL_HANDLE job = PRL_INVALID_HANDLE; @@ -1609,40 +1609,40 @@ int prlsdkStart(parallelsConnPtr privconn, PRL_HANDLE sdkdom) return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; } -static int prlsdkStopEx(parallelsConnPtr privconn, +static PRL_RESULT prlsdkStopEx(parallelsConnPtr privconn, PRL_HANDLE sdkdom, PRL_UINT32 mode) { PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_StopEx(sdkdom, mode, 0); - return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; + return waitJob(job, privconn->jobTimeout); } -int prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +PRL_RESULT prlsdkKill(parallelsConnPtr privconn, PRL_HANDLE sdkdom) { return prlsdkStopEx(privconn, sdkdom, PSM_KILL); } -int prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +PRL_RESULT prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom) { return prlsdkStopEx(privconn, sdkdom, PSM_SHUTDOWN); } -int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +PRL_RESULT prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom) { PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_Pause(sdkdom, false); - return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; + return waitJob(job, privconn->jobTimeout); } -int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) +PRL_RESULT prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom) { PRL_HANDLE job = PRL_INVALID_HANDLE; job = PrlVm_Resume(sdkdom); - return PRL_FAILED(waitJob(job, privconn->jobTimeout)) ? -1 : 0; + return waitJob(job, privconn->jobTimeout); } int @@ -1652,7 +1652,9 @@ prlsdkDomainChangeState(virDomainPtr domain, parallelsConnPtr privconn = domain->conn->privateData; virDomainObjPtr dom; parallelsDomObjPtr pdom; + PRL_RESULT pret; int ret = -1; + virErrorNumber virerr; dom = virDomainObjListFindByUUID(privconn->domains, domain->uuid); if (dom == NULL) { @@ -1661,8 +1663,23 @@ prlsdkDomainChangeState(virDomainPtr domain, } pdom = dom->privateData; - if ((ret = chstate(privconn, pdom->sdkdom))) + pret = chstate(privconn, pdom->sdkdom); + virReportError(VIR_ERR_OPERATION_FAILED, "Can't change domain state: %d", pret); + if (PRL_FAILED(pret)) { + virResetLastError(); + + switch (pret) { + case PRL_ERR_DISP_VM_IS_NOT_STARTED: + case PRL_ERR_DISP_VM_IS_NOT_STOPPED: + virerr = VIR_ERR_OPERATION_INVALID; + break; + default: + virerr = VIR_ERR_OPERATION_FAILED; + } + + virReportError(virerr, "Can't change domain state."); goto cleanup; + } ret = prlsdkUpdateDomain(privconn, dom); diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index dee9359..694c19b 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -41,7 +41,7 @@ int prlsdkStop(parallelsConnPtr privconn, PRL_HANDLE sdkdom); int prlsdkPause(parallelsConnPtr privconn, PRL_HANDLE sdkdom); int prlsdkResume(parallelsConnPtr privconn, PRL_HANDLE sdkdom); -typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdom); +typedef PRL_RESULT (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdom); int prlsdkDomainChangeState(virDomainPtr domain, prlsdkChangeStateFunc chstate); -- 1.9.3

01.12.2014 18:38, Dmitry Guryanov пишет:
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.
Changes in v2: * Rebase to latest libvirt sources * Use only "parallels" prefix for functions in parallelsDriver, so that make check will pass * Update privconn->domains in case we change something from current connection.
Changes in v3: * in parallels: get domain info with SDK: replace + case VIR_ARCH_X86_64: with + case PCM_CPU_MODE_64:
Changes in v4: * handle onReboot, onPoweroff and onCrash properly * handle disks cache mode * don't set net interface name if virDomainNetDef.ifname is NULL * improve error handling
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 (11): 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: refactor parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags parallels: return PRL_RESULT from waitJob and getJobResult parallels: fix getJobResultHelper parallels: report proper error in Create/Destroy/Suspend e.t.c.
src/parallels/parallels_driver.c | 2456 +++++++----------------------------- src/parallels/parallels_sdk.c | 2544 +++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 25 + src/parallels/parallels_utils.h | 11 + 4 files changed, 3033 insertions(+), 2003 deletions(-)
Series looks good to me as a first step to switch to SDK.

On 12/01/14 19:49, Maxim Nestratov wrote:
01.12.2014 18:38, Dmitry Guryanov пишет:
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.
Changes in v2: * Rebase to latest libvirt sources * Use only "parallels" prefix for functions in parallelsDriver, so that make check will pass * Update privconn->domains in case we change something from current connection.
Changes in v3: * in parallels: get domain info with SDK: replace + case VIR_ARCH_X86_64: with + case PCM_CPU_MODE_64:
Changes in v4: * handle onReboot, onPoweroff and onCrash properly * handle disks cache mode * don't set net interface name if virDomainNetDef.ifname is NULL * improve error handling
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 (11): 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: refactor parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags parallels: return PRL_RESULT from waitJob and getJobResult parallels: fix getJobResultHelper parallels: report proper error in Create/Destroy/Suspend e.t.c.
src/parallels/parallels_driver.c | 2456 +++++++----------------------------- src/parallels/parallels_sdk.c | 2544 +++++++++++++++++++++++++++++++++++++- src/parallels/parallels_sdk.h | 25 + src/parallels/parallels_utils.h | 11 + 4 files changed, 3033 insertions(+), 2003 deletions(-)
Series looks good to me as a first step to switch to SDK.
I'll take over from here. I need to install the SDK first so I can make sure that everything compiles before pushing. I'll hope I get to push this this week. Peter

On Tuesday 02 December 2014 14:15:26 Peter Krempa wrote:
On 12/01/14 19:49, Maxim Nestratov wrote:
01.12.2014 18:38, Dmitry Guryanov пишет:
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.
Changes in v2: * Rebase to latest libvirt sources * Use only "parallels" prefix for functions in parallelsDriver,
so that make check will pass
* Update privconn->domains in case we change something from current
connection.
Changes in v3: * in parallels: get domain info with SDK: replace + case VIR_ARCH_X86_64: with + case PCM_CPU_MODE_64:
Changes in v4: * handle onReboot, onPoweroff and onCrash properly * handle disks cache mode * don't set net interface name if virDomainNetDef.ifname is NULL * improve error handling
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 (11): 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: refactor parallelsDomainDefineXML parallels: add cdroms support parallels: implement domainUndefine and domainUndefineFlags parallels: return PRL_RESULT from waitJob and getJobResult parallels: fix getJobResultHelper parallels: report proper error in Create/Destroy/Suspend e.t.c.
src/parallels/parallels_driver.c | 2456
+++++++-----------------------------
src/parallels/parallels_sdk.c | 2544
+++++++++++++++++++++++++++++++++++++-
src/parallels/parallels_sdk.h | 25 + src/parallels/parallels_utils.h | 11 + 4 files changed, 3033 insertions(+), 2003 deletions(-)
Series looks good to me as a first step to switch to SDK.
I'll take over from here. I need to install the SDK first so I can make sure that everything compiles before pushing. I'll hope I get to push this this week.
Thanks! BTW, it fails to compile now, the patch "parallels: fix compilation of parallels_storage.c" fixes it.
Peter
-- Dmitry Guryanov

On 12/01/14 16:38, 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.
So, I finally went ahead and pushed this series as we agreed on the post-freeze approach. I have following notes though: * please run make syntax-check before sending patches (and make sure the cppi package is installed) The series contained a few patches with whitespace errors in macro definitions. * please compile with --enable-compile-warnings=error There were a few warnings that hinted to unused variables and one bad constant use. Additionally it will make obvious my next point... * the parallels SDK [1] produces warnings when included I had to add "-Wno-strict-prototypes" to PARALLELS_SDK_CFLAGS otherwise the compiler would complain to mistakes in the header file. I didn't chase them any further though to see why. * The parallels SDK doesn't provide a pkg-config description file Libvirt tests for the "parallels-sdk" pkg-config module, but the default installation doesn't provide it. It's then extremely user-unfriendly to hack the paths so that it actually compiles. Please provide that desc in the installer. * The parallels SDK installed needs root even for unpacking I personally don't like tools that install everything. The self-installer [1] has an option to just unpack the files. For this option the root privilege shouldn't be required ... it's just ridiulous. Anyways, thanks for contributing. It would also be really helpful to provide the pkg-config file. Peter [1] - I used the package at: http://download.cloudserver.parallels.com/server/pcs/en_us/parallels/6/updat...

On 12/09/2014 11:57 AM, Peter Krempa wrote:
* The parallels SDK installed needs root even for unpacking
I personally don't like tools that install everything. The self-installer [1] has an option to just unpack the files. For this option the root privilege shouldn't be required ... it's just ridiulous.
[1] - I used the package at: http://download.cloudserver.parallels.com/server/pcs/en_us/parallels/6/updat...
Can you paste the sequence of shell commands (if you still have them in your history) that you used for installing the SDK? Having the recipe in the list archives will make it easier for others to at least help in compile-testing global changes that happen to touch parallels code. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Tuesday 09 December 2014 19:57:51 Peter Krempa wrote:
On 12/01/14 16:38, 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.
So, I finally went ahead and pushed this series as we agreed on the post-freeze approach. I have following notes though:
Thanks, Peter!
* please run make syntax-check before sending patches (and make sure the cppi package is installed)
The series contained a few patches with whitespace errors in macro definitions.
* please compile with --enable-compile-warnings=error
There were a few warnings that hinted to unused variables and one bad constant use.
Sorry about that.
Additionally it will make obvious my next point...
* the parallels SDK [1] produces warnings when included
I had to add "-Wno-strict-prototypes" to PARALLELS_SDK_CFLAGS otherwise the compiler would complain to mistakes in the header file. I didn't chase them any further though to see why.
* The parallels SDK doesn't provide a pkg-config description file
Libvirt tests for the "parallels-sdk" pkg-config module, but the default installation doesn't provide it. It's then extremely user-unfriendly to hack the paths so that it actually compiles.
Please provide that desc in the installer.
* The parallels SDK installed needs root even for unpacking
I personally don't like tools that install everything. The self-installer [1] has an option to just unpack the files. For this option the root privilege shouldn't be required ... it's just ridiulous.
You've installed commercial version of this SDK, we haven't prepared binary packages for opensource version yet, sources can be found here - https://github.com/CloudServer/parallels-sdk.
Anyways, thanks for contributing. It would also be really helpful to provide the pkg-config file.
Peter
[1] - I used the package at: http://download.cloudserver.parallels.com/server/pcs/en_us/parallels/6/updat e8/parallels-virtualization-sdk-6.8.23687.1081632.run
-- Dmitry Guryanov
participants (4)
-
Dmitry Guryanov
-
Eric Blake
-
Maxim Nestratov
-
Peter Krempa