vz_driver.c 41.8 KB
Newer Older
D
Dmitry Guryanov 已提交
1
/*
2
 * vz_driver.c: core driver functions for managing
D
Dmitry Guryanov 已提交
3 4
 * Parallels Cloud Server hosts
 *
5
 * Copyright (C) 2014-2015 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"
54
#include "virtypedparam.h"
D
Dmitry Guryanov 已提交
55

56 57 58
#include "vz_driver.h"
#include "vz_utils.h"
#include "vz_sdk.h"
D
Dmitry Guryanov 已提交
59 60 61

#define VIR_FROM_THIS VIR_FROM_PARALLELS

62 63
VIR_LOG_INIT("parallels.parallels_driver");

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

67
static int vzConnectClose(virConnectPtr conn);
D
Dmitry Guryanov 已提交
68

D
Dmitry Guryanov 已提交
69
void
70
vzDriverLock(vzConnPtr driver)
D
Dmitry Guryanov 已提交
71 72 73 74
{
    virMutexLock(&driver->lock);
}

D
Dmitry Guryanov 已提交
75
void
76
vzDriverUnlock(vzConnPtr driver)
D
Dmitry Guryanov 已提交
77 78 79 80
{
    virMutexUnlock(&driver->lock);
}

D
Dmitry Guryanov 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
static int
vzCapsAddGuestDomain(virCapsPtr caps,
                     virDomainOSType ostype,
                     virArch arch,
                     const char * emulator,
                     virDomainVirtType virt_type)
{
    virCapsGuestPtr guest;

    if ((guest = virCapabilitiesAddGuest(caps, ostype, arch, emulator,
                                         NULL, 0, NULL)) == NULL)
        return -1;


    if (virCapabilitiesAddGuestDomain(guest, virt_type,
                                      NULL, NULL, 0, NULL) == NULL)
        return -1;

    return 0;
}

D
Dmitry Guryanov 已提交
102
static virCapsPtr
103
vzBuildCapabilities(void)
D
Dmitry Guryanov 已提交
104
{
105 106 107 108
    virCapsPtr caps = NULL;
    virCPUDefPtr cpu = NULL;
    virCPUDataPtr data = NULL;
    virNodeInfo nodeinfo;
D
Dmitry Guryanov 已提交
109 110 111 112 113 114 115 116 117 118 119
    virDomainOSType ostypes[] = {
        VIR_DOMAIN_OSTYPE_HVM,
        VIR_DOMAIN_OSTYPE_EXE
    };
    virArch archs[] = { VIR_ARCH_I686, VIR_ARCH_X86_64 };
    const char *const emulators[] = { "parallels", "vz" };
    virDomainVirtType virt_types[] = {
        VIR_DOMAIN_VIRT_PARALLELS,
        VIR_DOMAIN_VIRT_VZ
    };
    size_t i, j, k;
D
Dmitry Guryanov 已提交
120

121
    if ((caps = virCapabilitiesNew(virArchFromHost(),
122
                                   false, false)) == NULL)
123
        return NULL;
D
Dmitry Guryanov 已提交
124

125
    if (nodeCapsInitNUMA(NULL, caps) < 0)
126
        goto error;
D
Dmitry Guryanov 已提交
127

D
Dmitry Guryanov 已提交
128 129 130 131 132 133
    for (i = 0; i < 2; i++)
        for (j = 0; j < 2; j++)
            for (k = 0; k < 2; k++)
                if (vzCapsAddGuestDomain(caps, ostypes[i], archs[j],
                                         emulators[k], virt_types[k]) < 0)
                    goto error;
134

135
    if (nodeGetInfo(NULL, &nodeinfo))
136 137
        goto error;

138
    if (VIR_ALLOC(cpu) < 0)
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        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 已提交
156 157
    return caps;

158
 error:
159
    virObjectUnref(caps);
160
    goto cleanup;
D
Dmitry Guryanov 已提交
161 162 163
}

static char *
164
vzConnectGetCapabilities(virConnectPtr conn)
D
Dmitry Guryanov 已提交
165
{
166
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
167 168
    char *xml;

169
    vzDriverLock(privconn);
170
    xml = virCapabilitiesFormatXML(privconn->caps);
171
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
172 173 174
    return xml;
}

175
static int
176
vzDomainDefPostParse(virDomainDefPtr def,
M
Michal Privoznik 已提交
177
                     virCapsPtr caps ATTRIBUTE_UNUSED,
178
                     unsigned int parseFlags ATTRIBUTE_UNUSED,
M
Michal Privoznik 已提交
179
                     void *opaque ATTRIBUTE_UNUSED)
180
{
181 182 183 184
    /* memory hotplug tunables are not supported by this driver */
    if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0)
        return -1;

185 186 187 188
    return 0;
}

static int
189
vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
M
Michal Privoznik 已提交
190 191
                           const virDomainDef *def,
                           virCapsPtr caps ATTRIBUTE_UNUSED,
192
                           unsigned int parseFlags ATTRIBUTE_UNUSED,
M
Michal Privoznik 已提交
193
                           void *opaque ATTRIBUTE_UNUSED)
