parallels_driver.c 26.9 KB
Newer Older
D
Dmitry Guryanov 已提交
1 2 3 4
/*
 * parallels_driver.c: core driver functions for managing
 * Parallels Cloud Server hosts
 *
5
 * Copyright (C) 2014 Red Hat, Inc.
D
Dmitry Guryanov 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2012 Parallels, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library.  If not, see
D
Dmitry Guryanov 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
 * <http://www.gnu.org/licenses/>.
 *
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/statvfs.h>

#include "datatypes.h"
44
#include "virerror.h"
45
#include "viralloc.h"
46
#include "virlog.h"
47
#include "vircommand.h"
D
Dmitry Guryanov 已提交
48
#include "configmake.h"
49
#include "virfile.h"
50
#include "virstoragefile.h"
D
Dmitry Guryanov 已提交
51
#include "nodeinfo.h"
52
#include "virstring.h"
53
#include "cpu/cpu.h"
D
Dmitry Guryanov 已提交
54 55

#include "parallels_driver.h"
56
#include "parallels_utils.h"
57
#include "parallels_sdk.h"
D
Dmitry Guryanov 已提交
58 59 60

#define VIR_FROM_THIS VIR_FROM_PARALLELS

61 62
VIR_LOG_INIT("parallels.parallels_driver");

D
Dmitry Guryanov 已提交
63
#define PRLCTL                      "prlctl"
64
#define PRLSRVCTL                   "prlsrvctl"
D
Dmitry Guryanov 已提交
65

66
static int parallelsConnectClose(virConnectPtr conn);
D
Dmitry Guryanov 已提交
67

D
Dmitry Guryanov 已提交
68
void
D
Dmitry Guryanov 已提交
69 70 71 72 73
parallelsDriverLock(parallelsConnPtr driver)
{
    virMutexLock(&driver->lock);
}

D
Dmitry Guryanov 已提交
74
void
D
Dmitry Guryanov 已提交
75 76 77 78 79 80 81 82
parallelsDriverUnlock(parallelsConnPtr driver)
{
    virMutexUnlock(&driver->lock);
}

static virCapsPtr
parallelsBuildCapabilities(void)
{
83 84 85
    virCapsPtr caps = NULL;
    virCPUDefPtr cpu = NULL;
    virCPUDataPtr data = NULL;
D
Dmitry Guryanov 已提交
86
    virCapsGuestPtr guest;
87
    virNodeInfo nodeinfo;
D
Dmitry Guryanov 已提交
88

89
    if ((caps = virCapabilitiesNew(virArchFromHost(),
90
                                   false, false)) == NULL)
91
        return NULL;
D
Dmitry Guryanov 已提交
92 93

    if (nodeCapsInitNUMA(caps) < 0)
94
        goto error;
D
Dmitry Guryanov 已提交
95

96 97 98
    if ((guest = virCapabilitiesAddGuest(caps, "hvm",
                                         VIR_ARCH_X86_64,
                                         "parallels",
D
Dmitry Guryanov 已提交
99
                                         NULL, 0, NULL)) == NULL)
100
        goto error;
D
Dmitry Guryanov 已提交
101 102 103

    if (virCapabilitiesAddGuestDomain(guest,
                                      "parallels", NULL, NULL, 0, NULL) == NULL)
104
        goto error;
D
Dmitry Guryanov 已提交
105

106 107 108
    if ((guest = virCapabilitiesAddGuest(caps, "exe",
                                         VIR_ARCH_X86_64,
                                         "parallels",
109
                                         NULL, 0, NULL)) == NULL)
110
        goto error;
111 112 113

    if (virCapabilitiesAddGuestDomain(guest,
                                      "parallels", NULL, NULL, 0, NULL) == NULL)
114
        goto error;
115

116
    if (nodeGetInfo(&nodeinfo))
117 118
        goto error;

119
    if (VIR_ALLOC(cpu) < 0)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
        goto error;

    cpu->arch = caps->host.arch;
    cpu->type = VIR_CPU_TYPE_HOST;
    cpu->sockets = nodeinfo.sockets;
    cpu->cores = nodeinfo.cores;
    cpu->threads = nodeinfo.threads;

    caps->host.cpu = cpu;

    if (!(data = cpuNodeData(cpu->arch))
        || cpuDecode(cpu, data, NULL, 0, NULL) < 0) {
        goto cleanup;
    }

 cleanup:
    cpuDataFree(data);
D
Dmitry Guryanov 已提交
137 138
    return caps;

139
 error:
140
    virObjectUnref(caps);
141
    goto cleanup;
D
Dmitry Guryanov 已提交
142 143 144
}

static char *
145
parallelsConnectGetCapabilities(virConnectPtr conn)
D
Dmitry Guryanov 已提交
146 147 148 149 150
{
    parallelsConnPtr privconn = conn->privateData;
    char *xml;

    parallelsDriverLock(privconn);
151
    xml = virCapabilitiesFormatXML(privconn->caps);
D
Dmitry Guryanov 已提交
152 153 154 155
    parallelsDriverUnlock(privconn);
    return xml;
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
static int
parallelsDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
                            virCapsPtr caps ATTRIBUTE_UNUSED,
                            void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}


static int
parallelsDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                                  const virDomainDef *def ATTRIBUTE_UNUSED,
                                  virCapsPtr caps ATTRIBUTE_UNUSED,
                                  void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}


175 176
virDomainDefParserConfig parallelsDomainDefParserConfig = {
    .macPrefix = {0x42, 0x1C, 0x00},
177 178
    .devicesPostParseCallback = parallelsDomainDeviceDefPostParse,
    .domainPostParseCallback = parallelsDomainDefPostParse,
179 180 181
};


D
Dmitry Guryanov 已提交
182 183 184 185 186
static int
parallelsOpenDefault(virConnectPtr conn)
{
    parallelsConnPtr privconn;

187
    if (VIR_ALLOC(privconn) < 0)
D
Dmitry Guryanov 已提交
188 189 190 191
        return VIR_DRV_OPEN_ERROR;
    if (virMutexInit(&privconn->lock) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot initialize mutex"));
192 193 194 195 196 197
        goto err_free;
    }

    if (prlsdkInit(privconn)) {
        VIR_DEBUG("%s", _("Can't initialize Parallels SDK"));
        goto err_free;
D
Dmitry Guryanov 已提交
198 199
    }

200 201 202
    if (prlsdkConnect(privconn) < 0)
        goto err_free;

D
Dmitry Guryanov 已提交
203 204 205
    if (!(privconn->caps = parallelsBuildCapabilities()))
        goto error;

206 207
    if (!(privconn->xmlopt = virDomainXMLOptionNew(&parallelsDomainDefParserConfig,
                                                 NULL, NULL)))
208 209
        goto error;

210
    if (!(privconn->domains = virDomainObjListNew()))
D
Dmitry Guryanov 已提交
211 212
        goto error;

213 214 215 216 217 218
    if (!(privconn->domainEventState = virObjectEventStateNew()))
        goto error;

    if (prlsdkSubscribeToPCSEvents(privconn))
        goto error;

D
Dmitry Guryanov 已提交
219 220
    conn->privateData = privconn;

221
    if (prlsdkLoadDomains(privconn))
222 223
        goto error;

D
Dmitry Guryanov 已提交
224 225
    return VIR_DRV_OPEN_SUCCESS;

226
 error:
227
    virObjectUnref(privconn->domains);
228
    virObjectUnref(privconn->caps);
D
Dmitry Guryanov 已提交
229
    virStoragePoolObjListFree(&privconn->pools);
230
    virObjectEventStateFree(privconn->domainEventState);
231 232 233
    prlsdkDisconnect(privconn);
    prlsdkDeinit();
 err_free:
D
Dmitry Guryanov 已提交
234 235 236 237 238
    VIR_FREE(privconn);
    return VIR_DRV_OPEN_ERROR;
}

static virDrvOpenStatus
239 240 241
parallelsConnectOpen(virConnectPtr conn,
                     virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                     unsigned int flags)
D
Dmitry Guryanov 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
{
    int ret;

    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

    if (!conn->uri)
        return VIR_DRV_OPEN_DECLINED;

    if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "parallels"))
        return VIR_DRV_OPEN_DECLINED;

    /* Remote driver should handle these. */
    if (conn->uri->server)
        return VIR_DRV_OPEN_DECLINED;

    /* From this point on, the connection is for us. */
