18.11.2014 16:16, Dmitry Guryanov пишет:
From: Alexander Burluka <aburluka(a)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(a)parallels.com>
---
src/parallels/parallels_driver.c | 747 +---------------------------
src/parallels/parallels_sdk.c | 1008 ++++++++++++++++++++++++++++++++++++++
src/parallels/parallels_sdk.h | 4 +
src/parallels/parallels_utils.h | 1 +
4 files changed, 1019 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..c6cf78a 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,998 @@ 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;
+
+ 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;
ack