194
{
195 196 197 198 199 200
    int ret = -1;

    if (dev->type == VIR_DOMAIN_DEVICE_NET &&
        (dev->data.net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
         dev->data.net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
        !dev->data.net->model &&
201
        def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
202 203 204 205 206 207
        VIR_STRDUP(dev->data.net->model, "e1000") < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    return ret;
208 209 210
}


211
virDomainDefParserConfig vzDomainDefParserConfig = {
212
    .macPrefix = {0x42, 0x1C, 0x00},
213 214
    .devicesPostParseCallback = vzDomainDeviceDefPostParse,
    .domainPostParseCallback = vzDomainDefPostParse,
215 216 217
};


D
Dmitry Guryanov 已提交
218
static int
219
vzOpenDefault(virConnectPtr conn)
D
Dmitry Guryanov 已提交
220
{
221
    vzConnPtr privconn;
D
Dmitry Guryanov 已提交
222

223
    if (VIR_ALLOC(privconn) < 0)
D
Dmitry Guryanov 已提交
224 225 226 227
        return VIR_DRV_OPEN_ERROR;
    if (virMutexInit(&privconn->lock) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot initialize mutex"));
228 229 230
        goto err_free;
    }

231 232
    privconn->drivername = conn->driver->name;

233
    if (prlsdkInit()) {
234 235
        VIR_DEBUG("%s", _("Can't initialize Parallels SDK"));
        goto err_free;
D
Dmitry Guryanov 已提交
236 237
    }

238 239 240
    if (prlsdkConnect(privconn) < 0)
        goto err_free;

241
    if (!(privconn->caps = vzBuildCapabilities()))
D
Dmitry Guryanov 已提交
242 243
        goto error;

244
    if (!(privconn->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig,
M
Michal Privoznik 已提交
245
                                                   NULL, NULL)))
246 247
        goto error;

248
    if (!(privconn->domains = virDomainObjListNew()))
D
Dmitry Guryanov 已提交
249 250
        goto error;

251 252 253 254 255 256
    if (!(privconn->domainEventState = virObjectEventStateNew()))
        goto error;

    if (prlsdkSubscribeToPCSEvents(privconn))
        goto error;

D
Dmitry Guryanov 已提交
257 258
    conn->privateData = privconn;

259
    if (prlsdkLoadDomains(privconn))
260 261
        goto error;

D
Dmitry Guryanov 已提交
262 263
    return VIR_DRV_OPEN_SUCCESS;

264
 error:
265
    virObjectUnref(privconn->domains);
266
    virObjectUnref(privconn->caps);
267
    virObjectEventStateFree(privconn->domainEventState);
268 269 270
    prlsdkDisconnect(privconn);
    prlsdkDeinit();
 err_free:
271
    conn->privateData = NULL;
D
Dmitry Guryanov 已提交
272 273 274 275 276
    VIR_FREE(privconn);
    return VIR_DRV_OPEN_ERROR;
}

static virDrvOpenStatus
277
vzConnectOpen(virConnectPtr conn,
M
Michal Privoznik 已提交
278 279
              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
              unsigned int flags)
D
Dmitry Guryanov 已提交
280 281 282 283 284 285 286 287
{
    int ret;

    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

    if (!conn->uri)
        return VIR_DRV_OPEN_DECLINED;

288 289 290 291 292 293 294 295 296 297 298
    if (!conn->uri->scheme)
        return VIR_DRV_OPEN_DECLINED;

    if (STRNEQ(conn->uri->scheme, "vz") &&
        STRNEQ(conn->uri->scheme, "parallels"))
        return VIR_DRV_OPEN_DECLINED;

    if (STREQ(conn->uri->scheme, "vz") && STRNEQ(conn->driver->name, "vz"))
        return VIR_DRV_OPEN_DECLINED;

    if (STREQ(conn->uri->scheme, "parallels") && STRNEQ(conn->driver->name, "Parallels"))
D
Dmitry Guryanov 已提交
299 300 301 302 303 304 305
        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. */
306
    if (STRNEQ_NULLABLE(conn->uri->path, "/system")) {
307
        virReportError(VIR_ERR_INTERNAL_ERROR,
308
                       _("Unexpected Virtuozzo URI path '%s', try vz:///system"),
309
                       conn->uri->path);
D
Dmitry Guryanov 已提交
310 311 312
        return VIR_DRV_OPEN_ERROR;
    }

313
    if ((ret = vzOpenDefault(conn)) != VIR_DRV_OPEN_SUCCESS)
D
Dmitry Guryanov 已提交
314 315 316 317 318 319
        return ret;

    return VIR_DRV_OPEN_SUCCESS;
}

static int
320
vzConnectClose(virConnectPtr conn)
D
Dmitry Guryanov 已提交
321
{
322
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
323

324 325 326
    if (!privconn)
        return 0;

327
    vzDriverLock(privconn);
328
    prlsdkUnsubscribeFromPCSEvents(privconn);
329
    virObjectUnref(privconn->caps);
330
    virObjectUnref(privconn->xmlopt);
331
    virObjectUnref(privconn->domains);
332
    virObjectEventStateFree(privconn->domainEventState);
333
    prlsdkDisconnect(privconn);
D
Dmitry Guryanov 已提交
334
    conn->privateData = NULL;
335
    prlsdkDeinit();
D
Dmitry Guryanov 已提交
336

337
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
338 339 340 341 342 343 344
    virMutexDestroy(&privconn->lock);

    VIR_FREE(privconn);
    return 0;
}

static int
345
vzConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
D
Dmitry Guryanov 已提交
346
{
347 348 349 350
    char *output, *sVer, *tmp;
    const char *searchStr = "prlsrvctl version ";
    int ret = -1;

351
    output = vzGetOutput(PRLSRVCTL, "--help", NULL);
352 353

    if (!output) {
354
        vzParseError();
355 356 357 358
        goto cleanup;
    }

    if (!(sVer = strstr(output, searchStr))) {
359
        vzParseError();
360 361 362 363 364 365 366 367
        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, '.'))) {
368
        vzParseError();
369 370 371 372
        goto cleanup;
    }

    if (!(tmp = strchr(tmp + 1, '.'))) {
373
        vzParseError();
374 375 376 377 378
        goto cleanup;
    }

    tmp[0] = '\0';
    if (virParseVersionString(sVer, hvVer, true) < 0) {
379
        vzParseError();
380 381 382 383 384
        goto cleanup;
    }

    ret = 0;