258 259 260 261
    if (!STREQ_NULLABLE(conn->uri->path, "/system")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected Parallels URI path '%s', try parallels:///system"),
                       conn->uri->path);
D
Dmitry Guryanov 已提交
262 263 264
        return VIR_DRV_OPEN_ERROR;
    }

265
    if ((ret = parallelsOpenDefault(conn)) != VIR_DRV_OPEN_SUCCESS)
D
Dmitry Guryanov 已提交
266 267 268 269 270 271
        return ret;

    return VIR_DRV_OPEN_SUCCESS;
}

static int
272
parallelsConnectClose(virConnectPtr conn)
D
Dmitry Guryanov 已提交
273 274 275 276
{
    parallelsConnPtr privconn = conn->privateData;

    parallelsDriverLock(privconn);
277
    prlsdkUnsubscribeFromPCSEvents(privconn);
278
    virObjectUnref(privconn->caps);
279
    virObjectUnref(privconn->xmlopt);
280
    virObjectUnref(privconn->domains);
281
    virObjectEventStateFree(privconn->domainEventState);
282
    prlsdkDisconnect(privconn);
D
Dmitry Guryanov 已提交
283
    conn->privateData = NULL;
284
    prlsdkDeinit();
D
Dmitry Guryanov 已提交
285 286 287 288 289 290 291 292 293

    parallelsDriverUnlock(privconn);
    virMutexDestroy(&privconn->lock);

    VIR_FREE(privconn);
    return 0;
}

