[libvirt] [PATCH v2 06/12] parallels: rewrite parallelsApplyConfig with SDK

Dmitry Guryanov dguryanov at parallels.com
Tue Oct 28 12:54:15 UTC 2014


Rewrite code, which applies domain configuration given
to virDomainDefineXML function to the VM of container
registered in PCS.

This code first check if there are unsupported parameters
in domain XML and if yes - reports error. Some of such
parameters are not supported by PCS, for some - it's not
obvious, how to convert them into PCS's corresponding params,
so let's put off it, and implement only basic params in
this patch.

Signed-off-by: Dmitry Guryanov <dguryanov at parallels.com>
---
 src/parallels/parallels_driver.c | 737 +------------------------------
 src/parallels/parallels_sdk.c    | 928 +++++++++++++++++++++++++++++++++++++++
 src/parallels/parallels_sdk.h    |   4 +
 3 files changed, 933 insertions(+), 736 deletions(-)

diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c
index 658969f..55ee003 100644
--- a/src/parallels/parallels_driver.c
+++ b/src/parallels/parallels_driver.c
@@ -65,19 +65,6 @@ VIR_LOG_INIT("parallels.parallels_driver");
 
 static int parallelsConnectClose(virConnectPtr conn);
 
-static const char * parallelsGetDiskBusName(int bus) {
-    switch (bus) {
-    case VIR_DOMAIN_DISK_BUS_IDE:
-        return "ide";
-    case VIR_DOMAIN_DISK_BUS_SATA:
-        return "sata";
-    case VIR_DOMAIN_DISK_BUS_SCSI:
-        return "scsi";
-    default:
-        return NULL;
-    }
-}
-
 void
 parallelsDriverLock(parallelsConnPtr driver)
 {
@@ -671,728 +658,6 @@ parallelsDomainGetAutostart(virDomainPtr domain, int *autostart)
 }
 
 static int