385
 cleanup:
386 387 388 389
    VIR_FREE(output);
    return ret;
}

390

391
static char *vzConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
392 393 394 395 396
{
    return virGetHostname();
}


397
static int
398
vzConnectListDomains(virConnectPtr conn, int *ids, int maxids)
399
{
400
    vzConnPtr privconn = conn->privateData;
401 402
    int n;

403
    vzDriverLock(privconn);
404 405
    n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
                                     NULL, NULL);
406
    vzDriverUnlock(privconn);
407 408 409 410 411

    return n;
}

static int
412
vzConnectNumOfDomains(virConnectPtr conn)
413
{
414
    vzConnPtr privconn = conn->privateData;
415 416
    int count;

417
    vzDriverLock(privconn);
418 419
    count = virDomainObjListNumOfDomains(privconn->domains, true,
                                         NULL, NULL);
420
    vzDriverUnlock(privconn);
421 422 423 424 425

    return count;
}

static int
426
vzConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
427
{
428
    vzConnPtr privconn = conn->privateData;
429 430
    int n;

431
    vzDriverLock(privconn);
432
    memset(names, 0, sizeof(*names) * maxnames);
433
    n = virDomainObjListGetInactiveNames(privconn->domains, names,
434
                                         maxnames, NULL, NULL);
435
    vzDriverUnlock(privconn);
436 437 438 439 440

    return n;
}

static int
441
vzConnectNumOfDefinedDomains(virConnectPtr conn)
442
{
443
    vzConnPtr privconn = conn->privateData;
444 445
    int count;

446
    vzDriverLock(privconn);
447 448
    count = virDomainObjListNumOfDomains(privconn->domains, false,
                                         NULL, NULL);
449
    vzDriverUnlock(privconn);
450 451 452 453 454

    return count;
}

static int
455
vzConnectListAllDomains(virConnectPtr conn,
M
Michal Privoznik 已提交
456 457
                        virDomainPtr **domains,
                        unsigned int flags)
458
{
459
    vzConnPtr privconn = conn->privateData;
460 461
    int ret = -1;

O
Osier Yang 已提交
462
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
463
    vzDriverLock(privconn);
464 465
    ret = virDomainObjListExport(privconn->domains, conn, domains,
                                 NULL, flags);
466
    vzDriverUnlock(privconn);
467 468 469 470 471

    return ret;
}

static virDomainPtr
472
vzDomainLookupByID(virConnectPtr conn, int id)
473
{
474
    vzConnPtr privconn = conn->privateData;
475 476 477
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

478
    vzDriverLock(privconn);
479
    dom = virDomainObjListFindByID(privconn->domains, id);
480
    vzDriverUnlock(privconn);
481 482 483 484 485 486 487 488 489 490

    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;

491
 cleanup:
492
    if (dom)
493
        virObjectUnlock(dom);
494 495 496 497
    return ret;
}

static virDomainPtr
498
vzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
499
{
500
    vzConnPtr privconn = conn->privateData;
501 502 503
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

504
    vzDriverLock(privconn);
505
    dom = virDomainObjListFindByUUID(privconn->domains, uuid);
506
    vzDriverUnlock(privconn);
507 508 509 510 511 512 513 514 515 516 517 518 519

    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;

520
 cleanup:
521
    if (dom)
522
        virObjectUnlock(dom);
523 524 525 526
    return ret;
}

static virDomainPtr
527
vzDomainLookupByName(virConnectPtr conn, const char *name)
528
{
529
    vzConnPtr privconn = conn->privateData;
530 531 532
    virDomainPtr ret = NULL;
    virDomainObjPtr dom;

533
    vzDriverLock(privconn);
534
    dom = virDomainObjListFindByName(privconn->domains, name);
535
    vzDriverUnlock(privconn);
536 537 538 539 540 541 542 543 544 545 546

    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;

547
 cleanup:
548
    virDomainObjEndAPI(&dom);
549 550 551 552
    return ret;
}

static int
553
vzDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
554 555 556 557
{
    virDomainObjPtr privdom;
    int ret = -1;

558
    if (!(privdom = vzDomObjFromDomainRef(domain)))
559 560 561 562
        goto cleanup;

    info->state = virDomainObjGetState(privdom, NULL);
    info->memory = privdom->def->mem.cur_balloon;
563
    info->maxMem = virDomainDefGetMemoryActual(privdom->def);
564
    info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
565
    info->cpuTime = 0;
566 567 568 569 570

    if (virDomainObjIsActive(privdom)) {
        unsigned long long vtime;
        size_t i;

571
        for (i = 0; i < virDomainDefGetVcpus(privdom->def); ++i) {
572 573 574 575 576 577 578 579
            if (prlsdkGetVcpuStats(privdom, i, &vtime) < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot read cputime for domain"));
                goto cleanup;
            }
            info->cpuTime += vtime;
        }
    }
580 581
    ret = 0;

582
 cleanup:
583
    virDomainObjEndAPI(&privdom);
584 585 586 587
    return ret;
}

static char *
588
vzDomainGetOSType(virDomainPtr domain)
589 590 591 592 593
{
    virDomainObjPtr privdom;

    char *ret = NULL;

594
    if (!(privdom = vzDomObjFromDomain(domain)))
595 596
        goto cleanup;

597
    ignore_value(VIR_STRDUP(ret, virDomainOSTypeToString(privdom->def->os.type)));
598

599
 cleanup:
600
    if (privdom)
601
        virObjectUnlock(privdom);
602 603 604 605
    return ret;
}