static int
294
parallelsConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
D
Dmitry Guryanov 已提交
295
{
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    char *output, *sVer, *tmp;
    const char *searchStr = "prlsrvctl version ";
    int ret = -1;

    output = parallelsGetOutput(PRLSRVCTL, "--help", NULL);

    if (!output) {
        parallelsParseError();
        goto cleanup;
    }

    if (!(sVer = strstr(output, searchStr))) {
        parallelsParseError();
        goto cleanup;
    }

    sVer = sVer + strlen(searchStr);

    /* parallels server has versions number like 6.0.17977.782218,
     * so libvirt can handle only first two numbers. */
    if (!(tmp = strchr(sVer, '.'))) {
        parallelsParseError();
        goto cleanup;
    }

    if (!(tmp = strchr(tmp + 1, '.'))) {
        parallelsParseError();
        goto cleanup;
    }

    tmp[0] = '\0';
    if (virParseVersionString(sVer, hvVer, true) < 0) {
        parallelsParseError();
        goto cleanup;
    }

    ret = 0;

334
 cleanup:
335 336 337 338
    VIR_FREE(output);
    return ret;
}

339 340 341 342 343 344 345

static char *parallelsConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return virGetHostname();
}


346
static int
347
parallelsConnectListDomains(virConnectPtr conn, int *ids, int maxids)
348 349 350 351 352
{
    parallelsConnPtr privconn = conn->privateData;
    int n;

    parallelsDriverLock(privconn);
353 354
    n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
                                     NULL, NULL);
355 356 357 358 359 360
    parallelsDriverUnlock(privconn);

    return n;
}

static int
361
parallelsConnectNumOfDomains(virConnectPtr conn)
362 363 364 365 366
{
    parallelsConnPtr privconn = conn->privateData;
    int count;

    parallelsDriverLock(privconn);
367 368
    count = virDomainObjListNumOfDomains(privconn->domains, true,
                                         NULL, NULL);
369 370 371 372 373 374
    parallelsDriverUnlock(privconn);

    return count;
}

static int
375
parallelsConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
376 377 378 379 380 381
{
    parallelsConnPtr privconn = conn->privateData;
    int n;

    parallelsDriverLock(privconn);
    memset(names, 0, sizeof(*names) * maxnames);
382
    n = virDomainObjListGetInactiveNames(privconn->domains, names,
383
                                         maxnames, NULL, NULL);
384 385 386 387 388 389
    parallelsDriverUnlock(privconn);

    return n;
}

static int
390
parallelsConnectNumOfDefinedDomains(virConnectPtr conn)
391 392 393 394 395
{
    parallelsConnPtr privconn = conn->privateData;
    int count;

    parallelsDriverLock(privconn);
396 397
    count = virDomainObjListNumOfDomains(privconn->domains, false,
                                         NULL, NULL);
398 399 400 401 402 403
    parallelsDriverUnlock(privconn);

    return count;
}

static int
404 405 406
parallelsConnectListAllDomains(virConnectPtr conn,
                               virDomainPtr **domains,
                               unsigned int flags)