-parallelsApplyGraphicsParams(virDomainGraphicsDefPtr *oldgraphics, int nold,
-                             virDomainGraphicsDefPtr *newgraphics, int nnew)
-{
-    virDomainGraphicsDefPtr new, old;
-
-    /* parallels server supports only 1 VNC display per VM */
-    if (nold != nnew || nnew > 1)
-        goto error;
-
-    if (nnew == 0)
-        return 0;
-
-    if (newgraphics[0]->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC)
-        goto error;
-
-    old = oldgraphics[0];
-    new = newgraphics[0];
-
-    if (old->data.vnc.port != new->data.vnc.port &&
-        (old->data.vnc.port != 0 && new->data.vnc.port != 0)) {
-
-        goto error;
-    } else if (old->data.vnc.autoport != new->data.vnc.autoport ||
-        new->data.vnc.keymap != NULL ||
-        new->data.vnc.socket != NULL ||
-        !STREQ_NULLABLE(old->data.vnc.auth.passwd, new->data.vnc.auth.passwd) ||
-        old->data.vnc.auth.expires != new->data.vnc.auth.expires ||
-        old->data.vnc.auth.validTo != new->data.vnc.auth.validTo ||
-        old->data.vnc.auth.connected != new->data.vnc.auth.connected) {
-
-        goto error;
-    } else if (old->nListens != new->nListens ||
-               new->nListens > 1 ||
-               old->listens[0].type != new->listens[0].type ||
-                 !STREQ_NULLABLE(old->listens[0].address, new->listens[0].address) ||
-                 !STREQ_NULLABLE(old->listens[0].network, new->listens[0].network)) {
-
-        goto error;
-    }
-
-    return 0;
- error:
-    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                   _("changing display parameters is not supported "
-                     "by parallels driver"));
-    return -1;
-}
-
-static int
-parallelsApplySerialParams(virDomainChrDefPtr *oldserials, int nold,
-                           virDomainChrDefPtr *newserials, int nnew)
-{
-    size_t i, j;
-
-    if (nold != nnew)
-        goto error;
-
-    for (i = 0; i < nold; i++) {
-        virDomainChrDefPtr oldserial = oldserials[i];
-        virDomainChrDefPtr newserial = NULL;
-
-        for (j = 0; j < nnew; j++) {
-            if (newserials[j]->target.port == oldserial->target.port) {
-                newserial = newserials[j];
-                break;
-            }
-        }
-
-        if (!newserial)
-            goto error;
-
-        if (oldserial->source.type != newserial->source.type)
-            goto error;
-
-        if ((newserial->source.type == VIR_DOMAIN_CHR_TYPE_DEV ||
-            newserial->source.type == VIR_DOMAIN_CHR_TYPE_FILE) &&
-            !STREQ_NULLABLE(oldserial->source.data.file.path,
-                            newserial->source.data.file.path))
-            goto error;
-        if (newserial->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
-           (!STREQ_NULLABLE(oldserial->source.data.nix.path,
-                            newserial->source.data.nix.path) ||
-            oldserial->source.data.nix.listen == newserial->source.data.nix.listen)) {
-
-            goto error;
-        }
-    }
-
-    return 0;
- error:
-    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                   _("changing serial device parameters is "
-                     "not supported by parallels driver"));
-    return -1;
-}
-
-static int
-parallelsApplyVideoParams(parallelsDomObjPtr pdom,
-                          virDomainVideoDefPtr *oldvideos, int nold,
-                           virDomainVideoDefPtr *newvideos, int nnew)
-{
-    virDomainVideoDefPtr old, new;
-    char str_vram[32];
-
-    if (nold != 1 || nnew != 1) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Only one video device is "
-                         "supported by parallels driver"));
-        return -1;
-    }
-
-    old = oldvideos[0];
-    new = newvideos[0];
-    if (new->type != VIR_DOMAIN_VIDEO_TYPE_VGA) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Only VGA video device is "
-                         "supported by parallels driver"));
-        return -1;
-    }
-
-    if (new->heads != 1) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Only one monitor is supported by parallels driver"));
-        return -1;
-    }
-
-    /* old->accel must be always non-NULL */
-    if (new->accel == NULL ||
-        old->accel->support2d != new->accel->support2d ||
-        old->accel->support3d != new->accel->support3d) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                   _("Changing video acceleration parameters is "
-                     "not supported by parallels driver"));
-        return -1;
-
-    }
-
-    if (old->vram != new->vram) {
-        if (new->vram % (1 << 10) != 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Video RAM size should be multiple of 1Mb."));
-            return -1;
-        }
-
-        snprintf(str_vram, 31, "%dK", new->vram);
-        str_vram[31] = '\0';
-
-        if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                            "--videosize", str_vram, NULL))
-            return -1;
-    }
-    return 0;
-}
-
-static int parallelsAddHdd(parallelsDomObjPtr pdom,
-                           virDomainDiskDefPtr disk)
-{
-    int ret = -1;
-    const char *src = virDomainDiskGetSource(disk);
-    int type = virDomainDiskGetType(disk);
-    const char *strbus;
-
-    virCommandPtr cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid,
-                                             "--device-add", "hdd", NULL);
-
-    if (type == VIR_STORAGE_TYPE_FILE) {
-        int format = virDomainDiskGetFormat(disk);
-
-        if (format != VIR_STORAGE_FILE_PLOOP) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("Invalid disk format: %d"), type);
-            goto cleanup;
-        }
-
-        virCommandAddArg(cmd, "--image");
-    } else if (VIR_STORAGE_TYPE_BLOCK) {
-        virCommandAddArg(cmd, "--device");
-    } else {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("Invalid disk type: %d"), type);
-        goto cleanup;
-    }
-
-    virCommandAddArg(cmd, src);
-
-    if (!(strbus = parallelsGetDiskBusName(disk->bus))) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("Invalid disk bus: %d"), disk->bus);
-        goto cleanup;
-    }
-
-    virCommandAddArgFormat(cmd, "--iface=%s", strbus);
-
-    if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
-        virCommandAddArgFormat(cmd, "--position=%d",
-                               disk->info.addr.drive.target);
-
-    if (virCommandRun(cmd, NULL) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    virCommandFree(cmd);
-    return ret;
-}
-
-static int parallelsRemoveHdd(parallelsDomObjPtr pdom,
-                              virDomainDiskDefPtr disk)
-{
-    char prlname[16];
-
-    prlname[15] = '\0';
-    snprintf(prlname, 15, "hdd%d", virDiskNameToIndex(disk->dst));
-
-    if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                        "--device-del", prlname,
-                        "--detach-only", NULL))
-        return -1;
-
-    return 0;
-}
-
-static int
-parallelsApplyDisksParams(parallelsDomObjPtr pdom,
-                          virDomainDiskDefPtr *olddisks, int nold,
-                          virDomainDiskDefPtr *newdisks, int nnew)
-{
-    size_t i, j;
-
-    for (i = 0; i < nold; i++) {
-        virDomainDiskDefPtr newdisk = NULL;
-        virDomainDiskDefPtr olddisk = olddisks[i];
-        for (j = 0; j < nnew; j++) {
-            if (STREQ_NULLABLE(newdisks[j]->dst, olddisk->dst)) {
-                newdisk = newdisks[j];
-                break;
-            }
-        }
-
-        if (!newdisk) {
-            if (parallelsRemoveHdd(pdom, olddisk)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               _("Can't remove disk '%s' "
-                                 "in the specified config"), olddisks[i]->serial);
-                return -1;
-            }
-
-            continue;
-        }
-
-        if (olddisk->bus != newdisk->bus ||
-            olddisk->info.addr.drive.target != newdisk->info.addr.drive.target ||
-            !STREQ_NULLABLE(virDomainDiskGetSource(olddisk),
-                            virDomainDiskGetSource(newdisk))) {
-
-            char prlname[16];
-            char strpos[16];
-            const char *strbus;
-
-            prlname[15] = '\0';
-            snprintf(prlname, 15, "hdd%d", virDiskNameToIndex(newdisk->dst));
-
-            strpos[15] = '\0';
-            snprintf(strpos, 15, "%d", newdisk->info.addr.drive.target);
-
-            if (!(strbus = parallelsGetDiskBusName(newdisk->bus))) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               _("Unsupported disk bus: %d"), newdisk->bus);
-                return -1;
-            }
-
-            if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                                "--device-set", prlname,
-                                "--iface", strbus,
-                                "--position", strpos,
-                                "--image", newdisk->src, NULL))
-                return -1;
-        }
-    }
-
-    for (i = 0; i < nnew; i++) {
-        virDomainDiskDefPtr newdisk = newdisks[i];
-        bool found = false;
-        for (j = 0; j < nold; j++)
-            if (STREQ_NULLABLE(olddisks[j]->dst, newdisk->dst))
-                found = true;
-        if (found)
-            continue;
-
-        if (parallelsAddHdd(pdom, newdisk))
-            return -1;
-    }
-
-    return 0;
-}
-
-static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom,
-                                     virDomainNetDefPtr oldnet,
-                                     virDomainNetDefPtr newnet)
-{
-    bool create = false;
-    bool is_changed = false;
-    virCommandPtr cmd = NULL;
-    char strmac[VIR_MAC_STRING_BUFLEN];
-    size_t i;
-    int ret = -1;
-
-    if (!oldnet) {
-        create = true;
-        if (VIR_ALLOC(oldnet) < 0)
-            return -1;
-    }
-
-    if (!create && oldnet->type != newnet->type) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Changing network type is not supported"));
-        goto cleanup;
-    }
-
-    if (!STREQ_NULLABLE(oldnet->model, newnet->model)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Changing network device model is not supported"));
-        goto cleanup;
-    }
-
-    if (!STREQ_NULLABLE(oldnet->data.network.portgroup,
-                        newnet->data.network.portgroup)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Changing network portgroup is not supported"));
-        goto cleanup;
-    }
-
-    if (!virNetDevVPortProfileEqual(oldnet->virtPortProfile,
-                                    newnet->virtPortProfile)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Changing virtual port profile is not supported"));
-        goto cleanup;
-    }
-
-    if (newnet->tune.sndbuf_specified) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Setting send buffer size is not supported"));
-        goto cleanup;
-    }
-
-    if (!STREQ_NULLABLE(oldnet->script, newnet->script)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Setting startup script is not supported"));
-        goto cleanup;
-    }
-
-    if (!STREQ_NULLABLE(oldnet->filter, newnet->filter)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Changing filter params is not supported"));
-        goto cleanup;
-    }
-
-    if (newnet->bandwidth != NULL) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Setting bandwidth params is not supported"));
-        goto cleanup;
-    }
-
-    for (i = 0; i < sizeof(newnet->vlan); i++) {
-        if (((char *)&newnet->vlan)[i] != 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("Setting vlan params is not supported"));
-            goto cleanup;
-        }
-    }
-
-    /* Here we know, that there are no differences, that are forbidden.
-     * Check is something changed, if no - do nothing */
-
-    if (create) {
-        cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid,
-                                   "--device-add", "net", NULL);
-    } else {
-        cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid,
-                                   "--device-set", newnet->ifname, NULL);
-    }
-
-    if (virMacAddrCmp(&oldnet->mac, &newnet->mac)) {
-        virMacAddrFormat(&newnet->mac, strmac);
-        virCommandAddArgFormat(cmd, "--mac=%s", strmac);
-        is_changed = true;
-    }
-
-    if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) {
-        if (STREQ_NULLABLE(newnet->data.network.name,
-                           PARALLELS_ROUTED_NETWORK_NAME)) {
-            virCommandAddArgFormat(cmd, "--type=routed");
-        } else {
-            virCommandAddArgFormat(cmd, "--network=%s",
-                                   newnet->data.network.name);
-        }
-
-        is_changed = true;
-    }
-
-    if (oldnet->linkstate != newnet->linkstate) {
-        if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP) {
-            virCommandAddArgFormat(cmd, "--connect");
-        } else if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
-            virCommandAddArgFormat(cmd, "--disconnect");
-        }
-        is_changed = true;
-    }
-
-    if (!create && !is_changed) {
-        /* nothing changed - no need to run prlctl */
-        ret = 0;
-        goto cleanup;
-    }
-
-    if (virCommandRun(cmd, NULL) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    if (create)
-        VIR_FREE(oldnet);
-    virCommandFree(cmd);
-    return ret;
-}
-
-static int
-parallelsApplyIfacesParams(parallelsDomObjPtr pdom,
-                            virDomainNetDefPtr *oldnets, int nold,
-                            virDomainNetDefPtr *newnets, int nnew)
-{
-    size_t i, j;
-    virDomainNetDefPtr newnet;
-    virDomainNetDefPtr oldnet;
-    bool found;
-
-    for (i = 0; i < nold; i++) {
-        newnet = NULL;
-        oldnet = oldnets[i];
-        for (j = 0; j < nnew; j++) {
-            if (STREQ_NULLABLE(newnets[j]->ifname, oldnet->ifname)) {
-                newnet = newnets[j];
-                break;
-            }
-        }
-
-        if (!newnet) {
-            if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                                "--device-del", oldnet->ifname, NULL) < 0)
-                return -1;
-
-            continue;
-        }
-
-        if (parallelsApplyIfaceParams(pdom, oldnet, newnet) < 0)
-            return -1;
-    }
-
-    for (i = 0; i < nnew; i++) {
-        newnet = newnets[i];
-        found = false;
-
-        for (j = 0; j < nold; j++)
-            if (STREQ_NULLABLE(oldnets[j]->ifname, newnet->ifname))
-                found = true;
-        if (found)
-            continue;
-
-        if (parallelsApplyIfaceParams(pdom, NULL, newnet))
-            return -1;
-    }
-
-    return 0;
-}
-
-static int
-parallelsApplyChanges(virDomainObjPtr dom, virDomainDefPtr new)
-{
-    char buf[32];
-    size_t i;
-
-    virDomainDefPtr old = dom->def;
-    parallelsDomObjPtr pdom = dom->privateData;
-
-    if (new->description && !STREQ_NULLABLE(old->description, new->description)) {
-        if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                            "--description", new->description, NULL))
-            return -1;
-    }
-
-    if (new->name && !STREQ_NULLABLE(old->name, new->name)) {
-        if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                            "--name", new->name, NULL))
-            return -1;
-    }
-
-    if (new->title && !STREQ_NULLABLE(old->title, new->title)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("titles are not supported by parallels driver"));
-        return -1;
-    }
-
-    if (new->blkio.ndevices > 0) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("blkio parameters are not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    if (old->mem.max_balloon != new->mem.max_balloon) {
-        if (new->mem.max_balloon != new->mem.cur_balloon) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing balloon parameters is not supported "
-                         "by parallels driver"));
-           return -1;
-        }
-
-        if (new->mem.max_balloon % (1 << 10) != 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Memory size should be multiple of 1Mb."));
-            return -1;
-        }
-
-        snprintf(buf, 31, "%llu", new->mem.max_balloon >> 10);
-        buf[31] = '\0';
-
-        if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                            "--memsize", buf, NULL))
-            return -1;
-    }
-
-    if (old->mem.nhugepages != new->mem.nhugepages ||
-        old->mem.hard_limit != new->mem.hard_limit ||
-        old->mem.soft_limit != new->mem.soft_limit ||
-        old->mem.min_guarantee != new->mem.min_guarantee ||
-        old->mem.swap_hard_limit != new->mem.swap_hard_limit) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Memory parameter is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    if (old->vcpus != new->vcpus) {
-        if (new->vcpus != new->maxvcpus) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("current vcpus must be equal to maxvcpus"));
-            return -1;
-        }
-
-        snprintf(buf, 31, "%d", new->vcpus);
-        buf[31] = '\0';
-
-        if (parallelsCmdRun(PRLCTL, "set", pdom->uuid,
-                            "--cpus", buf, NULL))
-            return -1;
-    }
-
-    if (old->placement_mode != new->placement_mode) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing cpu placement mode is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    if ((old->cpumask != NULL || new->cpumask != NULL) &&
-        (old->cpumask == NULL || new->cpumask == NULL ||
-        !virBitmapEqual(old->cpumask, new->cpumask))) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing cpu mask is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    if (old->cputune.shares != new->cputune.shares ||
-        old->cputune.sharesSpecified != new->cputune.sharesSpecified ||
-        old->cputune.period != new->cputune.period ||
-        old->cputune.quota != new->cputune.quota ||
-        old->cputune.nvcpupin != new->cputune.nvcpupin) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("cputune is not supported by parallels driver"));
-        return -1;
-    }
-
-    if (!virDomainNumatuneEquals(old->numatune, new->numatune)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                        _("numa parameters are not supported "
-                          "by parallels driver"));
-        return -1;
-    }
-
-    if (old->onReboot != new->onReboot ||
-        old->onPoweroff != new->onPoweroff ||
-        old->onCrash != new->onCrash) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("on_reboot, on_poweroff and on_crash parameters "
-                         "are not supported by parallels driver"));
-        return -1;
-    }
-
-    /* we fill only type and arch fields in parallelsLoadDomain for
-     * hvm type and also init for containers, so we can check that all
-     * other paramenters are null and boot devices config is default */
-
-    if (!STREQ_NULLABLE(old->os.type, new->os.type) ||
-        old->os.arch != new->os.arch ||
-        new->os.machine != NULL || new->os.bootmenu != 0 ||
-        new->os.kernel != NULL || new->os.initrd != NULL ||
-        new->os.cmdline != NULL || new->os.root != NULL ||
-        new->os.loader != NULL || new->os.bootloader != NULL ||
-        new->os.bootloaderArgs != NULL || new->os.smbios_mode != 0 ||
-        new->os.bios.useserial != 0) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing OS parameters is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-    if (STREQ(new->os.type, "hvm")) {
-        if (new->os.nBootDevs != 1 ||
-            new->os.bootDevs[0] != VIR_DOMAIN_BOOT_DISK ||
-            new->os.init != NULL || new->os.initargv != NULL) {
-
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("changing OS parameters is not supported "
-                             "by parallels driver"));
-            return -1;
-        }
-    } else {
-        if (new->os.nBootDevs != 0 ||
-            !STREQ_NULLABLE(old->os.init, new->os.init) ||
-            (new->os.initargv != NULL && new->os.initargv[0] != NULL)) {
-
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("changing OS parameters is not supported "
-                             "by parallels driver"));
-            return -1;
-        }
-    }
-
-
-    if (!STREQ_NULLABLE(old->emulator, new->emulator)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing emulator is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
-        if (old->features[i] != new->features[i]) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("changing features is not supported "
-                             "by parallels driver"));
-            return -1;
-        }
-    }
-
-    if (new->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC ||
-        new->clock.ntimers != 0) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing clock parameters is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    if (parallelsApplyGraphicsParams(old->graphics, old->ngraphics,
-                                   new->graphics, new->ngraphics) < 0)
-        return -1;
-
-    if (new->nfss != 0 ||
-        new->nsounds != 0 || new->nhostdevs != 0 ||
-        new->nredirdevs != 0 || new->nsmartcards != 0 ||
-        new->nparallels || new->nchannels != 0 ||
-        new->nleases != 0 || new->nhubs != 0) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing devices parameters is not supported "
-                         "by parallels driver"));
-        return -1;
-    }
-
-    /* there may be one auto-input */
-    if (new->ninputs > 1 ||
-        (new->ninputs > 1 &&
-        (new->inputs[0]->type != VIR_DOMAIN_INPUT_TYPE_MOUSE ||
-        new->inputs[0]->bus != VIR_DOMAIN_INPUT_BUS_PS2))) {
-
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("changing input devices parameters is not supported "
-                         "by parallels driver"));
-    }
-
-
-    if (parallelsApplySerialParams(old->serials, old->nserials,
-                                   new->serials, new->nserials) < 0)
-        return -1;
-
-    if (parallelsApplySerialParams(old->consoles, old->nconsoles,
-                                   new->consoles, new->nconsoles) < 0)
-        return -1;
-
-    if (parallelsApplyVideoParams(pdom, old->videos, old->nvideos,
-                                   new->videos, new->nvideos) < 0)
-        return -1;
-    if (parallelsApplyDisksParams(pdom, old->disks, old->ndisks,
-                                  new->disks, new->ndisks) < 0)
-        return -1;
-    if (parallelsApplyIfacesParams(pdom, old->nets, old->nnets,
-                                  new->nets, new->nnets) < 0)
-        return -1;
-
-    return 0;
-}
-
-static int
 parallelsCreateVm(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def)
 {
     char uuidstr[VIR_UUID_STRING_BUFLEN];
@@ -1479,7 +744,7 @@ parallelsDomainDefineXML(virConnectPtr conn, const char *xml)
         }
     }
 