static int
606
vzDomainIsPersistent(virDomainPtr domain)
607 608 609 610
{
    virDomainObjPtr privdom;
    int ret = -1;

611
    if (!(privdom = vzDomObjFromDomain(domain)))
612 613 614 615
        goto cleanup;

    ret = 1;

616
 cleanup:
617
    if (privdom)
618
        virObjectUnlock(privdom);
619 620 621 622
    return ret;
}

static int
623
vzDomainGetState(virDomainPtr domain,
M
Michal Privoznik 已提交
624
                 int *state, int *reason, unsigned int flags)
625 626 627 628 629
{
    virDomainObjPtr privdom;
    int ret = -1;
    virCheckFlags(0, -1);

630
    if (!(privdom = vzDomObjFromDomain(domain)))
631 632 633 634 635
        goto cleanup;

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

636
 cleanup:
637
    if (privdom)
638
        virObjectUnlock(privdom);
639 640 641 642
    return ret;
}

static char *
643
vzDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
644
{
645
    vzConnPtr privconn = domain->conn->privateData;
646 647 648 649 650 651
    virDomainDefPtr def;
    virDomainObjPtr privdom;
    char *ret = NULL;

    /* Flags checked by virDomainDefFormat */

652
    if (!(privdom = vzDomObjFromDomain(domain)))
653 654 655 656 657
        goto cleanup;

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

658
    ret = virDomainDefFormat(def, privconn->caps, flags);
659

660
 cleanup:
661
    if (privdom)
662
        virObjectUnlock(privdom);
663 664 665 666
    return ret;
}

static int
667
vzDomainGetAutostart(virDomainPtr domain, int *autostart)
668 669 670 671
{
    virDomainObjPtr privdom;
    int ret = -1;

672
    if (!(privdom = vzDomObjFromDomain(domain)))
673 674 675 676 677
        goto cleanup;

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

678
 cleanup:
679
    if (privdom)
680
        virObjectUnlock(privdom);
681
    return ret;
D
Dmitry Guryanov 已提交
682 683
}

684
static virDomainPtr
685
vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
686
{
687
    vzConnPtr privconn = conn->privateData;
688
    virDomainPtr retdom = NULL;
689
    virDomainDefPtr def;
690
    virDomainObjPtr olddom = NULL;
691
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
692

693 694 695 696
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
697

698
    vzDriverLock(privconn);
699
    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
700
                                       parse_flags)) == NULL)
701 702
        goto cleanup;

703 704 705
    olddom = virDomainObjListFindByUUID(privconn->domains, def->uuid);
    if (olddom == NULL) {
        virResetLastError();
706
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
707
            if (prlsdkCreateVm(conn, def))
708
                goto cleanup;
709
        } else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
710
            if (prlsdkCreateCt(conn, def))
711 712 713
                goto cleanup;
        } else {
            virReportError(VIR_ERR_INVALID_ARG,
714 715
                           _("Unsupported OS type: %s"),
                           virDomainOSTypeToString(def->os.type));
716
            goto cleanup;
717
        }
718 719 720

        olddom = prlsdkAddDomain(privconn, def->uuid);
        if (!olddom)
721
            goto cleanup;
722
    } else {
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
        int state, reason;

        state = virDomainObjGetState(olddom, &reason);

        if (state == VIR_DOMAIN_SHUTOFF &&
            reason == VIR_DOMAIN_SHUTOFF_SAVED) {

            /* PCS doesn't store domain config in managed save state file.
             * It's forbidden to change config for VMs in this state.
             * It's possible to change config for containers, but after
             * restoring domain will have that new config, not a config,
             * which domain had at the moment of virDomainManagedSave.
             *
             * So forbid this operation, if config is changed. If it's
             * not changed - just do nothing. */

            if (!virDomainDefCheckABIStability(olddom->def, def)) {
                virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                               _("Can't change domain configuration "
                                 "in managed save state"));
                goto cleanup;
            }
        } else {
            if (prlsdkApplyConfig(conn, olddom, def))
                goto cleanup;
748

749 750 751
            if (prlsdkUpdateDomain(privconn, olddom))
                goto cleanup;
        }
752 753
    }

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

758
 cleanup:
759 760
    if (olddom)
        virObjectUnlock(olddom);
761
    virDomainDefFree(def);
762
    vzDriverUnlock(privconn);
763
    return retdom;
764 765
}

766
static virDomainPtr
767
vzDomainDefineXML(virConnectPtr conn, const char *xml)
768
{
769
    return vzDomainDefineXMLFlags(conn, xml, 0);
770 771 772
}


773
static int
774
vzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
M
Michal Privoznik 已提交
775
              virNodeInfoPtr nodeinfo)
776
{
777
    return nodeGetInfo(NULL, nodeinfo);
778 779
}

780
static int vzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
781 782 783 784 785
{
    /* Encryption is not relevant / applicable to way we talk to PCS */
    return 0;
}

786
static int vzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
787 788 789 790 791
{
    /* We run CLI tools directly so this is secure */
    return 1;
}

792
static int vzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
793 794 795 796
{
    return 1;
}

797

798
static char *
799
vzConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
M
Michal Privoznik 已提交
800 801 802
                     const char **xmlCPUs,
                     unsigned int ncpus,
                     unsigned int flags)
803 804 805 806 807 808 809
{
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);

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


810
static int
811
vzDomainGetVcpus(virDomainPtr domain,
M
Michal Privoznik 已提交
812 813 814 815
                 virVcpuInfoPtr info,
                 int maxinfo,
                 unsigned char *cpumaps,
                 int maplen)