407 408 409 410
{
    parallelsConnPtr privconn = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
411
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
412
    parallelsDriverLock(privconn);
413 414
    ret = virDomainObjListExport(privconn->domains, conn, domains,
                                 NULL, flags);
415 416 417 418 419 420
    parallelsDriverUnlock(privconn);

    return ret;
}

static virDomainPtr
421
parallelsDomainLookupByID(virConnectPtr conn, int id)
422 423 424 425 426 427
{
    parallelsConnPtr privconn = conn->privateData;
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

    parallelsDriverLock(privconn);
428
    dom = virDomainObjListFindByID(privconn->domains, id);
429 430 431 432 433 434 435 436 437 438 439
    parallelsDriverUnlock(privconn);

    if (dom == NULL) {
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }

    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
    if (ret)
        ret->id = dom->def->id;

440
 cleanup:
441
    if (dom)
442
        virObjectUnlock(dom);
443 444 445 446
    return ret;
}

static virDomainPtr
447
parallelsDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
448 449 450 451 452 453
{
    parallelsConnPtr privconn = conn->privateData;
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

    parallelsDriverLock(privconn);
454
    dom = virDomainObjListFindByUUID(privconn->domains, uuid);
455 456 457 458 459 460 461 462 463 464 465 466 467 468
    parallelsDriverUnlock(privconn);

    if (dom == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
    if (ret)
        ret->id = dom->def->id;

469
 cleanup:
470
    if (dom)
471
        virObjectUnlock(dom);
472 473 474 475
    return ret;
}

static virDomainPtr
476
parallelsDomainLookupByName(virConnectPtr conn, const char *name)
477 478 479 480 481 482
{
    parallelsConnPtr privconn = conn->privateData;
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

    parallelsDriverLock(privconn);
483
    dom = virDomainObjListFindByName(privconn->domains, name);
484 485 486 487 488 489 490 491 492 493 494 495
    parallelsDriverUnlock(privconn);

    if (dom == NULL) {
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
        goto cleanup;
    }

    ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
    if (ret)
        ret->id = dom->def->id;

496
 cleanup:
497
    if (dom)
498
        virObjectUnlock(dom);
499 500 501 502
    return ret;
}

static int
503
parallelsDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
504 505 506 507 508 509
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainObjPtr privdom;
    int ret = -1;

    parallelsDriverLock(privconn);
510
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
511 512 513 514 515 516 517 518 519 520 521 522 523 524
    parallelsDriverUnlock(privconn);

    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    info->state = virDomainObjGetState(privdom, NULL);
    info->memory = privdom->def->mem.cur_balloon;
    info->maxMem = privdom->def->mem.max_balloon;
    info->nrVirtCpu = privdom->def->vcpus;
    info->cpuTime = 0;
    ret = 0;

525
 cleanup:
526
    if (privdom)
527
        virObjectUnlock(privdom);
528 529 530 531
    return ret;
}

static char *
532
parallelsDomainGetOSType(virDomainPtr domain)
533 534 535 536 537 538 539
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainObjPtr privdom;

    char *ret = NULL;

    parallelsDriverLock(privconn);
540
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
541 542 543 544 545
    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

546
    ignore_value(VIR_STRDUP(ret, privdom->def->os.type));
547

548
 cleanup:
549
    if (privdom)
550
        virObjectUnlock(privdom);
551 552 553 554 555 556 557 558 559 560 561 562
    parallelsDriverUnlock(privconn);
    return ret;
}

static int
parallelsDomainIsPersistent(virDomainPtr domain)
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainObjPtr privdom;
    int ret = -1;

    parallelsDriverLock(privconn);
563
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
564 565 566 567 568 569 570
    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    ret = 1;

571
 cleanup:
572
    if (privdom)
573
        virObjectUnlock(privdom);
574 575 576 577 578 579 580 581 582 583 584 585 586 587
    parallelsDriverUnlock(privconn);
    return ret;
}

static int
parallelsDomainGetState(virDomainPtr domain,
                  int *state, int *reason, unsigned int flags)
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainObjPtr privdom;
    int ret = -1;
    virCheckFlags(0, -1);

    parallelsDriverLock(privconn);
588
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
589 590 591 592 593 594 595 596 597 598
    parallelsDriverUnlock(privconn);

    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    *state = virDomainObjGetState(privdom, reason);
    ret = 0;

