From: Alexander Burluka <aburluka@xxxxxxxxxxxxx> Obtain information about domains using parallels sdk instead of prlctl. prlsdkLoadDomains functions behaves as former parallelsLoadDomains with NULL as second parameter (name) - it fills parallelsConn.domains list. prlsdkLoadDomain is now able update specified domain by given virDomainObjPtr. Signed-off-by: Dmitry Guryanov <dguryanov@xxxxxxxxxxxxx> --- src/parallels/parallels_driver.c | 747 +--------------------------- src/parallels/parallels_sdk.c | 1002 ++++++++++++++++++++++++++++++++++++++ src/parallels/parallels_sdk.h | 4 + src/parallels/parallels_utils.h | 1 + 4 files changed, 1013 insertions(+), 741 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 1760d08..7a60401 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -49,7 +49,6 @@ #include "virfile.h" #include "virstoragefile.h" #include "nodeinfo.h" -#include "c-ctype.h" #include "virstring.h" #include "cpu/cpu.h" @@ -99,21 +98,6 @@ parallelsDriverUnlock(parallelsConnPtr driver) virMutexUnlock(&driver->lock); } - -static void -parallelsDomObjFreePrivate(void *p) -{ - parallelsDomObjPtr pdom = p; - - if (!pdom) - return; - - virBitmapFree(pdom->cpumask); - VIR_FREE(pdom->uuid); - VIR_FREE(pdom->home); - VIR_FREE(p); -}; - static virCapsPtr parallelsBuildCapabilities(void) { @@ -191,729 +175,6 @@ parallelsConnectGetCapabilities(virConnectPtr conn) } static int -parallelsGetSerialInfo(virDomainChrDefPtr chr, - const char *name, virJSONValuePtr value) -{ - const char *tmp; - - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; - if (virStrToLong_i(name + strlen("serial"), - NULL, 10, &chr->target.port) < 0) { - parallelsParseError(); - return -1; - } - - if (virJSONValueObjectHasKey(value, "output")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_FILE; - - tmp = virJSONValueObjectGetString(value, "output"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.file.path, tmp) < 0) - return -1; - } else if (virJSONValueObjectHasKey(value, "socket")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_UNIX; - - tmp = virJSONValueObjectGetString(value, "socket"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.nix.path, tmp) < 0) - return -1; - chr->source.data.nix.listen = false; - } else if (virJSONValueObjectHasKey(value, "real")) { - chr->source.type = VIR_DOMAIN_CHR_TYPE_DEV; - - tmp = virJSONValueObjectGetString(value, "real"); - if (!tmp) { - parallelsParseError(); - return -1; - } - - if (VIR_STRDUP(chr->source.data.file.path, tmp) < 0) - return -1; - } else { - parallelsParseError(); - return -1; - } - - return 0; -} - -static int -parallelsAddSerialInfo(virDomainChrDefPtr **serials, size_t *nserials, - const char *key, virJSONValuePtr value) -{ - virDomainChrDefPtr chr = NULL; - - if (!(chr = virDomainChrDefNew())) - goto cleanup; - - if (parallelsGetSerialInfo(chr, key, value)) - goto cleanup; - - if (VIR_APPEND_ELEMENT(*serials, *nserials, chr) < 0) - goto cleanup; - - return 0; - - cleanup: - virDomainChrDefFree(chr); - return -1; -} - -static int -parallelsAddVideoInfo(virDomainDefPtr def, virJSONValuePtr value) -{ - virDomainVideoDefPtr video = NULL; - virDomainVideoAccelDefPtr accel = NULL; - const char *tmp; - char *endptr; - unsigned long mem; - - if (!(tmp = virJSONValueObjectGetString(value, "size"))) { - parallelsParseError(); - goto error; - } - - if (virStrToLong_ul(tmp, &endptr, 10, &mem) < 0) { - parallelsParseError(); - goto error; - } - - if (!STREQ(endptr, "Mb")) { - parallelsParseError(); - goto error; - } - - if (VIR_ALLOC(video) < 0) - goto error; - - if (VIR_ALLOC(accel) < 0) - goto error; - - if (VIR_APPEND_ELEMENT_COPY(def->videos, def->nvideos, video) < 0) - goto error; - - video->type = VIR_DOMAIN_VIDEO_TYPE_VGA; - video->vram = mem << 20; - video->heads = 1; - video->accel = accel; - - return 0; - - error: - VIR_FREE(accel); - virDomainVideoDefFree(video); - return -1; -} - -static int -parallelsGetHddInfo(virDomainDefPtr def, - virDomainDiskDefPtr disk, - const char *key, - virJSONValuePtr value) -{ - const char *tmp; - unsigned int idx; - - disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; - - if (virJSONValueObjectHasKey(value, "real") == 1) { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); - - if (!(tmp = virJSONValueObjectGetString(value, "real"))) { - parallelsParseError(); - return -1; - } - - if (virDomainDiskSetSource(disk, tmp) < 0) - return -1; - } else { - virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); - - if (!(tmp = virJSONValueObjectGetString(value, "image"))) { - parallelsParseError(); - return -1; - } - - if (virDomainDiskSetSource(disk, tmp) < 0) - return -1; - - virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); - } - - tmp = virJSONValueObjectGetString(value, "port"); - if (!tmp && !IS_CT(def)) { - parallelsParseError(); - return -1; - } - - if (tmp) { - if (STRPREFIX(tmp, "ide")) { - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - } else if (STRPREFIX(tmp, "sata")) { - disk->bus = VIR_DOMAIN_DISK_BUS_SATA; - } else if (STRPREFIX(tmp, "scsi")) { - disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; - } else { - parallelsParseError(); - return -1; - } - - char *colonp; - unsigned int pos; - - if (!(colonp = strchr(tmp, ':'))) { - parallelsParseError(); - return -1; - } - - if (virStrToLong_ui(colonp + 1, NULL, 10, &pos) < 0) { - parallelsParseError(); - return -1; - } - - disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; - disk->info.addr.drive.target = pos; - } else { - /* Actually there are no disk devices in containers, but in - * in Parallels Cloud Server we mount disk images as container's - * root fs during start, so it looks like a disk device. */ - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - } - - if (virStrToLong_ui(key + strlen("hdd"), NULL, 10, &idx) < 0) { - parallelsParseError(); - return -1; - } - - if (!(disk->dst = virIndexToDiskName(idx, "sd"))) - return -1; - - return 0; -} - -static int -parallelsAddHddInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) -{ - virDomainDiskDefPtr disk = NULL; - - if (!(disk = virDomainDiskDefNew())) - goto error; - - if (parallelsGetHddInfo(def, disk, key, value)) - goto error; - - if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) - goto error; - - return 0; - - error: - virDomainDiskDefFree(disk); - return -1; -} - -static inline unsigned char hex2int(char c) -{ - if (c <= '9') - return c - '0'; - else - return 10 + c - 'A'; -} - -/* - * Parse MAC address in format XXXXXXXXXXXX. - */ -static int -parallelsMacAddrParse(const char *str, virMacAddrPtr addr) -{ - size_t i; - - if (strlen(str) != 12) - goto error; - - for (i = 0; i < 6; i++) { - if (!c_isxdigit(str[2 * i]) || !c_isxdigit(str[2 * i + 1])) - goto error; - - addr->addr[i] = (hex2int(str[2 * i]) << 4) + hex2int(str[2 * i + 1]); - } - - return 0; - error: - virReportError(VIR_ERR_INVALID_ARG, - _("Invalid MAC address format '%s'"), str); - return -1; -} - -static int -parallelsGetNetInfo(virDomainNetDefPtr net, - const char *key, - virJSONValuePtr value) -{ - const char *tmp; - - /* use device name, shown by prlctl as target device - * for identifying network adapter in virDomainDefineXML */ - if (VIR_STRDUP(net->ifname, key) < 0) - goto error; - - net->type = VIR_DOMAIN_NET_TYPE_NETWORK; - - if (!(tmp = virJSONValueObjectGetString(value, "mac"))) { - parallelsParseError(); - return -1; - } - - if (parallelsMacAddrParse(tmp, &net->mac) < 0) { - parallelsParseError(); - goto error; - } - - - if (virJSONValueObjectHasKey(value, "network")) { - if (!(tmp = virJSONValueObjectGetString(value, "network"))) { - parallelsParseError(); - goto error; - } - - if (VIR_STRDUP(net->data.network.name, tmp) < 0) - goto error; - } else if (virJSONValueObjectHasKey(value, "type")) { - if (!(tmp = virJSONValueObjectGetString(value, "type"))) { - parallelsParseError(); - goto error; - } - - if (!STREQ(tmp, "routed")) { - parallelsParseError(); - goto error; - } - - if (VIR_STRDUP(net->data.network.name, - PARALLELS_ROUTED_NETWORK_NAME) < 0) - goto error; - } else { - parallelsParseError(); - goto error; - } - - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; - if ((tmp = virJSONValueObjectGetString(value, "state")) && - STREQ(tmp, "disconnected")) { - net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; - } - - return 0; - - error: - return -1; -} - -static int -parallelsAddNetInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) -{ - virDomainNetDefPtr net = NULL; - - if (VIR_ALLOC(net) < 0) - goto error; - - if (parallelsGetNetInfo(net, key, value)) - goto error; - - if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) - goto error; - - def->nets[def->nnets - 1] = net; - - return 0; - - error: - virDomainNetDefFree(net); - return -1; -} - -static int -parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) -{ - int n; - size_t i; - virJSONValuePtr value; - const char *key; - - n = virJSONValueObjectKeysNumber(jobj); - if (n < 1) - goto cleanup; - - for (i = 0; i < n; i++) { - key = virJSONValueObjectGetKey(jobj, i); - value = virJSONValueObjectGetValue(jobj, i); - - if (STRPREFIX(key, "serial")) { - if (parallelsAddSerialInfo(&def->serials, - &def->nserials, key, value)) - goto cleanup; - if (def->nconsoles == 0) { - if (parallelsAddSerialInfo(&def->consoles, - &def->nconsoles, key, value)) - goto cleanup; - } - } else if (STREQ(key, "video")) { - if (parallelsAddVideoInfo(def, value)) - goto cleanup; - } else if (STRPREFIX(key, "hdd")) { - if (parallelsAddHddInfo(def, key, value)) - goto cleanup; - } else if (STRPREFIX(key, "net")) { - if (parallelsAddNetInfo(def, key, value)) - goto cleanup; - } - } - - return 0; - - cleanup: - return -1; -} - -static int -parallelsAddVNCInfo(virDomainDefPtr def, virJSONValuePtr jobj_root) -{ - const char *tmp; - unsigned int port; - virJSONValuePtr jobj; - int ret = -1; - virDomainGraphicsDefPtr gr = NULL; - - jobj = virJSONValueObjectGet(jobj_root, "Remote display"); - if (!jobj) { - parallelsParseError(); - goto cleanup; - } - - tmp = virJSONValueObjectGetString(jobj, "mode"); - if (!tmp) { - parallelsParseError(); - goto cleanup; - } - - if (STREQ(tmp, "off")) { - ret = 0; - goto cleanup; - } - - if (VIR_ALLOC(gr) < 0) - goto cleanup; - - if (STREQ(tmp, "auto")) { - if (virJSONValueObjectGetNumberUint(jobj, "port", &port) < 0) - port = 0; - gr->data.vnc.autoport = true; - } else { - if (virJSONValueObjectGetNumberUint(jobj, "port", &port) < 0) { - parallelsParseError(); - goto cleanup; - } - gr->data.vnc.autoport = false; - } - - gr->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; - gr->data.vnc.port = port; - gr->data.vnc.keymap = NULL; - gr->data.vnc.socket = NULL; - gr->data.vnc.auth.passwd = NULL; - gr->data.vnc.auth.expires = false; - gr->data.vnc.auth.connected = 0; - - if (!(tmp = virJSONValueObjectGetString(jobj, "address"))) { - parallelsParseError(); - goto cleanup; - } - - if (VIR_ALLOC(gr->listens) < 0) - goto cleanup; - - gr->nListens = 1; - - if (VIR_STRDUP(gr->listens[0].address, tmp) < 0) - goto cleanup; - - gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; - - if (VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr) < 0) - goto cleanup; - - return 0; - - cleanup: - virDomainGraphicsDefFree(gr); - return ret; -} - -/* - * Must be called with privconn->lock held - */ -static virDomainObjPtr -parallelsLoadDomain(parallelsConnPtr privconn, virJSONValuePtr jobj) -{ - virDomainObjPtr dom = NULL; - virDomainDefPtr def = NULL; - parallelsDomObjPtr pdom = NULL; - virJSONValuePtr jobj2, jobj3; - const char *tmp; - char *endptr; - unsigned long mem; - unsigned int x; - const char *autostart; - const char *state; - int hostcpus; - - if (VIR_ALLOC(def) < 0) - goto cleanup; - - if (VIR_ALLOC(pdom) < 0) - goto cleanup; - - def->virtType = VIR_DOMAIN_VIRT_PARALLELS; - def->id = -1; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Name"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(def->name, tmp) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj, "ID"))) { - parallelsParseError(); - goto cleanup; - } - - if (virUUIDParse(tmp, def->uuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("UUID in config file malformed")); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj, "Description"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(def->description, tmp) < 0) - goto cleanup; - - if (!(jobj2 = virJSONValueObjectGet(jobj, "Hardware"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(jobj3 = virJSONValueObjectGet(jobj2, "cpu"))) { - parallelsParseError(); - goto cleanup; - } - - if (virJSONValueObjectGetNumberUint(jobj3, "cpus", &x) == 0) { - def->vcpus = x; - def->maxvcpus = x; - } else if ((tmp = virJSONValueObjectGetString(jobj3, "cpus"))) { - if (STREQ(tmp, "unlimited")) { - virNodeInfo nodeinfo; - - if (nodeGetInfo(&nodeinfo) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Can't get node info")); - goto cleanup; - } - - def->vcpus = nodeinfo.cpus; - def->maxvcpus = def->vcpus; - } else { - parallelsParseError(); - goto cleanup; - } - } else { - parallelsParseError(); - goto cleanup; - } - - if ((hostcpus = nodeGetCPUCount()) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj3, "mask"))) { - /* Absence of this field means that all domains cpus are available */ - if (!(pdom->cpumask = virBitmapNew(hostcpus))) - goto cleanup; - virBitmapSetAll(pdom->cpumask); - } else { - if (virBitmapParse(tmp, 0, &pdom->cpumask, hostcpus) < 0) - goto cleanup; - } - - if (!(jobj3 = virJSONValueObjectGet(jobj2, "memory"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(tmp = virJSONValueObjectGetString(jobj3, "size"))) { - parallelsParseError(); - goto cleanup; - } - - if (virStrToLong_ul(tmp, &endptr, 10, &mem) < 0) { - parallelsParseError(); - goto cleanup; - } - - if (!STREQ(endptr, "Mb")) { - parallelsParseError(); - goto cleanup; - } - - def->mem.max_balloon = mem; - def->mem.max_balloon <<= 10; - def->mem.cur_balloon = def->mem.max_balloon; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { - parallelsParseError(); - goto cleanup; - } - - if (STREQ(tmp, "CT")) { - if (VIR_STRDUP(def->os.type, "exe") < 0) - goto cleanup; - if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) - goto cleanup; - } else if (STREQ(tmp, "VM")) { - if (VIR_STRDUP(def->os.type, "hvm") < 0) - goto cleanup; - } - - def->os.arch = VIR_ARCH_X86_64; - - if (virJSONValueObjectGetNumberUint(jobj, "EnvID", &x) < 0) - goto cleanup; - pdom->id = x; - if (!(tmp = virJSONValueObjectGetString(jobj, "ID"))) { - parallelsParseError(); - goto cleanup; - } - if (VIR_STRDUP(pdom->uuid, tmp) < 0) - goto cleanup; - - if (!(tmp = virJSONValueObjectGetString(jobj, "Home"))) { - parallelsParseError(); - goto cleanup; - } - - if (VIR_STRDUP(pdom->home, tmp) < 0) - goto cleanup; - - if (!(state = virJSONValueObjectGetString(jobj, "State"))) { - parallelsParseError(); - goto cleanup; - } - - if (!(autostart = virJSONValueObjectGetString(jobj, "Autostart"))) { - parallelsParseError(); - goto cleanup; - } - - if (parallelsAddDomainHardware(def, jobj2) < 0) - goto cleanup; - - if (parallelsAddVNCInfo(def, jobj) < 0) - goto cleanup; - - if (!(dom = virDomainObjListAdd(privconn->domains, def, - privconn->xmlopt, - 0, NULL))) - goto cleanup; - /* dom is locked here */ - - dom->privateDataFreeFunc = parallelsDomObjFreePrivate; - dom->privateData = pdom; - dom->persistent = 1; - - /* TODO: handle all possible states */ - if (STREQ(state, "running")) { - virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_BOOTED); - def->id = pdom->id; - } - - if (STREQ(autostart, "on")) - dom->autostart = 1; - else - dom->autostart = 0; - - virObjectUnlock(dom); - - return dom; - - cleanup: - virDomainDefFree(def); - parallelsDomObjFreePrivate(pdom); - return NULL; -} - -/* - * Must be called with privconn->lock held - * - * if domain_name is NULL - load information about all - * registered domains. - */ -static int -parallelsLoadDomains(parallelsConnPtr privconn, const char *domain_name) -{ - int count; - size_t i; - virJSONValuePtr jobj; - virJSONValuePtr jobj2; - virDomainObjPtr dom = NULL; - int ret = -1; - - jobj = parallelsParseOutput(PRLCTL, "list", "-j", "-a", "-i", "-H", - "--vmtype", "all", domain_name, NULL); - if (!jobj) { - parallelsParseError(); - goto cleanup; - } - - count = virJSONValueArraySize(jobj); - if (count < 0) { - parallelsParseError(); - goto cleanup; - } - - for (i = 0; i < count; i++) { - jobj2 = virJSONValueArrayGet(jobj, i); - if (!jobj2) { - parallelsParseError(); - goto cleanup; - } - - dom = parallelsLoadDomain(privconn, jobj2); - if (!dom) - goto cleanup; - } - - ret = 0; - - cleanup: - virJSONValueFree(jobj); - return ret; -} - - -static int parallelsDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED, virCapsPtr caps ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) @@ -972,7 +233,7 @@ parallelsOpenDefault(virConnectPtr conn) conn->privateData = privconn; - if (parallelsLoadDomains(privconn, NULL)) + if (prlsdkLoadDomains(privconn)) goto error; return VIR_DRV_OPEN_SUCCESS; @@ -2292,6 +1553,7 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) virDomainPtr ret = NULL; virDomainDefPtr def; virDomainObjPtr olddom = NULL; + virDomainObjPtr dom = NULL; parallelsDriverLock(privconn); if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt, @@ -2316,7 +1578,10 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml) _("Unsupported OS type: %s"), def->os.type); goto cleanup; } - if (parallelsLoadDomains(privconn, def->name)) + dom = prlsdkAddDomain(privconn, def->uuid); + if (dom) + virObjectUnlock(dom); + else goto cleanup; olddom = virDomainObjListFindByName(privconn->domains, def->name); if (!olddom) { diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c index 1c77d27..a05cdb3 100644 --- a/src/parallels/parallels_sdk.c +++ b/src/parallels/parallels_sdk.c @@ -24,6 +24,9 @@ #include "virerror.h" #include "viralloc.h" +#include "virstring.h" +#include "nodeinfo.h" +#include "virlog.h" #include "parallels_sdk.h" @@ -32,6 +35,8 @@ PRL_UINT32 defaultJobTimeout = JOB_INFINIT_WAIT_TIMEOUT; +VIR_LOG_INIT("parallels.sdk"); + /* * Log error description */ @@ -72,6 +77,14 @@ logPrlErrorHelper(PRL_RESULT err, const char *filename, logPrlErrorHelper(code, __FILE__, \ __FUNCTION__, __LINE__) +# define prlsdkCheckRetGoto(ret, label) \ + do { \ + if (PRL_FAILED(ret)) { \ + logPrlError(ret); \ + goto label; \ + } \ + } while (0) + static PRL_RESULT logPrlEventErrorHelper(PRL_HANDLE event, const char *filename, const char *funcname, size_t linenr) @@ -239,3 +252,992 @@ prlsdkDisconnect(parallelsConnPtr privconn) PrlHandle_Free(privconn->server); } + +int +prlsdkSdkDomainLookup(parallelsConnPtr privconn, + const char *id, + unsigned int flags, + PRL_HANDLE *sdkdom) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_RESULT pret = PRL_ERR_UNINITIALIZED; + int ret = -1; + + job = PrlSrv_GetVmConfig(privconn->server, id, flags); + if (!(result = getJobResult(job, privconn->jobTimeout))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, sdkdom); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(result); + return ret; +} + +PRL_HANDLE +prlsdkSdkDomainLookupByUUID(parallelsConnPtr privconn, const unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + + virUUIDFormat(uuid, uuidstr + 1); + + uuidstr[0] = '{'; + uuidstr[VIR_UUID_STRING_BUFLEN] = '}'; + uuidstr[VIR_UUID_STRING_BUFLEN + 1] = '\0'; + + if (prlsdkSdkDomainLookup(privconn, uuidstr, + PGVC_SEARCH_BY_UUID, &sdkdom) < 0) { + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + return PRL_INVALID_HANDLE; + } + + return sdkdom; +} + +static int +prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid) +{ + char *tmp = NULL; + int ret = -1; + + virCheckNonNullArgGoto(uuidstr, error); + virCheckNonNullArgGoto(uuid, error); + + if (VIR_STRDUP(tmp, uuidstr) < 0) + goto error; + + tmp[strlen(tmp) - 1] = '\0'; + + /* trim curly braces */ + if (virUUIDParse(tmp + 1, uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("UUID in config file malformed")); + ret = -1; + goto error; + } + + ret = 0; + error: + VIR_FREE(tmp); + return ret; +} + +static int +prlsdkGetDomainIds(PRL_HANDLE sdkdom, + char **name, + unsigned char *uuid) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 len; + PRL_RESULT pret; + + len = 0; + /* get name length */ + pret = PrlVmCfg_GetName(sdkdom, NULL, &len); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(*name, len) < 0) + goto error; + + PrlVmCfg_GetName(sdkdom, *name, &len); + prlsdkCheckRetGoto(pret, error); + + len = sizeof(uuidstr); + PrlVmCfg_GetUuid(sdkdom, uuidstr, &len); + prlsdkCheckRetGoto(pret, error); + + if (prlsdkUUIDParse(uuidstr, uuid) < 0) + goto error; + + return 0; + + error: + VIR_FREE(*name); + return -1; +} + +static int +prlsdkGetDomainState(parallelsConnPtr privconn, + PRL_HANDLE sdkdom, + VIRTUAL_MACHINE_STATE_PTR vmState) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_HANDLE vmInfo = PRL_INVALID_HANDLE; + PRL_RESULT pret; + int ret = -1; + + job = PrlVm_GetState(sdkdom); + + if (!(result = getJobResult(job, privconn->jobTimeout))) + goto cleanup; + + pret = PrlResult_GetParamByIndex(result, 0, &vmInfo); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmInfo_GetState(vmInfo, vmState); + prlsdkCheckRetGoto(pret, cleanup); + + ret = 0; + + cleanup: + PrlHandle_Free(vmInfo); + PrlHandle_Free(result); + return ret; +} + +static void +prlsdkDomObjFreePrivate(void *p) +{ + parallelsDomObjPtr pdom = p; + + if (!pdom) + return; + + PrlHandle_Free(pdom->sdkdom); + virBitmapFree(pdom->cpumask); + VIR_FREE(pdom->uuid); + VIR_FREE(pdom->home); + VIR_FREE(p); +}; + +static int +prlsdkAddDomainVideoInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainVideoDefPtr video = NULL; + virDomainVideoAccelDefPtr accel = NULL; + PRL_RESULT ret; + PRL_UINT32 videoRam; + + /* video info */ + ret = PrlVmCfg_GetVideoRamSize(sdkdom, &videoRam); + prlsdkCheckRetGoto(ret, error); + + if (VIR_ALLOC(video) < 0) + goto error; + + if (VIR_ALLOC(accel) < 0) + goto error; + + if (VIR_APPEND_ELEMENT_COPY(def->videos, def->nvideos, video) < 0) + goto error; + + video->type = VIR_DOMAIN_VIDEO_TYPE_VGA; + video->vram = videoRam << 10; /* from mbibytes to kbibytes */ + video->heads = 1; + video->accel = accel; + + return 0; + + error: + VIR_FREE(accel); + virDomainVideoDefFree(video); + return -1; +} + +static int +prlsdkGetDiskInfo(PRL_HANDLE prldisk, + virDomainDiskDefPtr disk) +{ + char *buf = NULL; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 emulatedType; + PRL_UINT32 ifType; + PRL_UINT32 pos; + PRL_UINT32 prldiskIndex; + int ret = -1; + + pret = PrlVmDev_GetEmulatedType(prldisk, &emulatedType); + prlsdkCheckRetGoto(pret, cleanup); + if (emulatedType == PDT_USE_IMAGE_FILE) { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); + virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_PLOOP); + } else { + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); + } + + pret = PrlVmDev_GetFriendlyName(prldisk, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmDev_GetFriendlyName(prldisk, buf, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (virDomainDiskSetSource(disk, buf) < 0) + goto cleanup; + + pret = PrlVmDev_GetIfaceType(prldisk, &ifType); + prlsdkCheckRetGoto(pret, cleanup); + switch (ifType) { + case PMS_IDE_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + break; + case PMS_SCSI_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; + break; + case PMS_SATA_DEVICE: + disk->bus = VIR_DOMAIN_DISK_BUS_SATA; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown disk bus: %X"), ifType); + goto cleanup; + break; + } + + pret = PrlVmDev_GetStackIndex(prldisk, &pos); + prlsdkCheckRetGoto(pret, cleanup); + + disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + disk->info.addr.drive.target = pos; + + pret = PrlVmDev_GetIndex(prldisk, &prldiskIndex); + prlsdkCheckRetGoto(pret, cleanup); + + if (!(disk->dst = virIndexToDiskName(prldiskIndex, "sd"))) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(buf); + return ret; +} + +static int +prlsdkAddDomainHardDisksInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_RESULT pret; + PRL_UINT32 hddCount; + PRL_UINT32 i; + PRL_HANDLE hdd = PRL_INVALID_HANDLE; + virDomainDiskDefPtr disk = NULL; + + pret = PrlVmCfg_GetHardDisksCount(sdkdom, &hddCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < hddCount; ++i) { + pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd); + prlsdkCheckRetGoto(pret, error); + + if (IS_CT(def)) { + /* TODO: convert info about disks in container + * to virDomainFSDef structs */ + VIR_WARN("Skipping disk information for container"); + + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + } else { + if (!(disk = virDomainDiskDefNew())) + goto error; + + if (prlsdkGetDiskInfo(hdd, disk) < 0) + goto error; + + PrlHandle_Free(hdd); + hdd = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + goto error; + } + } + + return 0; + + error: + PrlHandle_Free(hdd); + virDomainDiskDefFree(disk); + return -1; +} + +static int +prlsdkGetNetInfo(PRL_HANDLE netAdapter, virDomainNetDefPtr net, bool isCt) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + PRL_UINT32 buflen; + PRL_UINT32 netAdapterIndex; + PRL_UINT32 emulatedType; + PRL_RESULT pret; + PRL_BOOL isConnected; + int ret = -1; + + net->type = VIR_DOMAIN_NET_TYPE_NETWORK; + + + /* use device name, shown by prlctl as target device + * for identifying network adapter in virDomainDefineXML */ + pret = PrlVmDev_GetIndex(netAdapter, &netAdapterIndex); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(net->ifname, buflen) < 0) + goto cleanup; + + pret = PrlVmDevNet_GetHostInterfaceName(netAdapter, net->ifname, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (isCt && netAdapterIndex == (PRL_UINT32) -1) { + /* venet devices don't have mac address and + * always up */ + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (VIR_STRDUP(net->data.network.name, + PARALLELS_ROUTED_NETWORK_NAME) < 0) + goto cleanup; + return 0; + } + + buflen = ARRAY_CARDINALITY(macstr); + if (VIR_ALLOC_N(macstr, buflen)) + goto cleanup; + pret = PrlVmDevNet_GetMacAddressCanonical(netAdapter, macstr, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (virMacAddrParse(macstr, &net->mac) < 0) + goto cleanup; + + pret = PrlVmDev_GetEmulatedType(netAdapter, &emulatedType); + prlsdkCheckRetGoto(pret, cleanup); + + if (emulatedType == PNA_ROUTED) { + if (VIR_STRDUP(net->data.network.name, + PARALLELS_ROUTED_NETWORK_NAME) < 0) + goto cleanup; + } else { + pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(net->data.network.name, buflen) < 0) + goto cleanup; + + pret = PrlVmDevNet_GetVirtualNetworkId(netAdapter, + net->data.network.name, + &buflen); + prlsdkCheckRetGoto(pret, cleanup); + } + + pret = PrlVmDev_IsConnected(netAdapter, &isConnected); + prlsdkCheckRetGoto(pret, cleanup); + + if (isConnected) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + + ret = 0; + cleanup: + return ret; +} + +static int +prlsdkAddDomainNetInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainNetDefPtr net = NULL; + PRL_RESULT ret; + PRL_HANDLE netAdapter; + PRL_UINT32 netAdaptersCount; + PRL_UINT32 i; + + ret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &netAdaptersCount); + prlsdkCheckRetGoto(ret, error); + for (i = 0; i < netAdaptersCount; ++i) { + ret = PrlVmCfg_GetNetAdapter(sdkdom, i, &netAdapter); + prlsdkCheckRetGoto(ret, error); + + if (VIR_ALLOC(net) < 0) + goto error; + + if (prlsdkGetNetInfo(netAdapter, net, IS_CT(def)) < 0) + goto error; + + PrlHandle_Free(netAdapter); + netAdapter = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0) + goto error; + } + + return 0; + + error: + PrlHandle_Free(netAdapter); + virDomainNetDefFree(net); + return -1; +} + +static int +prlsdkGetSerialInfo(PRL_HANDLE serialPort, virDomainChrDefPtr chr) +{ + PRL_RESULT pret; + PRL_UINT32 serialPortIndex; + PRL_UINT32 emulatedType; + char *friendlyName = NULL; + PRL_UINT32 buflen; + + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->targetTypeAttr = false; + pret = PrlVmDev_GetIndex(serialPort, &serialPortIndex); + prlsdkCheckRetGoto(pret, error); + chr->target.port = serialPortIndex; + + pret = PrlVmDev_GetEmulatedType(serialPort, &emulatedType); + prlsdkCheckRetGoto(pret, error); + + pret = PrlVmDev_GetFriendlyName(serialPort, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(friendlyName, buflen) < 0) + goto error; + + pret = PrlVmDev_GetFriendlyName(serialPort, friendlyName, &buflen); + prlsdkCheckRetGoto(pret, error); + + switch (emulatedType) { + case PDT_USE_OUTPUT_FILE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_FILE; + chr->source.data.file.path = friendlyName; + break; + case PDT_USE_SERIAL_PORT_SOCKET_MODE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_UNIX; + chr->source.data.nix.path = friendlyName; + break; + case PDT_USE_REAL_DEVICE: + chr->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + chr->source.data.file.path = friendlyName; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown serial type: %X"), emulatedType); + goto error; + break; + } + + return 0; + error: + VIR_FREE(friendlyName); + return -1; +} + + +static int +prlsdkAddSerialInfo(PRL_HANDLE sdkdom, + virDomainChrDefPtr **serials, + size_t *nserials) +{ + PRL_RESULT ret; + PRL_HANDLE serialPort; + PRL_UINT32 serialPortsCount; + PRL_UINT32 i; + virDomainChrDefPtr chr = NULL; + + ret = PrlVmCfg_GetSerialPortsCount(sdkdom, &serialPortsCount); + prlsdkCheckRetGoto(ret, cleanup); + for (i = 0; i < serialPortsCount; ++i) { + ret = PrlVmCfg_GetSerialPort(sdkdom, i, &serialPort); + prlsdkCheckRetGoto(ret, cleanup); + + if (!(chr = virDomainChrDefNew())) + goto cleanup; + + if (prlsdkGetSerialInfo(serialPort, chr)) + goto cleanup; + + PrlHandle_Free(serialPort); + serialPort = PRL_INVALID_HANDLE; + + if (VIR_APPEND_ELEMENT(*serials, *nserials, chr) < 0) + goto cleanup; + } + + return 0; + + cleanup: + PrlHandle_Free(serialPort); + virDomainChrDefFree(chr); + return -1; +} + + +static int +prlsdkAddDomainHardware(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + if (!IS_CT(def)) + if (prlsdkAddDomainVideoInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainHardDisksInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainNetInfo(sdkdom, def) < 0) + goto error; + + if (prlsdkAddSerialInfo(sdkdom, + &def->serials, + &def->nserials) < 0) + goto error; + + return 0; + error: + return -1; +} + + +static int +prlsdkAddVNCInfo(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + virDomainGraphicsDefPtr gr = NULL; + PRL_VM_REMOTE_DISPLAY_MODE vncMode; + PRL_UINT32 port; + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + + pret = PrlVmCfg_GetVNCMode(sdkdom, &vncMode); + prlsdkCheckRetGoto(pret, error); + + if (vncMode == PRD_DISABLED) + return 0; + + if (VIR_ALLOC(gr) < 0) + goto error; + + pret = PrlVmCfg_GetVNCPort(sdkdom, &port); + prlsdkCheckRetGoto(pret, error); + + gr->data.vnc.autoport = (vncMode == PRD_AUTO); + gr->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; + gr->data.vnc.port = port; + gr->data.vnc.keymap = NULL; + gr->data.vnc.socket = NULL; + gr->data.vnc.auth.passwd = NULL; + gr->data.vnc.auth.expires = false; + gr->data.vnc.auth.connected = 0; + + if (VIR_ALLOC(gr->listens) < 0) + goto error; + + gr->nListens = 1; + + pret = PrlVmCfg_GetVNCHostName(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + if (VIR_ALLOC_N(gr->listens[0].address, buflen) < 0) + goto error; + + pret = PrlVmCfg_GetVNCHostName(sdkdom, gr->listens[0].address, &buflen); + prlsdkCheckRetGoto(pret, error); + + gr->listens[0].type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS; + + if (VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, gr) < 0) + goto error; + + return 0; + + error: + virDomainGraphicsDefFree(gr); + return -1; +} + +static int +prlsdkConvertDomainState(VIRTUAL_MACHINE_STATE domainState, + PRL_UINT32 envId, + virDomainObjPtr dom) +{ + switch (domainState) { + case VMS_STOPPED: + case VMS_MOUNTED: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, + VIR_DOMAIN_SHUTOFF_SHUTDOWN); + dom->def->id = -1; + break; + case VMS_STARTING: + case VMS_COMPACTING: + case VMS_RESETTING: + case VMS_PAUSING: + case VMS_RECONNECTING: + case VMS_RUNNING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_BOOTED); + dom->def->id = envId; + break; + case VMS_PAUSED: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_USER); + dom->def->id = envId; + break; + case VMS_SUSPENDED: + case VMS_DELETING_STATE: + case VMS_SUSPENDING_SYNC: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, + VIR_DOMAIN_SHUTOFF_SAVED); + dom->def->id = -1; + break; + case VMS_STOPPING: + virDomainObjSetState(dom, VIR_DOMAIN_SHUTDOWN, + VIR_DOMAIN_SHUTDOWN_USER); + dom->def->id = envId; + break; + case VMS_SNAPSHOTING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_SNAPSHOT); + dom->def->id = envId; + break; + case VMS_MIGRATING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + dom->def->id = envId; + break; + case VMS_SUSPENDING: + virDomainObjSetState(dom, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_SAVE); + dom->def->id = envId; + break; + case VMS_RESTORING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_RESTORED); + dom->def->id = envId; + break; + case VMS_CONTINUING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_UNPAUSED); + dom->def->id = envId; + break; + case VMS_RESUMING: + virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_RESTORED); + dom->def->id = envId; + break; + case VMS_UNKNOWN: + virDomainObjSetState(dom, VIR_DOMAIN_NOSTATE, + VIR_DOMAIN_NOSTATE_UNKNOWN); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown domain state: %X"), domainState); + return -1; + break; + } + + return 0; +} + +static int +prlsdkConvertCpuInfo(PRL_HANDLE sdkdom, + virDomainDefPtr def, + parallelsDomObjPtr pdom) +{ + char *buf; + PRL_UINT32 buflen = 0; + int hostcpus; + PRL_UINT32 cpuCount; + PRL_RESULT pret; + int ret = -1; + + if ((hostcpus = nodeGetCPUCount()) < 0) + goto cleanup; + + /* get number of CPUs */ + pret = PrlVmCfg_GetCpuCount(sdkdom, &cpuCount); + prlsdkCheckRetGoto(pret, cleanup); + + if (cpuCount > hostcpus) + cpuCount = hostcpus; + + def->vcpus = cpuCount; + def->maxvcpus = cpuCount; + + pret = PrlVmCfg_GetCpuMask(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (VIR_ALLOC_N(buf, buflen) < 0) + goto cleanup; + + pret = PrlVmCfg_GetCpuMask(sdkdom, buf, &buflen); + + if (strlen(buf) == 0) { + if (!(pdom->cpumask = virBitmapNew(hostcpus))) + goto cleanup; + virBitmapSetAll(pdom->cpumask); + } else { + if (virBitmapParse(buf, 0, &pdom->cpumask, hostcpus) < 0) + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(buf); + return ret; +} + +static int +prlsdkConvertDomainType(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_VM_TYPE domainType; + PRL_RESULT pret; + + pret = PrlVmCfg_GetVmType(sdkdom, &domainType); + prlsdkCheckRetGoto(pret, error); + + switch (domainType) { + case PVT_VM: + if (VIR_STRDUP(def->os.type, "hvm") < 0) + return -1; + break; + case PVT_CT: + if (VIR_STRDUP(def->os.type, "exe") < 0) + return -1; + if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) + return -1; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown domain type: %X"), domainType); + return -1; + } + + return 0; + + error: + return -1; +} + +static int +prlsdkConvertCpuMode(PRL_HANDLE sdkdom, virDomainDefPtr def) +{ + PRL_RESULT pret; + PRL_CPU_MODE cpuMode; + + pret = PrlVmCfg_GetCpuMode(sdkdom, &cpuMode); + prlsdkCheckRetGoto(pret, error); + + switch (cpuMode) { + case PCM_CPU_MODE_32: + def->os.arch = VIR_ARCH_I686; + break; + case PCM_CPU_MODE_64: + def->os.arch = VIR_ARCH_X86_64; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU mode: %X"), cpuMode); + return -1; + } + + return 0; + error: + return -1; +} + +/* + * This function retrieves information about domain. + * If the domains is already in the domains list + * privconn->domains, then locked 'olddom' must be + * provided. If the domains must be added to the list, + * olddom must be NULL. + * + * The function return a pointer to a locked virDomainObj. + */ +static virDomainObjPtr +prlsdkLoadDomain(parallelsConnPtr privconn, + PRL_HANDLE sdkdom, + virDomainObjPtr olddom) +{ + virDomainObjPtr dom = NULL; + virDomainDefPtr def = NULL; + parallelsDomObjPtr pdom = NULL; + VIRTUAL_MACHINE_STATE domainState; + + PRL_UINT32 buflen = 0; + PRL_RESULT pret; + PRL_UINT32 ram; + PRL_UINT32 envId; + PRL_VM_AUTOSTART_OPTION autostart; + + virCheckNonNullArgGoto(privconn, error); + virCheckNonNullArgGoto(sdkdom, error); + + if (VIR_ALLOC(def) < 0) + goto error; + + if (!olddom) { + if (VIR_ALLOC(pdom) < 0) + goto error; + } else { + pdom = olddom->privateData; + } + + def->virtType = VIR_DOMAIN_VIRT_PARALLELS; + def->id = -1; + + /* we will remove this field in the near future, so let's set it + * to NULL temporarily */ + pdom->uuid = NULL; + + if (prlsdkGetDomainIds(sdkdom, &def->name, def->uuid) < 0) + goto error; + + /* get RAM parameters */ + pret = PrlVmCfg_GetRamSize(sdkdom, &ram); + prlsdkCheckRetGoto(pret, error); + def->mem.max_balloon = ram << 10; /* RAM size obtained in Mbytes, + convert to Kbytes */ + def->mem.cur_balloon = def->mem.max_balloon; + + if (prlsdkConvertCpuInfo(sdkdom, def, pdom) < 0) + goto error; + + if (prlsdkConvertCpuMode(sdkdom, def) < 0) + goto error; + + if (prlsdkConvertDomainType(sdkdom, def) < 0) + goto error; + + if (prlsdkAddDomainHardware(sdkdom, def) < 0) + goto error; + + if (prlsdkAddVNCInfo(sdkdom, def) < 0) + goto error; + + pret = PrlVmCfg_GetEnvId(sdkdom, &envId); + prlsdkCheckRetGoto(pret, error); + pdom->id = envId; + + buflen = 0; + pret = PrlVmCfg_GetHomePath(sdkdom, NULL, &buflen); + prlsdkCheckRetGoto(pret, error); + + VIR_FREE(pdom->home); + if (VIR_ALLOC_N(pdom->home, buflen) < 0) + goto error; + + pret = PrlVmCfg_GetHomePath(sdkdom, pdom->home, &buflen); + prlsdkCheckRetGoto(pret, error); + + if (olddom) { + /* assign new virDomainDef without any checks */ + /* we can't use virDomainObjAssignDef, because it checks + * for state and domain name */ + dom = olddom; + virDomainDefFree(dom->def); + virDomainDefFree(dom->newDef); + dom->def = def; + dom->newDef = def; + } else { + if (!(dom = virDomainObjListAdd(privconn->domains, def, + privconn->xmlopt, + 0, NULL))) + goto error; + } + /* dom is locked here */ + + dom->privateData = pdom; + dom->privateDataFreeFunc = prlsdkDomObjFreePrivate; + dom->persistent = 1; + + if (prlsdkGetDomainState(privconn, sdkdom, &domainState) < 0) + goto error; + + if (prlsdkConvertDomainState(domainState, envId, dom) < 0) + goto error; + + pret = PrlVmCfg_GetAutoStart(sdkdom, &autostart); + prlsdkCheckRetGoto(pret, error); + + switch (autostart) { + case PAO_VM_START_ON_LOAD: + dom->autostart = 1; + break; + case PAO_VM_START_MANUAL: + dom->autostart = 0; + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown autostart mode: %X"), autostart); + goto error; + } + + if (!pdom->sdkdom) { + pret = PrlHandle_AddRef(sdkdom); + prlsdkCheckRetGoto(pret, error); + pdom->sdkdom = sdkdom; + } + + return dom; + error: + if (dom && !olddom) + virDomainObjListRemove(privconn->domains, dom); + virDomainDefFree(def); + prlsdkDomObjFreePrivate(pdom); + return NULL; +} + +int +prlsdkLoadDomains(parallelsConnPtr privconn) +{ + PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result; + PRL_HANDLE sdkdom; + PRL_UINT32 paramsCount; + PRL_RESULT pret; + size_t i = 0; + virDomainObjPtr dom; + + job = PrlSrv_GetVmListEx(privconn->server, PVTF_VM | PVTF_CT); + + if (!(result = getJobResult(job, privconn->jobTimeout))) + return -1; + + pret = PrlResult_GetParamsCount(result, ¶msCount); + prlsdkCheckRetGoto(pret, error); + + for (i = 0; i < paramsCount; i++) { + pret = PrlResult_GetParamByIndex(result, i, &sdkdom); + if (PRL_FAILED(pret)) { + logPrlError(pret); + PrlHandle_Free(sdkdom); + goto error; + } + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + + if (!dom) + goto error; + else + virObjectUnlock(dom); + } + + PrlHandle_Free(result); + return 0; + + error: + PrlHandle_Free(result); + PrlHandle_Free(job); + return -1; +} + +virDomainObjPtr +prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid) +{ + PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; + virDomainObjPtr dom; + + sdkdom = prlsdkSdkDomainLookupByUUID(privconn, uuid); + if (sdkdom == PRL_INVALID_HANDLE) + return NULL; + + dom = prlsdkLoadDomain(privconn, sdkdom, NULL); + PrlHandle_Free(sdkdom); + return dom; +} diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h index cefe67d..d9461ca 100644 --- a/src/parallels/parallels_sdk.h +++ b/src/parallels/parallels_sdk.h @@ -28,3 +28,7 @@ int prlsdkInit(parallelsConnPtr privconn); void prlsdkDeinit(void); int prlsdkConnect(parallelsConnPtr privconn); void prlsdkDisconnect(parallelsConnPtr privconn); +int +prlsdkLoadDomains(parallelsConnPtr privconn); +virDomainObjPtr +prlsdkAddDomain(parallelsConnPtr privconn, const unsigned char *uuid); diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 269020a..95206d6 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -61,6 +61,7 @@ struct parallelsDomObj { char *uuid; char *home; virBitmapPtr cpumask; + PRL_HANDLE sdkdom; }; typedef struct parallelsDomObj *parallelsDomObjPtr; -- 1.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list