816 817 818 819 820
{
    virDomainObjPtr privdom = NULL;
    size_t i;
    int ret = -1;

N
Nikolay Shirokovskiy 已提交
821
    if (!(privdom = vzDomObjFromDomainRef(domain)))
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
        goto cleanup;

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

    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;
N
Nikolay Shirokovskiy 已提交
837 838
                if (prlsdkGetVcpuStats(privdom, i, &info[i].cpuTime) < 0)
                    goto cleanup;
839 840 841 842
            }
        }
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
843 844 845 846
            for (i = 0; i < maxinfo; i++)
                virBitmapToDataBuf(privdom->def->cpumask,
                                   VIR_GET_CPUMAP(cpumaps, maplen, i),
                                   maplen);
847 848 849 850 851 852
        }
    }
    ret = maxinfo;

 cleanup:
    if (privdom)
N
Nikolay Shirokovskiy 已提交
853
        virDomainObjEndAPI(&privdom);
854 855 856 857
    return ret;
}


858
static int
859
vzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
M
Michal Privoznik 已提交
860 861 862
                unsigned char **cpumap,
                unsigned int *online,
                unsigned int flags)
863
{
864
    return nodeGetCPUMap(NULL, cpumap, online, flags);
865 866
}

867
static int
868
vzConnectDomainEventRegisterAny(virConnectPtr conn,
M
Michal Privoznik 已提交
869 870 871 872 873
                                virDomainPtr domain,
                                int eventID,
                                virConnectDomainEventGenericCallback callback,
                                void *opaque,
                                virFreeCallback freecb)
874 875
{
    int ret = -1;
876
    vzConnPtr privconn = conn->privateData;
877 878 879 880 881 882 883 884 885
    if (virDomainEventStateRegisterID(conn,
                                      privconn->domainEventState,
                                      domain, eventID,
                                      callback, opaque, freecb, &ret) < 0)
        ret = -1;
    return ret;
}

static int
886
vzConnectDomainEventDeregisterAny(virConnectPtr conn,
M
Michal Privoznik 已提交
887
                                  int callbackID)
888
{
889
    vzConnPtr privconn = conn->privateData;
890 891 892 893 894 895 896 897 898 899 900 901
    int ret = -1;

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

    ret = 0;

 cleanup:
    return ret;
}
902

903
static int vzDomainSuspend(virDomainPtr domain)
904 905 906 907
{
    return prlsdkDomainChangeState(domain, prlsdkPause);
}

908
static int vzDomainResume(virDomainPtr domain)
909 910 911 912
{
    return prlsdkDomainChangeState(domain, prlsdkResume);
}

913
static int vzDomainCreate(virDomainPtr domain)
914 915 916 917
{
    return prlsdkDomainChangeState(domain, prlsdkStart);
}

918
static int vzDomainDestroy(virDomainPtr domain)
919 920 921 922
{
    return prlsdkDomainChangeState(domain, prlsdkKill);
}

923
static int vzDomainShutdown(virDomainPtr domain)
924 925 926 927
{
    return prlsdkDomainChangeState(domain, prlsdkStop);
}

928 929 930 931 932 933 934
static int vzDomainReboot(virDomainPtr domain,
                          unsigned int flags)
{
    virCheckFlags(0, -1);
    return prlsdkDomainChangeState(domain, prlsdkRestart);
}

935
static int vzDomainIsActive(virDomainPtr domain)
936 937 938 939
{
    virDomainObjPtr dom = NULL;
    int ret = -1;

940
    if (!(dom = vzDomObjFromDomain(domain)))
941 942 943 944 945 946 947 948
        return -1;

    ret = virDomainObjIsActive(dom);
    virObjectUnlock(dom);

    return ret;
}

949
static int
950
vzDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
951 952 953 954
{
    /* we don't support any create flags */
    virCheckFlags(0, -1);

955
    return vzDomainCreate(domain);
956 957
}

958
static int
959
vzDomainUndefineFlags(virDomainPtr domain,
M
Michal Privoznik 已提交
960
                      unsigned int flags)
961
{
962
    vzConnPtr privconn = domain->conn->privateData;
963
    virDomainObjPtr dom = NULL;
964
    int ret;
965

966 967
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
968

969
    if (!(dom = vzDomObjFromDomain(domain)))
970 971
        return -1;

972
    ret = prlsdkUnregisterDomain(privconn, dom, flags);
973
    if (ret)
M
Michal Privoznik 已提交
974
        virObjectUnlock(dom);
975 976

    return ret;
977 978 979
}

static int
980
vzDomainUndefine(virDomainPtr domain)
981
{
982
    return vzDomainUndefineFlags(domain, 0);
983 984
}

985
static int
986
vzDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
987 988
{
    virDomainObjPtr dom = NULL;
989 990
    int state, reason;
    int ret = 0;
991 992 993

    virCheckFlags(0, -1);

994
    if (!(dom = vzDomObjFromDomain(domain)))
995 996
        return -1;

997 998 999
    state = virDomainObjGetState(dom, &reason);
    if (state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED)
        ret = 1;
1000 1001
    virObjectUnlock(dom);

1002 1003 1004 1005
    return ret;
}

static int
1006
vzDomainManagedSave(virDomainPtr domain, unsigned int flags)
1007
{
1008
    vzConnPtr privconn = domain->conn->privateData;
1009 1010 1011 1012 1013 1014 1015
    virDomainObjPtr dom = NULL;
    int state, reason;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);