-    if (parallelsApplyChanges(olddom, def) < 0) {
+    if (prlsdkApplyConfig(conn, olddom, def) < 0) {
         virObjectUnlock(olddom);
         goto cleanup;
     }
diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c
index 4a5a900..0940bfb 100644
--- a/src/parallels/parallels_sdk.c
+++ b/src/parallels/parallels_sdk.c
@@ -28,6 +28,7 @@
 #include "nodeinfo.h"
 #include "virlog.h"
 #include "datatypes.h"
+#include "domain_conf.h"
 
 #include "parallels_sdk.h"
 
@@ -1609,3 +1610,930 @@ prlsdkDomainChangeState(virDomainPtr domain,
     virObjectUnlock(dom);
     return ret;
 }
+
+static int
+prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def)
+{
+    size_t i;
+    PRL_VM_TYPE vmType;
+    PRL_RESULT pret;
+
+    if (def->title) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("titles are not supported by parallels driver"));
+        return -1;
+    }
+
+    if (def->blkio.ndevices > 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("blkio parameters are not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (def->mem.max_balloon != def->mem.cur_balloon) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                   _("changing balloon parameters is not supported "
+                     "by parallels driver"));
+       return -1;
+    }
+
+    if (def->mem.max_balloon % (1 << 10) != 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                   _("Memory size should be multiple of 1Mb."));
+        return -1;
+    }
+
+    if (def->mem.nhugepages ||
+        def->mem.hard_limit ||
+        def->mem.soft_limit ||
+        def->mem.min_guarantee ||
+        def->mem.swap_hard_limit) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Memory parameter is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (def->vcpus != def->maxvcpus) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                   _("current vcpus must be equal to maxvcpus"));
+        return -1;
+    }
+
+    if (def->placement_mode) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing cpu placement mode is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (def->cpumask != NULL) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing cpu mask is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (def->cputune.shares ||
+        def->cputune.sharesSpecified ||
+        def->cputune.period ||
+        def->cputune.quota ||
+        def->cputune.nvcpupin) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("cputune is not supported by parallels driver"));
+        return -1;
+    }
+
+    if (def->numatune) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("numa parameters are not supported "
+                          "by parallels driver"));
+        return -1;
+    }
+
+    if (def->onReboot ||
+        def->onPoweroff ||
+        def->onCrash) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("on_reboot, on_poweroff and on_crash parameters "
+                         "are not supported by parallels driver"));
+        return -1;
+    }
+
+    /* we fill only type and arch fields in parallelsLoadDomain for
+     * hvm type and also init for containers, so we can check that all
+     * other paramenters are null and boot devices config is default */
+
+    if (def->os.machine != NULL || def->os.bootmenu != 0 ||
+        def->os.kernel != NULL || def->os.initrd != NULL ||
+        def->os.cmdline != NULL || def->os.root != NULL ||
+        def->os.loader != NULL || def->os.bootloader != NULL ||
+        def->os.bootloaderArgs != NULL || def->os.smbios_mode != 0 ||
+        def->os.bios.useserial != 0) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing OS parameters is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    pret = PrlVmCfg_GetVmType(sdkdom, &vmType);
+    if (PRL_FAILED(pret)) {
+        logPrlError(pret);
+        return -1;
+    }
+
+    if (!(vmType == PVT_VM && STREQ(def->os.type, "hvm")) &&
+        !(vmType == PVT_CT && STREQ(def->os.type, "exe"))) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing OS type is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (STREQ(def->os.type, "hvm")) {
+        if (def->os.nBootDevs != 1 ||
+            def->os.bootDevs[0] != VIR_DOMAIN_BOOT_DISK ||
+            def->os.init != NULL || def->os.initargv != NULL) {
+
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("changing OS parameters is not supported "
+                             "by parallels driver"));
+            return -1;
+        }
+    } else {
+        if (def->os.nBootDevs != 0 ||
+            !STREQ_NULLABLE(def->os.init, "/sbin/init") ||
+            (def->os.initargv != NULL && def->os.initargv[0] != NULL)) {
+
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("changing OS parameters is not supported "
+                             "by parallels driver"));
+            return -1;
+        }
+    }
+
+    if (def->emulator) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing emulator is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
+        if (def->features[i]) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("changing features is not supported "
+                             "by parallels driver"));
+            return -1;
+        }
+    }
+
+    if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC ||
+        def->clock.ntimers != 0) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing clock parameters is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    if (def->nfss != 0 ||
+        def->nsounds != 0 || def->nhostdevs != 0 ||
+        def->nredirdevs != 0 || def->nsmartcards != 0 ||
+        def->nparallels || def->nchannels != 0 ||
+        def->nleases != 0 || def->nhubs != 0) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing devices parameters is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    /* there may be one auto-input */
+    if (def->ninputs != 0 &&
+        (def->ninputs != 2 &&
+            def->inputs[0]->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
+            def->inputs[0]->bus != VIR_DOMAIN_INPUT_BUS_PS2 &&
+            def->inputs[1]->type != VIR_DOMAIN_INPUT_TYPE_KBD &&
+            def->inputs[1]->bus != VIR_DOMAIN_INPUT_BUS_PS2)) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("changing input devices parameters is not supported "
+                         "by parallels driver"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int prlsdkClearDevices(PRL_HANDLE sdkdom)
+{
+    PRL_RESULT pret;
+    PRL_UINT32 n, i;
+    PRL_HANDLE devList;
+    PRL_HANDLE dev;
+    int ret = -1;
+
+    pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_DISABLED);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmCfg_GetAllDevices(sdkdom, &devList);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlHndlList_GetItemsCount(devList, &n);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    for (i = 0; i < n; i++) {
+        pret = PrlHndlList_GetItem(devList, i, &dev);
+        prlsdkCheckRetGoto(pret, cleanup);
+
+        pret = PrlVmDev_Remove(dev);
+        PrlHandle_Free(dev);
+    }
+
+    ret = 0;
+ cleanup:
+    PrlHandle_Free(devList);
+    return ret;
+}
+
+static int prlsdkCheckGraphicsUnsupportedParams(virDomainDefPtr def)
+{
+    virDomainGraphicsDefPtr gr;
+
+    if (def->ngraphics == 0)
+        return 0;
+
+    if (def->ngraphics >1) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server supports only "
+                         "one VNC per domain."));
+        return -1;
+    }
+
+    gr = def->graphics[0];
+
+    if (gr->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server supports only "
+                         "VNC graphics."));
+        return -1;
+    }
+
+    if (gr->data.vnc.websocket != 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "websockets for VNC graphics."));
+        return -1;
+    }
+
+    if (gr->data.vnc.keymap != 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "keymap setting for VNC graphics."));
+        return -1;
+    }
+
+    if (gr->data.vnc.sharePolicy == VIR_DOMAIN_GRAPHICS_VNC_SHARE_ALLOW_EXCLUSIVE) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "exclusive share policy for VNC graphics."));
+        return -1;
+    }
+
+    if (gr->data.vnc.socket) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "VNC graphics over unix sockets."));
+        return -1;
+    }
+
+    if (gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_FAIL ||
+            gr->data.vnc.auth.connected == VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "given action in case of password change."));
+        return -1;
+    }
+
+    if (gr->data.vnc.auth.expires) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "setting password expire time."));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int prlsdkCheckVideoUnsupportedParams(virDomainDefPtr def)
+{
+    bool isCt = STREQ(def->os.type, "exe");
+    virDomainVideoDefPtr v;
+
+    if (isCt) {
+        if (def->nvideos == 0) {
+            return 0;
+        } else {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Video adapters are not supported "
+                             "int containers."));
+            return -1;
+        }
+    } else {
+        if (def->nvideos != 1) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Parallels Cloud Server supports "
+                             "only one video adapter."));
+            return -1;
+        }
+    }
+
+    v = def->videos[0];
+
+    if (v->type != VIR_DOMAIN_VIDEO_TYPE_VGA) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server supports "
+                         "only VGA video adapters."));
+        return -1;
+    }
+
+    if (v->heads != 1) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "multihead video adapters."));
+        return -1;
+    }
+
+    if (v->accel == NULL || v->accel->support2d || v->accel->support3d) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "setting video acceleration parameters."));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int prlsdkCheckSerialUnsupportedParams(virDomainChrDefPtr chr)
+{
+    if (chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Specified character device type is not supported "
+                         "by parallels driver."));
+        return -1;
+    }
+
+    if (chr->targetTypeAttr) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Specified character device target type is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_DEV &&
+        chr->source.type != VIR_DOMAIN_CHR_TYPE_FILE &&
+        chr->source.type != VIR_DOMAIN_CHR_TYPE_UNIX) {
+
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Specified character device source type is not "
+                         "supported by Parallels Cloud Server."));
+        return -1;
+    }
+
+    if (chr->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting device info for character devices is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (chr->nseclabels > 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting security labels is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int prlsdkCheckNetUnsupportedParams(virDomainNetDefPtr net)
+{
+    if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Specified network adapter type is not "
+                         "supported by Parallels Cloud Server."));
+        return -1;
+    }
+
+    if (net->backend.tap || net->backend.vhost) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Interface backend parameters are not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->data.network.portgroup) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Virtual network portgroups are not "
+                         "supported by Parallels Cloud Server."));
+        return -1;
+    }
+
+    if (net->tune.sndbuf_specified) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting interface sndbuf is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->script) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting interface script is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->ifname_guest) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting guest interface name is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting device info for network devices is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->filter) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting network filter is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->bandwidth) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting network bandwidth is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (net->vlan.trunk) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting up vlans is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int prlsdkCheckDiskUnsupportedParams(virDomainDiskDefPtr disk)
+{
+    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Only hard disks are supported "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+   if (disk->blockio.logical_block_size ||
+       disk->blockio.physical_block_size) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk block sizes is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->blkdeviotune.total_bytes_sec ||
+        disk->blkdeviotune.read_bytes_sec ||
+        disk->blkdeviotune.write_bytes_sec ||
+        disk->blkdeviotune.total_iops_sec ||
+        disk->blkdeviotune.read_iops_sec ||
+        disk->blkdeviotune.write_iops_sec) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk io limits is not "
+                         "supported by parallels driver yet."));
+        return -1;
+    }
+
+    if (disk->serial) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk serial number is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->wwn) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk wwn id is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->vendor) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk vendor is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->product) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk product id is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk cache mode is not "
+                         "supported by parallels driver yet."));
+        return -1;
+    }
+
+    if (disk->error_policy != VIR_DOMAIN_DISK_ERROR_POLICY_DEFAULT) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk error policy is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->iomode) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting disk io mode is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->copy_on_read) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Disk copy_on_read is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->startupPolicy != VIR_DOMAIN_STARTUP_POLICY_DEFAULT) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting up disk startup policy is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->transient) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Transient disks are not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->discard) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting up disk discard parameter is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->iothread) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Setting up disk io thread # is not "
+                         "supported by parallels driver."));
+        return -1;
+    }
+
+    if (disk->src->type != VIR_STORAGE_TYPE_FILE &&
+        disk->src->type != VIR_STORAGE_TYPE_BLOCK) {
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Only disk and block storage types are "
+                         "supported by parallels driver."));
+        return -1;
+
+    }
+
+    return 0;
+}
+
+static int prlsdkApplyGraphicsParams(PRL_HANDLE sdkdom, virDomainDefPtr def)
+{
+    virDomainGraphicsDefPtr gr;
+    PRL_RESULT pret;
+    int ret  = -1;
+
+    if (prlsdkCheckGraphicsUnsupportedParams(def))
+        return -1;
+
+    if (def->ngraphics == 0)
+        return 0;
+
+    gr = def->graphics[0];
+
+    if (gr->data.vnc.autoport) {
+        pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_AUTO);
+        prlsdkCheckRetGoto(pret, cleanup);
+    } else {
+        pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_MANUAL);
+        prlsdkCheckRetGoto(pret, cleanup);
+
+        pret = PrlVmCfg_SetVNCPort(sdkdom, gr->data.vnc.port);
+        prlsdkCheckRetGoto(pret, cleanup);
+    }
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+static int prlsdkApplyVideoParams(PRL_HANDLE sdkdom ATTRIBUTE_UNUSED, virDomainDefPtr def)
+{
+    PRL_RESULT pret;
+
+    if (def->nvideos == 0)
+        return 0;
+
+    if (IS_CT(def)) {
+        /* ignore video parameters */
+        return 0;
+    }
+
+    if (prlsdkCheckVideoUnsupportedParams(def))
+        return -1;
+
+    pret = PrlVmCfg_SetVideoRamSize(sdkdom, def->videos[0]->vram >> 10);
+    prlsdkCheckRetGoto(pret, error);
+
+    return 0;
+ error:
+    return -1;
+}
+
+static int prlsdkAddSerial(PRL_HANDLE sdkdom, virDomainChrDefPtr chr)
+{
+    PRL_RESULT pret;
+    PRL_HANDLE sdkchr = PRL_INVALID_HANDLE;
+    PRL_VM_DEV_EMULATION_TYPE emutype;
+    PRL_SERIAL_PORT_SOCKET_OPERATION_MODE socket_mode;
+    char *path;
+    int ret = -1;
+
+    if (prlsdkCheckSerialUnsupportedParams(chr) < 0)
+        return -1;
+
+    pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_SERIAL_PORT, &sdkchr);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    switch (chr->source.type) {
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+        emutype = PDT_USE_REAL_DEVICE;
+        path = chr->source.data.file.path;
+        break;
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        emutype = PDT_USE_OUTPUT_FILE;
+        path = chr->source.data.file.path;
+        break;
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        emutype = PDT_USE_SERIAL_PORT_SOCKET_MODE;
+        path = chr->source.data.nix.path;
+        if (chr->source.data.nix.listen)
+            socket_mode = PSP_SERIAL_SOCKET_SERVER;
+        else
+            socket_mode = PSP_SERIAL_SOCKET_CLIENT;
+        break;
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Parallels Cloud Server doesn't support "
+                         "specified serial source type."));
+        goto cleanup;
+    }
+
+    pret = PrlVmDev_SetEmulatedType(sdkchr, emutype);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetSysName(sdkchr, path);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetFriendlyName(sdkchr, path);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    if (chr->source.type == VIR_DOMAIN_CHR_TYPE_UNIX) {
+        pret = PrlVmDevSerial_SetSocketMode(sdkchr, socket_mode);
+        prlsdkCheckRetGoto(pret, cleanup);
+    }
+
+    pret = PrlVmDev_SetEnabled(sdkchr, 1);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetIndex(sdkchr, chr->target.port);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    ret = 0;
+ cleanup:
+    PrlHandle_Free(sdkchr);
+    return ret;
+}
+
+#define PRL_MAC_STRING_BUFNAME  13
+
+const char * prlsdkFormatMac(virMacAddrPtr mac, char *macstr)
+{
+    snprintf(macstr, VIR_MAC_STRING_BUFLEN,
+             "%02X%02X%02X%02X%02X%02X",
+             mac->addr[0], mac->addr[1], mac->addr[2],
+             mac->addr[3], mac->addr[4], mac->addr[5]);
+    macstr[PRL_MAC_STRING_BUFNAME - 1] = '\0';
+    return macstr;
+}
+
+static int prlsdkAddNet(PRL_HANDLE sdkdom, virDomainNetDefPtr net)
+{
+    PRL_RESULT pret;
+    PRL_HANDLE sdknet = PRL_INVALID_HANDLE;
+    int ret = -1;
+    char macstr[PRL_MAC_STRING_BUFNAME];
+
+    if (prlsdkCheckNetUnsupportedParams(net) < 0)
+        return -1;
+
+    pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_GENERIC_NETWORK_ADAPTER, &sdknet);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetEnabled(sdknet, 1);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetConnected(sdknet, net->linkstate);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDevNet_SetHostInterfaceName(sdknet, net->ifname);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    prlsdkFormatMac(&net->mac, macstr);
+    pret = PrlVmDevNet_SetMacAddress(sdknet, macstr);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    if (STREQ(net->data.network.name, PARALLELS_ROUTED_NETWORK_NAME)) {
+        pret = PrlVmDev_SetEmulatedType(sdknet, PNA_ROUTED);
+        prlsdkCheckRetGoto(pret, cleanup);
+    } else {
+        pret = PrlVmDevNet_SetVirtualNetworkId(sdknet, net->data.network.name);
+        prlsdkCheckRetGoto(pret, cleanup);
+    }
+
+    if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_YES)
+        pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 0);
+    else if (net->trustGuestRxFilters == VIR_TRISTATE_BOOL_NO)
+        pret = PrlVmDevNet_SetPktFilterPreventMacSpoof(sdknet, 1);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    ret = 0;
+ cleanup:
+    PrlHandle_Free(sdknet);
+    return ret;
+}
+
+static int prlsdkAddDisk(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk)
+{
+    PRL_RESULT pret;
+    PRL_HANDLE sdkdisk = PRL_INVALID_HANDLE;
+    int ret = -1;
+    PRL_VM_DEV_EMULATION_TYPE emutype;
+    PRL_MASS_STORAGE_INTERFACE_TYPE sdkbus;
+
+    if (prlsdkCheckDiskUnsupportedParams(disk) < 0)
+        return -1;
+
+    pret = PrlVmCfg_CreateVmDev(sdkdom, PDE_HARD_DISK, &sdkdisk);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetEnabled(sdkdisk, 1);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetConnected(sdkdisk, 1);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    if (disk->src->type == VIR_STORAGE_TYPE_FILE) {
+        if (virDomainDiskGetFormat(disk) != VIR_STORAGE_FILE_PLOOP) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Invalid disk format: %d"), disk->src->type);
+            goto cleanup;
+        }
+
+        emutype = PDT_USE_IMAGE_FILE;
+    } else {
+        emutype = PDT_USE_REAL_DEVICE;
+    }
+
+    pret = PrlVmDev_SetEmulatedType(sdkdisk, emutype);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetSysName(sdkdisk, disk->src->path);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetFriendlyName(sdkdisk, disk->src->path);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    switch (disk->bus) {
+    case VIR_DOMAIN_DISK_BUS_IDE:
+        sdkbus = PMS_IDE_DEVICE;
+        break;
+    case VIR_DOMAIN_DISK_BUS_SCSI:
+        sdkbus = PMS_SCSI_DEVICE;
+        break;
+    case VIR_DOMAIN_DISK_BUS_SATA:
+        sdkbus = PMS_SATA_DEVICE;
+        break;
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Specified disk bus is not "
+                         "supported by Parallels Cloud Server."));
+        goto cleanup;
+    }
+
+    pret = PrlVmDev_SetIfaceType(sdkdisk, sdkbus);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    pret = PrlVmDev_SetStackIndex(sdkdisk, disk->info.addr.drive.target);
+    prlsdkCheckRetGoto(pret, cleanup);
+
+    return 0;
+ cleanup:
+    PrlHandle_Free(sdkdisk);
+    return ret;
+}
+
+static int
+prlsdkDoApplyConfig(PRL_HANDLE sdkdom,
+                    virDomainDefPtr def)
+{
+    PRL_RESULT pret;
+    size_t i;
+
+    if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0)
+        return -1;
+
+    if (def->description) {
+        pret = PrlVmCfg_SetDescription(sdkdom, def->description);
+        prlsdkCheckRetGoto(pret, error);
+    }
+
+    if (def->name) {
+        pret = PrlVmCfg_SetName(sdkdom, def->name);
+        prlsdkCheckRetGoto(pret, error);
+    }
+
+    pret = PrlVmCfg_SetRamSize(sdkdom, def->mem.max_balloon >> 10);
+    prlsdkCheckRetGoto(pret, error);
+
+    pret = PrlVmCfg_SetCpuCount(sdkdom, def->vcpus);
+    prlsdkCheckRetGoto(pret, error);
+
+    if (prlsdkClearDevices(sdkdom) < 0)
+        goto error;
+
+    if (prlsdkApplyGraphicsParams(sdkdom, def) < 0)
+        goto error;
+
+    if (prlsdkApplyVideoParams(sdkdom, def) < 0)
+        goto error;
+
+    for (i = 0; i < def->nserials; i++) {
+       if (prlsdkAddSerial(sdkdom, def->serials[i]) < 0)
+           goto error;
+    }
+
+    for (i = 0; i < def->nnets; i++) {
+       if (prlsdkAddNet(sdkdom, def->nets[i]) < 0)
+           goto error;
+    }
+
+    for (i = 0; i < def->ndisks; i++) {
+       if (prlsdkAddDisk(sdkdom, def->disks[i]) < 0)
+           goto error;
+    }
+
+    return 0;
+
+ error:
+    return -1;
+
+}
+
+int
+prlsdkApplyConfig(virConnectPtr conn,
+                  virDomainObjPtr dom,
+                  virDomainDefPtr new)
+{
+    parallelsConnPtr privconn = conn->privateData;
+    PRL_HANDLE sdkdom = PRL_INVALID_HANDLE;
+    PRL_HANDLE job = PRL_INVALID_HANDLE;
+    int ret;
+
+    sdkdom = prlsdkSdkDomainLookupByUUID(privconn, dom->def->uuid);
+    if (sdkdom == PRL_INVALID_HANDLE)
+        return -1;
+
+    job = PrlVm_BeginEdit(sdkdom);
+    if (waitJob(job, privconn->jobTimeout) < 0)
+        return -1;
+
+    ret = prlsdkDoApplyConfig(sdkdom, new);
+
+    job = PrlVm_Commit(sdkdom);
+    ret = waitJob(job, privconn->jobTimeout);
+
+    PrlHandle_Free(sdkdom);
+
+    return ret;
+}
diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h
index 1e26672..8de077c 100644
--- a/src/parallels/parallels_sdk.h
+++ b/src/parallels/parallels_sdk.h
@@ -44,3 +44,7 @@ typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdo
 int
 prlsdkDomainChangeState(virDomainPtr domain,
                         prlsdkChangeStateFunc chstate);
+int
+prlsdkApplyConfig(virConnectPtr conn,
+                  virDomainObjPtr dom,
+                  virDomainDefPtr new);
-- 
1.9.3




More information about the libvir-list mailing list