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

Maxim Nestratov mnestratov at parallels.com
Tue Nov 25 13:17:33 UTC 2014


18.11.2014 16:17, Dmitry Guryanov пишет:
> 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    | 930 +++++++++++++++++++++++++++++++++++++++
>   src/parallels/parallels_sdk.h    |   4 +
>   3 files changed, 935 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 d42456f..bccb2d7 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"
>   
> @@ -1608,3 +1609,932 @@ 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);
> +    }
> +
   Uuid should be applied here via PrlVmCfg_SetUuid

> +    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);
> +
> +    if (ret == 0) {
> +        job = PrlVm_Commit(sdkdom);
> +        ret = waitJob(job, privconn->jobTimeout);
> +    }
> +
> +    PrlHandle_Free(sdkdom);
> +
> +    return ret;
> +}
> diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h
> index 1e26672..8de077c 100644
> --- a/src/parallels/parallels_sdk.h
> +++ b/src/parallels/parallels_sdk.h
> @@ -44,3 +44,7 @@ typedef int (*prlsdkChangeStateFunc)(parallelsConnPtr privconn, PRL_HANDLE sdkdo
>   int
>   prlsdkDomainChangeState(virDomainPtr domain,
>                           prlsdkChangeStateFunc chstate);
> +int
> +prlsdkApplyConfig(virConnectPtr conn,
> +                  virDomainObjPtr dom,
> +                  virDomainDefPtr new);




More information about the libvir-list mailing list