1016
    if (!(dom = vzDomObjFromDomain(domain)))
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        return -1;

    state = virDomainObjGetState(dom, &reason);

    if (state == VIR_DOMAIN_RUNNING && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
        ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkPause);
        if (ret)
            goto cleanup;
    }

    ret = prlsdkDomainChangeStateLocked(privconn, dom, prlsdkSuspend);

 cleanup:
    virObjectUnlock(dom);
    return ret;
}

static int
1035
vzDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags)
1036 1037 1038 1039 1040 1041 1042
{
    virDomainObjPtr dom = NULL;
    int state, reason;
    int ret = -1;

    virCheckFlags(0, -1);

1043
    if (!(dom = vzDomObjFromDomain(domain)))
1044 1045 1046 1047 1048 1049 1050
        return -1;

    state = virDomainObjGetState(dom, &reason);

    if (!(state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED))
        goto cleanup;

1051
    ret = prlsdkDomainManagedSaveRemove(dom);
1052 1053 1054 1055

 cleanup:
    virObjectUnlock(dom);
    return ret;
1056 1057
}

1058
static int vzDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
M
Michal Privoznik 已提交
1059
                                     unsigned int flags)
1060 1061
{
    int ret = -1;
1062
    vzConnPtr privconn = dom->conn->privateData;
1063 1064 1065 1066 1067 1068 1069
    virDomainDeviceDefPtr dev = NULL;
    virDomainObjPtr privdom = NULL;
    bool domactive = false;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

1070
    if (!(privdom = vzDomObjFromDomain(dom)))
1071
        return -1;
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099

    if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device attach needs VIR_DOMAIN_AFFECT_CONFIG "
                         "flag to be set"));
        goto cleanup;
    }

    domactive = virDomainObjIsActive(privdom);
    if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do live update a device on "
                         "inactive domain"));
        goto cleanup;
    }
    if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Updates on a running domain need "
                         "VIR_DOMAIN_AFFECT_LIVE flag"));
    }

    dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps,
                                  privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
1100
        ret = prlsdkAttachVolume(privdom, dev->data.disk);
1101 1102 1103 1104 1105 1106
        if (ret) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("disk attach failed"));
            goto cleanup;
        }
        break;
1107 1108 1109 1110 1111 1112 1113 1114
    case VIR_DOMAIN_DEVICE_NET:
        ret = prlsdkAttachNet(privdom, privconn, dev->data.net);
        if (ret) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("network attach failed"));
            goto cleanup;
        }
        break;
1115 1116
    default:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
1117
                       _("device type '%s' cannot be attached"),
1118 1119 1120 1121 1122 1123
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    ret = 0;
 cleanup:
1124
    virObjectUnlock(privdom);
1125 1126 1127
    return ret;
}

1128
static int vzDomainAttachDevice(virDomainPtr dom, const char *xml)
1129
{
1130
    return vzDomainAttachDeviceFlags(dom, xml,
M
Michal Privoznik 已提交
1131
                                     VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE);
1132 1133
}

1134
static int vzDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
M
Michal Privoznik 已提交
1135
                                     unsigned int flags)
1136 1137
{
    int ret = -1;
1138
    vzConnPtr privconn = dom->conn->privateData;
1139 1140 1141 1142 1143 1144 1145
    virDomainDeviceDefPtr dev = NULL;
    virDomainObjPtr privdom = NULL;
    bool domactive = false;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

1146
    privdom = vzDomObjFromDomain(dom);
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
    if (privdom == NULL)
        return -1;

    if (!(flags & VIR_DOMAIN_AFFECT_CONFIG)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device detach needs VIR_DOMAIN_AFFECT_CONFIG "
                         "flag to be set"));
        goto cleanup;
    }

    domactive = virDomainObjIsActive(privdom);
    if (!domactive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do live update a device on "
                         "inactive domain"));
        goto cleanup;
    }
    if (domactive && !(flags & VIR_DOMAIN_AFFECT_LIVE)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Updates on a running domain need "
                         "VIR_DOMAIN_AFFECT_LIVE flag"));
    }

    dev = virDomainDeviceDefParse(xml, privdom->def, privconn->caps,
                                  privconn->xmlopt, VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
1177
        ret = prlsdkDetachVolume(privdom, dev->data.disk);
1178 1179 1180 1181 1182 1183
        if (ret) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("disk detach failed"));
            goto cleanup;
        }
        break;
1184 1185 1186 1187 1188 1189 1190 1191
    case VIR_DOMAIN_DEVICE_NET:
        ret = prlsdkDetachNet(privdom, privconn, dev->data.net);
        if (ret) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("network detach failed"));
            goto cleanup;
        }
        break;
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
    default:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("device type '%s' cannot be detached"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }

    ret = 0;
 cleanup:
    virObjectUnlock(privdom);
    return ret;
}

1205
static int vzDomainDetachDevice(virDomainPtr dom, const char *xml)
1206
{
1207
    return vzDomainDetachDeviceFlags(dom, xml,
M
Michal Privoznik 已提交
1208
                                     VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE);
1209 1210
}

1211
static unsigned long long
1212
vzDomainGetMaxMemory(virDomainPtr domain)
1213 1214 1215 1216
{
    virDomainObjPtr dom = NULL;
    int ret = -1;

1217
    if (!(dom = vzDomObjFromDomain(domain)))
1218 1219
        return -1;

1220
    ret = virDomainDefGetMemoryActual(dom->def);
1221 1222 1223 1224
    virObjectUnlock(dom);
    return ret;
}

1225
static int
1226
vzDomainBlockStats(virDomainPtr domain, const char *path,
M
Michal Privoznik 已提交
1227
                   virDomainBlockStatsPtr stats)