599
 cleanup:
600
    if (privdom)
601
        virObjectUnlock(privdom);
602 603 604 605 606 607 608 609 610 611 612 613 614 615
    return ret;
}

static char *
parallelsDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainDefPtr def;
    virDomainObjPtr privdom;
    char *ret = NULL;

    /* Flags checked by virDomainDefFormat */

    parallelsDriverLock(privconn);
616
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
617 618 619 620 621 622 623 624 625 626 627 628
    parallelsDriverUnlock(privconn);

    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
        privdom->newDef ? privdom->newDef : privdom->def;

    ret = virDomainDefFormat(def, flags);

629
 cleanup:
630
    if (privdom)
631
        virObjectUnlock(privdom);
632 633 634 635 636 637 638 639 640 641 642
    return ret;
}

static int
parallelsDomainGetAutostart(virDomainPtr domain, int *autostart)
{
    parallelsConnPtr privconn = domain->conn->privateData;
    virDomainObjPtr privdom;
    int ret = -1;

    parallelsDriverLock(privconn);
643
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
644 645 646 647 648 649 650 651 652 653
    parallelsDriverUnlock(privconn);

    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    *autostart = privdom->autostart;
    ret = 0;

654
 cleanup:
655
    if (privdom)
656
        virObjectUnlock(privdom);
657
    return ret;
D
Dmitry Guryanov 已提交
658 659
}

660
static int
661
parallelsCreateVm(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def)
662 663 664 665 666
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(def->uuid, uuidstr);

667
    if (parallelsCmdRun(PRLCTL, "create", def->name, "--no-hdd",
668
                        "--uuid", uuidstr, NULL) < 0)
669
        return -1;
670 671 672 673

    return 0;
}

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
static int
parallelsCreateCt(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDefPtr def)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(def->uuid, uuidstr);

    if (def->nfss != 1 ||
        def->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE) {

        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("There must be only 1 template FS for "
                         "container creation"));
        goto error;
    }

    if (parallelsCmdRun(PRLCTL, "create", def->name, "--vmtype", "ct",
                        "--uuid", uuidstr,
                        "--ostemplate", def->fss[0]->src, NULL) < 0)
        goto error;

    return 0;

697
 error:
698 699 700
    return -1;
}

701 702 703 704 705 706
static virDomainPtr
parallelsDomainDefineXML(virConnectPtr conn, const char *xml)
{
    parallelsConnPtr privconn = conn->privateData;
    virDomainPtr ret = NULL;
    virDomainDefPtr def;
707
    virDomainObjPtr olddom = NULL;
708
    virDomainObjPtr dom = NULL;
709 710

    parallelsDriverLock(privconn);
711 712
    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
                                       1 << VIR_DOMAIN_VIRT_PARALLELS,
713 714 715 716 717 718
                                       VIR_DOMAIN_XML_INACTIVE)) == NULL) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Can't parse XML desc"));
        goto cleanup;
    }

719 720 721
    olddom = virDomainObjListFindByUUID(privconn->domains, def->uuid);
    if (olddom == NULL) {
        virResetLastError();
722 723 724 725 726 727 728 729 730
        if (STREQ(def->os.type, "hvm")) {
            if (parallelsCreateVm(conn, def))
                goto cleanup;
        } else if (STREQ(def->os.type, "exe")) {
            if (parallelsCreateCt(conn, def))
                goto cleanup;
        } else {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Unsupported OS type: %s"), def->os.type);
731
            goto cleanup;
732
        }
733 734 735 736
        dom = prlsdkAddDomain(privconn, def->uuid);
        if (dom)
            virObjectUnlock(dom);
        else
737
            goto cleanup;
738
        olddom = virDomainObjListFindByName(privconn->domains, def->name);
739
        if (!olddom) {
740 741
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Domain for '%s' is not defined after creation"),
E
Eric Blake 已提交
742
                           def->name ? def->name : _("(unnamed)"));
743 744
            goto cleanup;
        }
745 746
    }

747
    if (prlsdkApplyConfig(conn, olddom, def) < 0) {
748
        virObjectUnlock(olddom);
749 750
        goto cleanup;
    }
751
    virObjectUnlock(olddom);
752

753
    ret = virGetDomain(conn, def->name, def->uuid);
754
    if (ret)
755
        ret->id = def->id;
756

757
 cleanup:
758 759 760 761 762
    virDomainDefFree(def);
    parallelsDriverUnlock(privconn);
    return ret;
}

763 764 765 766 767 768 769
static int
parallelsNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                     virNodeInfoPtr nodeinfo)
{
    return nodeGetInfo(nodeinfo);
}

770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
static int parallelsConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Encryption is not relevant / applicable to way we talk to PCS */
    return 0;
}

static int parallelsConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* We run CLI tools directly so this is secure */
    return 1;
}

static int parallelsConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}

787

788 789 790 791 792 793 794 795 796 797 798 799
static char *
parallelsConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
                            const char **xmlCPUs,
                            unsigned int ncpus,
                            unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);

    return cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
}


800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
static int
parallelsDomainGetVcpus(virDomainPtr domain,
                        virVcpuInfoPtr info,
                        int maxinfo,
                        unsigned char *cpumaps,
                        int maplen)
{
    parallelsConnPtr privconn = domain->conn->privateData;
    parallelsDomObjPtr privdomdata = NULL;
    virDomainObjPtr privdom = NULL;
    size_t i;
    int v, maxcpu, hostcpus;
    int ret = -1;

    parallelsDriverLock(privconn);
    privdom = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
    parallelsDriverUnlock(privconn);

    if (privdom == NULL) {
        parallelsDomNotFoundError(domain);
        goto cleanup;
    }

    if (!virDomainObjIsActive(privdom)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
        goto cleanup;
    }

    privdomdata = privdom->privateData;
    if ((hostcpus = nodeGetCPUCount()) < 0)
        goto cleanup;

    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

    if (maxinfo >= 1) {
        if (info != NULL) {
            memset(info, 0, sizeof(*info) * maxinfo);
            for (i = 0; i < maxinfo; i++) {
                info[i].number = i;
                info[i].state = VIR_VCPU_RUNNING;
            }
        }
        if (cpumaps != NULL) {
            unsigned char *tmpmap = NULL;
            int tmpmapLen = 0;

            memset(cpumaps, 0, maplen * maxinfo);
            virBitmapToData(privdomdata->cpumask, &tmpmap, &tmpmapLen);
            if (tmpmapLen > maplen)
                tmpmapLen = maplen;

            for (v = 0; v < maxinfo; v++) {
                unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
                memcpy(cpumap, tmpmap, tmpmapLen);
            }
            VIR_FREE(tmpmap);
        }
    }
    ret = maxinfo;

 cleanup:
    if (privdom)
        virObjectUnlock(privdom);
    return ret;
}


871 872 873 874 875 876 877 878 879
static int
parallelsNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
                       unsigned char **cpumap,
                       unsigned int *online,
                       unsigned int flags)
{
    return nodeGetCPUMap(cpumap, online, flags);
}

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
static int
parallelsConnectDomainEventRegisterAny(virConnectPtr conn,
                                       virDomainPtr domain,
                                       int eventID,
                                       virConnectDomainEventGenericCallback callback,
                                       void *opaque,
                                       virFreeCallback freecb)
{
    int ret = -1;
    parallelsConnPtr privconn = conn->privateData;
    if (virDomainEventStateRegisterID(conn,
                                      privconn->domainEventState,
                                      domain, eventID,
                                      callback, opaque, freecb, &ret) < 0)
        ret = -1;
    return ret;
}

