parallels: get domain info with SDK

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>
This commit is contained in:
Alexander Burluka 2014-12-01 18:38:48 +03:00 committed by Peter Krempa
parent d211ba7c49
commit 7039bb3cd1
4 changed files with 1029 additions and 741 deletions

View File

@ -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)
{
@ -190,729 +174,6 @@ parallelsConnectGetCapabilities(virConnectPtr conn)
return xml;
}
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,
@ -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) {

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -62,6 +62,7 @@ struct parallelsDomObj {
char *uuid;
char *home;
virBitmapPtr cpumask;
PRL_HANDLE sdkdom;
};
typedef struct parallelsDomObj *parallelsDomObjPtr;