1228 1229 1230 1231 1232 1233
{
    virDomainObjPtr dom = NULL;
    int ret = -1;
    size_t i;
    int idx;

1234
    if (!(dom = vzDomObjFromDomainRef(domain)))
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
        return -1;

    if (*path) {
        if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) {
            virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path);
            goto cleanup;
        }
        if (prlsdkGetBlockStats(dom, dom->def->disks[idx], stats) < 0)
            goto cleanup;
    } else {
        virDomainBlockStatsStruct s;

M
Michal Privoznik 已提交
1247
#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME)      \
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
        stats->VAR = 0;

        PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS)

#undef PARALLELS_ZERO_STATS

        for (i = 0; i < dom->def->ndisks; i++) {
            if (prlsdkGetBlockStats(dom, dom->def->disks[i], &s) < 0)
                goto cleanup;

1258
#define PARALLELS_SUM_STATS(VAR, TYPE, NAME)        \
M
Michal Privoznik 已提交
1259 1260
    if (s.VAR != -1)                                \
        stats->VAR += s.VAR;
1261

M
Michal Privoznik 已提交
1262
        PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_SUM_STATS)
1263

1264
#undef PARALLELS_SUM_STATS
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
        }
    }
    stats->errs = -1;
    ret = 0;

 cleanup:
    if (dom)
        virDomainObjEndAPI(&dom);

    return ret;
}

static int
1278
vzDomainBlockStatsFlags(virDomainPtr domain,
M
Michal Privoznik 已提交
1279 1280 1281 1282
                        const char *path,
                        virTypedParameterPtr params,
                        int *nparams,
                        unsigned int flags)
1283 1284 1285 1286 1287 1288 1289 1290 1291
{
    virDomainBlockStatsStruct stats;
    int ret = -1;
    size_t i;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

1292
    if (vzDomainBlockStats(domain, path, &stats) < 0)
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
        goto cleanup;

    if (*nparams == 0) {
#define PARALLELS_COUNT_STATS(VAR, TYPE, NAME)       \
        if ((stats.VAR) != -1)                       \
            ++*nparams;

        PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_COUNT_STATS)

#undef PARALLELS_COUNT_STATS
        ret = 0;
        goto cleanup;
    }

    i = 0;
#define PARALLELS_BLOCK_STATS_ASSIGN_PARAM(VAR, TYPE, NAME)                    \
    if (i < *nparams && (stats.VAR) != -1) {                                   \
        if (virTypedParameterAssign(params + i, TYPE,                          \
                                    VIR_TYPED_PARAM_LLONG, (stats.VAR)) < 0)   \
            goto cleanup;                                                      \
        i++;                                                                   \
    }

    PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_BLOCK_STATS_ASSIGN_PARAM)

#undef PARALLELS_BLOCK_STATS_ASSIGN_PARAM

    *nparams = i;
    ret = 0;

 cleanup:
    return ret;
}

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
static int
vzDomainInterfaceStats(virDomainPtr domain,
                         const char *path,
                         virDomainInterfaceStatsPtr stats)
{
    virDomainObjPtr dom = NULL;
    int ret;

    if (!(dom = vzDomObjFromDomainRef(domain)))
        return -1;

    ret = prlsdkGetNetStats(dom, path, stats);
    virDomainObjEndAPI(&dom);

    return ret;
}
1343

N
Nikolay Shirokovskiy 已提交
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
static int
vzDomainMemoryStats(virDomainPtr domain,
                    virDomainMemoryStatPtr stats,
                    unsigned int nr_stats,
                    unsigned int flags)
{
    virDomainObjPtr dom = NULL;
    int ret = -1;

    virCheckFlags(0, -1);
    if (!(dom = vzDomObjFromDomainRef(domain)))
        return -1;

    ret = prlsdkGetMemoryStats(dom, stats, nr_stats);
    virDomainObjEndAPI(&dom);

    return ret;
}

1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
static int
vzDomainGetVcpusFlags(virDomainPtr dom,
                      unsigned int flags)
{
    virDomainObjPtr privdom = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    if (!(privdom = vzDomObjFromDomain(dom)))
        goto cleanup;

    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
1378
        ret = virDomainDefGetVcpusMax(privdom->def);
1379
    else
1380
        ret = virDomainDefGetVcpus(privdom->def);
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412

 cleanup:
    if (privdom)
        virObjectUnlock(privdom);

    return ret;
}

static int vzDomainGetMaxVcpus(virDomainPtr dom)
{
    return vzDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                       VIR_DOMAIN_VCPU_MAXIMUM));
}

static int vzDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr privdom;
    int ret = -1;

    /* As far as VZ domains are always updated (e.g. current==persistent),
     * we just check for domain existence */
    if (!(privdom = vzDomObjFromDomain(dom)))
        goto cleanup;

    ret = 0;

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

1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
static int vzConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
                                const char *type)
{
    /* As far as we have no limitation for containers
     * we report maximum */
    if (type == NULL || STRCASEEQ(type, "vz") || STRCASEEQ(type, "parallels"))
        return 1028;

    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
    return -1;
}

1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
static int
vzNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                  int cpuNum,
                  virNodeCPUStatsPtr params,
                  int *nparams,
                  unsigned int flags)
{
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}

static int
vzNodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                     int cellNum,
                     virNodeMemoryStatsPtr params,
                     int *nparams,
                     unsigned int flags)
{
    return nodeGetMemoryStats(NULL, cellNum, params, nparams, flags);
}

static int
vzNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                         unsigned long long *freeMems,
                         int startCell,
                         int maxCells)
{
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}

static unsigned long long
vzNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    unsigned long long freeMem;
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;
    return freeMem;
}