static int
parallelsConnectDomainEventDeregisterAny(virConnectPtr conn,
                                         int callbackID)
{
    parallelsConnPtr privconn = conn->privateData;
    int ret = -1;

    if (virObjectEventStateDeregisterID(conn,
                                        privconn->domainEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    return ret;
}
915

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
static int parallelsDomainSuspend(virDomainPtr domain)
{
    return prlsdkDomainChangeState(domain, prlsdkPause);
}

static int parallelsDomainResume(virDomainPtr domain)
{
    return prlsdkDomainChangeState(domain, prlsdkResume);
}

static int parallelsDomainCreate(virDomainPtr domain)
{
    return prlsdkDomainChangeState(domain, prlsdkStart);
}

static int parallelsDomainDestroy(virDomainPtr domain)
{
    return prlsdkDomainChangeState(domain, prlsdkKill);
}

static int parallelsDomainShutdown(virDomainPtr domain)
{
    return prlsdkDomainChangeState(domain, prlsdkStop);
}

941
static virHypervisorDriver parallelsDriver = {
D
Dmitry Guryanov 已提交
942 943
    .no = VIR_DRV_PARALLELS,
    .name = "Parallels",
944 945 946
    .connectOpen = parallelsConnectOpen,            /* 0.10.0 */
    .connectClose = parallelsConnectClose,          /* 0.10.0 */
    .connectGetVersion = parallelsConnectGetVersion,   /* 0.10.0 */
947
    .connectGetHostname = parallelsConnectGetHostname,      /* 0.10.0 */
948
    .nodeGetInfo = parallelsNodeGetInfo,      /* 0.10.0 */
949
    .connectGetCapabilities = parallelsConnectGetCapabilities,      /* 0.10.0 */
950
    .connectBaselineCPU = parallelsConnectBaselineCPU, /* 1.2.6 */
951 952 953 954 955 956 957 958 959 960
    .connectListDomains = parallelsConnectListDomains,      /* 0.10.0 */
    .connectNumOfDomains = parallelsConnectNumOfDomains,    /* 0.10.0 */
    .connectListDefinedDomains = parallelsConnectListDefinedDomains,        /* 0.10.0 */
    .connectNumOfDefinedDomains = parallelsConnectNumOfDefinedDomains,      /* 0.10.0 */
    .connectListAllDomains = parallelsConnectListAllDomains, /* 0.10.0 */
    .domainLookupByID = parallelsDomainLookupByID,    /* 0.10.0 */
    .domainLookupByUUID = parallelsDomainLookupByUUID,        /* 0.10.0 */
    .domainLookupByName = parallelsDomainLookupByName,        /* 0.10.0 */
    .domainGetOSType = parallelsDomainGetOSType,    /* 0.10.0 */
    .domainGetInfo = parallelsDomainGetInfo,  /* 0.10.0 */
961 962 963 964
    .domainGetState = parallelsDomainGetState,        /* 0.10.0 */
    .domainGetXMLDesc = parallelsDomainGetXMLDesc,    /* 0.10.0 */
    .domainIsPersistent = parallelsDomainIsPersistent,        /* 0.10.0 */
    .domainGetAutostart = parallelsDomainGetAutostart,        /* 0.10.0 */
965
    .domainGetVcpus = parallelsDomainGetVcpus, /* 1.2.6 */
966 967 968 969
    .domainSuspend = parallelsDomainSuspend,    /* 0.10.0 */
    .domainResume = parallelsDomainResume,    /* 0.10.0 */
    .domainDestroy = parallelsDomainDestroy,  /* 0.10.0 */
    .domainShutdown = parallelsDomainShutdown, /* 0.10.0 */
970
    .domainCreate = parallelsDomainCreate,    /* 0.10.0 */
971
    .domainDefineXML = parallelsDomainDefineXML,      /* 0.10.0 */
972 973
    .connectDomainEventRegisterAny = parallelsConnectDomainEventRegisterAny, /* 1.2.10 */
    .connectDomainEventDeregisterAny = parallelsConnectDomainEventDeregisterAny, /* 1.2.10 */
974
    .nodeGetCPUMap = parallelsNodeGetCPUMap, /* 1.2.8 */
975 976 977
    .connectIsEncrypted = parallelsConnectIsEncrypted, /* 1.2.5 */
    .connectIsSecure = parallelsConnectIsSecure, /* 1.2.5 */
    .connectIsAlive = parallelsConnectIsAlive, /* 1.2.5 */
D
Dmitry Guryanov 已提交
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
};

/**
 * parallelsRegister:
 *
 * Registers the parallels driver
 */
int
parallelsRegister(void)
{
    char *prlctl_path;

    prlctl_path = virFindFileInPath(PRLCTL);
    if (!prlctl_path) {
        VIR_DEBUG("%s", _("Can't find prlctl command in the PATH env"));
        return 0;
    }

    VIR_FREE(prlctl_path);

998
    if (virRegisterHypervisorDriver(&parallelsDriver) < 0)
D
Dmitry Guryanov 已提交
999
        return -1;
D
Dmitry Guryanov 已提交
1000 1001
    if (parallelsStorageRegister())
        return -1;
D
Dmitry Guryanov 已提交
1002 1003
    if (parallelsNetworkRegister())
        return -1;
D
Dmitry Guryanov 已提交
1004 1005 1006

    return 0;
}