1464 1465
static virHypervisorDriver vzDriver = {
    .name = "vz",
1466 1467 1468 1469
    .connectOpen = vzConnectOpen,            /* 0.10.0 */
    .connectClose = vzConnectClose,          /* 0.10.0 */
    .connectGetVersion = vzConnectGetVersion,   /* 0.10.0 */
    .connectGetHostname = vzConnectGetHostname,      /* 0.10.0 */
1470
    .connectGetMaxVcpus = vzConnectGetMaxVcpus, /* 1.2.21 */
1471
    .nodeGetInfo = vzNodeGetInfo,      /* 0.10.0 */
1472 1473 1474 1475
    .nodeGetCPUStats = vzNodeGetCPUStats,      /* 1.2.21 */
    .nodeGetMemoryStats = vzNodeGetMemoryStats, /* 1.2.21 */
    .nodeGetCellsFreeMemory = vzNodeGetCellsFreeMemory, /* 1.2.21 */
    .nodeGetFreeMemory = vzNodeGetFreeMemory, /* 1.2.21 */
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
    .connectGetCapabilities = vzConnectGetCapabilities,      /* 0.10.0 */
    .connectBaselineCPU = vzConnectBaselineCPU, /* 1.2.6 */
    .connectListDomains = vzConnectListDomains,      /* 0.10.0 */
    .connectNumOfDomains = vzConnectNumOfDomains,    /* 0.10.0 */
    .connectListDefinedDomains = vzConnectListDefinedDomains,        /* 0.10.0 */
    .connectNumOfDefinedDomains = vzConnectNumOfDefinedDomains,      /* 0.10.0 */
    .connectListAllDomains = vzConnectListAllDomains, /* 0.10.0 */
    .domainLookupByID = vzDomainLookupByID,    /* 0.10.0 */
    .domainLookupByUUID = vzDomainLookupByUUID,        /* 0.10.0 */
    .domainLookupByName = vzDomainLookupByName,        /* 0.10.0 */
    .domainGetOSType = vzDomainGetOSType,    /* 0.10.0 */
    .domainGetInfo = vzDomainGetInfo,  /* 0.10.0 */
    .domainGetState = vzDomainGetState,        /* 0.10.0 */
    .domainGetXMLDesc = vzDomainGetXMLDesc,    /* 0.10.0 */
    .domainIsPersistent = vzDomainIsPersistent,        /* 0.10.0 */
    .domainGetAutostart = vzDomainGetAutostart,        /* 0.10.0 */
    .domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
    .domainSuspend = vzDomainSuspend,    /* 0.10.0 */
    .domainResume = vzDomainResume,    /* 0.10.0 */
    .domainDestroy = vzDomainDestroy,  /* 0.10.0 */
    .domainShutdown = vzDomainShutdown, /* 0.10.0 */
    .domainCreate = vzDomainCreate,    /* 0.10.0 */
    .domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
P
Pavel Hrdina 已提交
1499
    .domainReboot = vzDomainReboot, /* 1.3.0 */
1500 1501 1502 1503 1504 1505 1506 1507 1508
    .domainDefineXML = vzDomainDefineXML,      /* 0.10.0 */
    .domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */
    .domainUndefine = vzDomainUndefine, /* 1.2.10 */
    .domainUndefineFlags = vzDomainUndefineFlags, /* 1.2.10 */
    .domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
    .domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
    .domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
    .domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
    .domainIsActive = vzDomainIsActive, /* 1.2.10 */
1509 1510 1511
    .domainIsUpdated = vzDomainIsUpdated,     /* 1.2.21 */
    .domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
    .domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
    .connectDomainEventRegisterAny = vzConnectDomainEventRegisterAny, /* 1.2.10 */
    .connectDomainEventDeregisterAny = vzConnectDomainEventDeregisterAny, /* 1.2.10 */
    .nodeGetCPUMap = vzNodeGetCPUMap, /* 1.2.8 */
    .connectIsEncrypted = vzConnectIsEncrypted, /* 1.2.5 */
    .connectIsSecure = vzConnectIsSecure, /* 1.2.5 */
    .connectIsAlive = vzConnectIsAlive, /* 1.2.5 */
    .domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
    .domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
    .domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
    .domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
1522 1523 1524 1525
    .domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
    .domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
    .domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */
    .domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
D
Dmitry Guryanov 已提交
1526 1527
};

1528 1529
static virConnectDriver vzConnectDriver = {
    .hypervisorDriver = &vzDriver,
1530 1531
};

1532 1533 1534 1535
/* Parallels domain type backward compatibility*/
static virHypervisorDriver parallelsDriver;
static virConnectDriver parallelsConnectDriver;

D
Dmitry Guryanov 已提交
1536
/**
1537
 * vzRegister:
D
Dmitry Guryanov 已提交
1538
 *
1539
 * Registers the vz driver
D
Dmitry Guryanov 已提交
1540 1541
 */
int
1542
vzRegister(void)
D
Dmitry Guryanov 已提交
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
{
    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);

1554 1555 1556 1557 1558
    /* Backward compatibility with Parallels domain type */
    parallelsDriver = vzDriver;
    parallelsDriver.name = "Parallels";
    parallelsConnectDriver = vzConnectDriver;
    parallelsConnectDriver.hypervisorDriver = &parallelsDriver;
1559
    if (virRegisterConnectDriver(&parallelsConnectDriver, false) < 0)
D
Dmitry Guryanov 已提交
1560
        return -1;
D
Dmitry Guryanov 已提交
1561

1562 1563 1564
    if (virRegisterConnectDriver(&vzConnectDriver, false) < 0)
        return -1;

D
Dmitry Guryanov 已提交
1565 1566
    return 0;
}