openvz_driver.c 72.2 KB
Newer Older
1 2 3
/*
 * openvz_driver.c: core driver methods for managing OpenVZ VEs
 *
4
 * Copyright (C) 2010-2016 Red Hat, Inc.
5 6
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
7
 * Copyright (C) 2007 Anoop Joe Cyriac
8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * License along with this library.  If not, see
O
Osier Yang 已提交
21
 * <http://www.gnu.org/licenses/>.
22
 *
23
 * Authors:
24 25 26
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 */

#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 <pwd.h>
#include <sys/wait.h>

45
#include "virerror.h"
46
#include "datatypes.h"
47
#include "openvz_driver.h"
48
#include "openvz_util.h"
49
#include "virbuffer.h"
50
#include "openvz_conf.h"
51
#include "virhostcpu.h"
52
#include "virhostmem.h"
53
#include "viralloc.h"
E
Eric Blake 已提交
54
#include "virfile.h"
55
#include "virtypedparam.h"
56
#include "virlog.h"
57
#include "vircommand.h"
M
Martin Kletzander 已提交
58
#include "viruri.h"
59
#include "virnetdevtap.h"
60
#include "virstring.h"
61

62 63
#define VIR_FROM_THIS VIR_FROM_OPENVZ

64 65
VIR_LOG_INIT("openvz.openvz_driver");

66 67
#define OPENVZ_NB_MEM_PARAM 3

D
Daniel Veillard 已提交
68
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
69
static int openvzConnectGetMaxVcpus(virConnectPtr conn, const char *type);
70
static int openvzDomainGetMaxVcpus(virDomainPtr dom);
71
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
72 73
                                        unsigned int nvcpus,
                                        virDomainXMLOptionPtr xmlopt);
74
static int openvzDomainSetMemoryInternal(virDomainObjPtr vm,
75
                                         unsigned long long memory);
76
static int openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason);
D
Daniel Veillard 已提交
77

78 79
static void openvzDriverLock(struct openvz_driver *driver)
{
80
    virMutexLock(&driver->lock);
81 82 83 84
}

static void openvzDriverUnlock(struct openvz_driver *driver)
{
85
    virMutexUnlock(&driver->lock);
86 87
}

88 89
struct openvz_driver ovz_driver;

90 91 92 93 94 95 96 97

static virDomainObjPtr
openvzDomObjFromDomainLocked(struct openvz_driver *driver,
                             const unsigned char *uuid)
{
    virDomainObjPtr vm;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

98
    if (!(vm = virDomainObjListFindByUUID(driver->domains, uuid))) {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        virUUIDFormat(uuid, uuidstr);

        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        return NULL;
    }

    return vm;
}


static virDomainObjPtr
openvzDomObjFromDomain(struct openvz_driver *driver,
                       const unsigned char *uuid)
{
    virDomainObjPtr vm;

    openvzDriverLock(driver);
    vm = openvzDomObjFromDomainLocked(driver, uuid);
    openvzDriverUnlock(driver);
    return vm;
}


123 124 125
static int
openvzDomainDefPostParse(virDomainDefPtr def,
                         virCapsPtr caps ATTRIBUTE_UNUSED,
126
                         unsigned int parseFlags ATTRIBUTE_UNUSED,
127 128
                         void *opaque ATTRIBUTE_UNUSED,
                         void *parseOpaque ATTRIBUTE_UNUSED)
129 130
{
    /* fill the init path */
131
    if (def->os.type == VIR_DOMAIN_OSTYPE_EXE && !def->os.init) {
132 133 134 135
        if (VIR_STRDUP(def->os.init, "/sbin/init") < 0)
            return -1;
    }

136 137 138 139
    return 0;
}


140 141
static int
openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
142
                               const virDomainDef *def ATTRIBUTE_UNUSED,
143
                               virCapsPtr caps ATTRIBUTE_UNUSED,
144
                               unsigned int parseFlags ATTRIBUTE_UNUSED,
145 146
                               void *opaque ATTRIBUTE_UNUSED,
                               void *parseOpaque ATTRIBUTE_UNUSED)
147 148 149 150 151 152
{
    if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
        dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
        dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;

153 154 155 156 157 158 159 160 161 162
    /* forbid capabilities mode hostdev in this kind of hypervisor */
    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
        dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode 'capabilities' is not "
                         "supported in %s"),
                       virDomainVirtTypeToString(def->virtType));
        return -1;
    }

163 164 165 166
    return 0;
}


167
virDomainDefParserConfig openvzDomainDefParserConfig = {
168 169 170
    .domainPostParseCallback = openvzDomainDefPostParse,
    .devicesPostParseCallback = openvzDomainDeviceDefPostParse,
    .features = VIR_DOMAIN_DEF_FEATURE_NAME_SLASH,
171 172 173
};


174 175 176
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
177
   Caller has to free the cmd
178
*/
179 180
static virCommandPtr
openvzDomainDefineCmd(virDomainDefPtr vmdef)
181
{
182 183 184 185
    virCommandPtr cmd = virCommandNewArgList(VZCTL,
                                             "--quiet",
                                             "create",
                                             NULL);
186

187
    if (vmdef == NULL) {
188 189
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Container is not defined"));
190 191
        virCommandFree(cmd);
        return NULL;
192
    }
193

194
    virCommandAddArgList(cmd, vmdef->name, "--name", vmdef->name, NULL);
195

196
    if (vmdef->nfss == 1 &&
197
        vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
198
        virCommandAddArgList(cmd, "--ostemplate", vmdef->fss[0]->src, NULL);
199
    }
200

201
    return cmd;
202 203 204
}


205
static int openvzSetInitialConfig(virDomainDefPtr vmdef)
206 207 208 209
{
    int ret = -1;
    int vpsid;
    char * confdir = NULL;
210
    virCommandPtr cmd = NULL;
211 212

    if (vmdef->nfss > 1) {
213 214
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only one filesystem supported"));
215 216 217 218 219 220 221
        goto cleanup;
    }

    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
    {
222 223
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("filesystem is not of type 'template' or 'mount'"));
224 225 226 227 228 229 230 231
        goto cleanup;
    }


    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_MOUNT)
    {

E
Eric Blake 已提交
232
        if (virStrToLong_i(vmdef->name, NULL, 10, &vpsid) < 0) {
233 234
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not convert domain name to VEID"));
235 236 237 238
            goto cleanup;
        }

        if (openvzCopyDefaultConfig(vpsid) < 0) {
239 240
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not copy default config"));
241 242 243
            goto cleanup;
        }

244
        if (openvzWriteVPSConfigParam(vpsid, "VE_PRIVATE", vmdef->fss[0]->src->path) < 0) {
245 246
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set the source dir for the filesystem"));
247 248
            goto cleanup;
        }
249 250 251
    } else {
        cmd = openvzDomainDefineCmd(vmdef);
        if (virCommandRun(cmd, NULL) < 0)
252 253 254 255 256
            goto cleanup;
    }

    ret = 0;

257
 cleanup:
J
John Ferlan 已提交
258 259
    VIR_FREE(confdir);
    virCommandFree(cmd);
260

J
John Ferlan 已提交
261
    return ret;
262 263 264
}


265 266
static int
openvzSetDiskQuota(virDomainDefPtr vmdef,
267 268
                   virDomainFSDefPtr fss,
                   bool persist)
269 270 271 272 273 274 275 276
{
    int ret = -1;
    unsigned long long sl, hl;
    virCommandPtr cmd = virCommandNewArgList(VZCTL,
                                             "--quiet",
                                             "set",
                                             vmdef->name,
                                             NULL);
277 278
    if (persist)
        virCommandAddArg(cmd, "--save");
279 280 281 282 283 284 285 286 287 288 289 290 291

    if (fss->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
        if (fss->space_hard_limit) {
            hl = VIR_DIV_UP(fss->space_hard_limit, 1024);
            virCommandAddArg(cmd, "--diskspace");

            if (fss->space_soft_limit) {
                sl = VIR_DIV_UP(fss->space_soft_limit, 1024);
                virCommandAddArgFormat(cmd, "%lld:%lld", sl, hl);
            } else {
                virCommandAddArgFormat(cmd, "%lld", hl);
            }
        } else if (fss->space_soft_limit) {
292 293
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Can't set soft limit without hard limit"));
294 295 296 297 298 299 300 301
            goto cleanup;
        }

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }

    ret = 0;
302
 cleanup:
J
John Ferlan 已提交
303
    virCommandFree(cmd);
304

J
John Ferlan 已提交
305
    return ret;
306 307 308
}


309 310 311 312 313 314 315 316
static char *
openvzDomainGetHostname(virDomainPtr dom, unsigned int flags)
{
    char *hostname = NULL;
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;

    virCheckFlags(0, NULL);
317 318
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return NULL;
319 320 321

    hostname = openvzVEGetStringParam(dom, "hostname");
    if (hostname == NULL)
322
        goto cleanup;
323 324 325 326 327

    /* vzlist prints an unset hostname as '-' */
    if (STREQ(hostname, "-")) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Hostname of '%s' is unset"), vm->def->name);
328
        VIR_FREE(hostname);
329 330
    }

331
 cleanup:
332
    virDomainObjEndAPI(&vm);
333 334 335 336
    return hostname;
}


337
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
338 339
                                           int id)
{
340
    struct openvz_driver *driver = conn->privateData;
341
    virDomainObjPtr vm;
342
    virDomainPtr dom = NULL;
343

344
    openvzDriverLock(driver);
345
    vm = virDomainObjListFindByIDRef(driver->domains, id);
346 347
    openvzDriverUnlock(driver);

348
    if (!vm) {
349 350
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id '%d'"), id);
351
        goto cleanup;
352 353
    }

354
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
355

356
 cleanup:
357
    virDomainObjEndAPI(&vm);
358 359 360
    return dom;
}

361 362
static int openvzConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
363
    struct  openvz_driver *driver = conn->privateData;
364
    openvzDriverLock(driver);
365
    *version = driver->version;
366
    openvzDriverUnlock(driver);
367 368 369
    return 0;
}

370 371 372 373 374 375 376

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


377
static char *openvzDomainGetOSType(virDomainPtr dom)
378
{
379 380 381
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
382

383 384
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return NULL;
385

386
    ignore_value(VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)));
387

388
    virDomainObjEndAPI(&vm);
389
    return ret;
390 391 392 393
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
394 395
                                             const unsigned char *uuid)
{
396 397 398
    struct  openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
399

400 401
    if (!(vm = openvzDomObjFromDomain(driver, uuid)))
        return NULL;
402

403
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
404

405
    virDomainObjEndAPI(&vm);
406 407 408 409
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
410 411
                                             const char *name)
{
412 413 414
    struct openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
415

416
    openvzDriverLock(driver);
417
    vm = virDomainObjListFindByName(driver->domains, name);
418 419
    openvzDriverUnlock(driver);

420
    if (!vm) {
421 422
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
423
        goto cleanup;
424 425
    }

426
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
427

428
 cleanup:
429
    virDomainObjEndAPI(&vm);
430 431 432 433
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
434 435
                               virDomainInfoPtr info)
{
436 437
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
438
    int state;
439
    int ret = -1;
440

441 442
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
443

444 445 446
    if (openvzGetVEStatus(vm, &state, NULL) == -1)
        goto cleanup;
    info->state = state;
447

448
    if (info->state != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
449 450 451
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
452 453
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("cannot read cputime for domain %d"), dom->id);
454
            goto cleanup;
D
Daniel Veillard 已提交
455 456 457
        }
    }

458
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
459
    info->memory = vm->def->mem.cur_balloon;
460
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
461 462
    ret = 0;

463
 cleanup:
464
    virDomainObjEndAPI(&vm);
465
    return ret;
466 467 468
}


469 470 471 472 473 474 475 476 477 478 479 480
static int
openvzDomainGetState(virDomainPtr dom,
                     int *state,
                     int *reason,
                     unsigned int flags)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

481 482
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
483

484
    ret = openvzGetVEStatus(vm, state, reason);
485

486
    virDomainObjEndAPI(&vm);
487 488 489 490
    return ret;
}


491 492 493 494 495 496
static int openvzDomainIsActive(virDomainPtr dom)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

497 498 499
    if (!(obj = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;

500 501
    ret = virDomainObjIsActive(obj);

502
    virDomainObjEndAPI(&obj);
503 504 505 506 507 508 509 510 511 512
    return ret;
}


static int openvzDomainIsPersistent(virDomainPtr dom)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

513 514 515
    if (!(obj = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;

516 517
    ret = obj->persistent;

518
    virDomainObjEndAPI(&obj);
519 520 521
    return ret;
}

522 523 524 525
static int openvzDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
    return 0;
}
526

527
static char *openvzDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
528 529 530
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
531

532 533
    /* Flags checked by virDomainDefFormat */

534 535
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return NULL;
536

537
    ret = virDomainDefFormat(vm->def, driver->caps,
538
                             virDomainDefFormatConvertXMLFlags(flags));
539

540
    virDomainObjEndAPI(&vm);
541
    return ret;
542
}
543

544

545 546 547 548 549 550
/*
 * Convenient helper to target a command line argv
 * and fill in an empty slot with the supplied
 * key value. This lets us declare the argv on the
 * stack and just splice in the domain name after
 */
E
Eric Blake 已提交
551
#define PROGRAM_SENTINEL ((char *)0x1)
552 553 554 555
static void openvzSetProgramSentinal(const char **prog, const char *key)
{
    const char **tmp = prog;
    while (tmp && *tmp) {
E
Eric Blake 已提交
556
        if (*tmp == PROGRAM_SENTINEL) {
557 558 559 560 561 562
            *tmp = key;
            break;
        }
        tmp++;
    }
}
563

564 565
static int openvzDomainSuspend(virDomainPtr dom)
{
566 567
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
568
    const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--suspend", NULL};
569 570
    int ret = -1;

571 572
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
573

574
    if (virDomainObjCheckActive(vm) < 0)
575 576
        goto cleanup;

J
Jiri Denemark 已提交
577
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
578
        openvzSetProgramSentinal(prog, vm->def->name);
579
        if (virRun(prog, NULL) < 0)
580
            goto cleanup;
J
Jiri Denemark 已提交
581
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
582 583 584 585
    }

    ret = 0;

586
 cleanup:
587
    virDomainObjEndAPI(&vm);
588 589 590
    return ret;
}

591 592
static int openvzDomainResume(virDomainPtr dom)
{
J
John Ferlan 已提交
593 594 595 596 597
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--resume", NULL};
    int ret = -1;

598 599
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
J
John Ferlan 已提交
600

601
    if (virDomainObjCheckActive(vm) < 0)
J
John Ferlan 已提交
602 603 604 605 606 607 608 609 610 611
        goto cleanup;

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
        openvzSetProgramSentinal(prog, vm->def->name);
        if (virRun(prog, NULL) < 0)
            goto cleanup;
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
    }

    ret = 0;
612

613
 cleanup:
614
    virDomainObjEndAPI(&vm);
J
John Ferlan 已提交
615
    return ret;
616 617
}

618 619
static int
openvzDomainShutdownFlags(virDomainPtr dom,
620 621
                          unsigned int flags)
{
622 623
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
624
    const char *prog[] = {VZCTL, "--quiet", "stop", PROGRAM_SENTINEL, NULL};
625
    int ret = -1;
626
    int status;
627

628 629
    virCheckFlags(0, -1);

630 631
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
632

633 634 635
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

636
    openvzSetProgramSentinal(prog, vm->def->name);
637
    if (status != VIR_DOMAIN_RUNNING) {
638 639
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
640
        goto cleanup;
641
    }
642

643
    if (virRun(prog, NULL) < 0)
644
        goto cleanup;
645

646
    vm->def->id = -1;
J
Jiri Denemark 已提交
647
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
648
    dom->id = -1;
649
    ret = 0;
650

651
 cleanup:
652
    virDomainObjEndAPI(&vm);
653
    return ret;
654 655
}

656 657 658 659 660 661
static int
openvzDomainShutdown(virDomainPtr dom)
{
    return openvzDomainShutdownFlags(dom, 0);
}

662 663 664 665 666 667 668 669 670 671 672 673
static int
openvzDomainDestroy(virDomainPtr dom)
{
    return openvzDomainShutdownFlags(dom, 0);
}

static int
openvzDomainDestroyFlags(virDomainPtr dom, unsigned int flags)
{
    return openvzDomainShutdownFlags(dom, flags);
}

674
static int openvzDomainReboot(virDomainPtr dom,
E
Eric Blake 已提交
675 676
                              unsigned int flags)
{
677 678
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
679
    const char *prog[] = {VZCTL, "--quiet", "restart", PROGRAM_SENTINEL, NULL};
680
    int ret = -1;
681
    int status;
682

E
Eric Blake 已提交
683 684
    virCheckFlags(0, -1);

685 686
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
687

688 689 690
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

691
    openvzSetProgramSentinal(prog, vm->def->name);
692
    if (status != VIR_DOMAIN_RUNNING) {
693 694
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
695
        goto cleanup;
696
    }
697

698
    if (virRun(prog, NULL) < 0)
699 700
        goto cleanup;
    ret = 0;
701

J
Jiri Denemark 已提交
702 703
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);

704
 cleanup:
705
    virDomainObjEndAPI(&vm);
706
    return ret;
707 708
}

709 710 711 712
static char *
openvzGenerateVethName(int veid, char *dev_name_ve)
{
    int     ifNo = 0;
713
    char    *ret;
714 715 716

    if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
        return NULL;
717
    ignore_value(virAsprintf(&ret, "veth%d.%d.", veid, ifNo));
718
    return ret;
719 720 721 722 723
}

static char *
openvzGenerateContainerVethName(int veid)
{
724 725
    char *temp = NULL;
    char *name = NULL;
726 727

    /* try to get line "^NETIF=..." from config */
728
    if (openvzReadVPSConfigParam(veid, "NETIF", &temp) <= 0) {
729
        ignore_value(VIR_STRDUP(name, "eth0"));
730
    } else {
731
        char *saveptr = NULL;
732 733
        char *s;
        int max = 0;
734 735

        /* get maximum interface number (actually, it is the last one) */
736
        for (s = strtok_r(temp, ";", &saveptr); s; s = strtok_r(NULL, ";", &saveptr)) {
737 738 739 740 741 742 743
            int x;

            if (sscanf(s, "ifname=eth%d", &x) != 1) return NULL;
            if (x > max) max = x;
        }

        /* set new name */
744
        ignore_value(virAsprintf(&name, "eth%d", max + 1));
745
    }
746 747 748 749

    VIR_FREE(temp);

    return name;
750 751
}

D
Daniel Veillard 已提交
752 753
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
754 755
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
756
{
757
    int rc = -1;
758
    char macaddr[VIR_MAC_STRING_BUFLEN];
759
    virMacAddr host_mac;
760
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
761
    struct openvz_driver *driver =  conn->privateData;
762
    virCommandPtr cmd = NULL;
763
    char *guest_ifname = NULL;
D
Daniel Veillard 已提交
764 765

    if (net == NULL)
J
John Ferlan 已提交
766 767
        return 0;

D
Daniel Veillard 已提交
768
    if (vpsid == NULL) {
769 770
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Container ID is not specified"));
D
Daniel Veillard 已提交
771 772 773
        return -1;
    }

774 775 776
    if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
        net->type != VIR_DOMAIN_NET_TYPE_ETHERNET)
        return 0;
D
Daniel Veillard 已提交
777

778
    cmd = virCommandNewArgList(VZCTL, "--quiet", "set", vpsid, NULL);
D
Daniel Veillard 已提交
779

780
    virMacAddrFormat(&net->mac, macaddr);
781
    virDomainNetGenerateMAC(driver->xmlopt, &host_mac);
782
    virMacAddrFormat(&host_mac, host_macaddr);
783

784 785
    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
786
         net->guestIP.nips == 0)) {
787
        virBuffer buf = VIR_BUFFER_INITIALIZER;
788
        int veid = openvzGetVEID(vpsid);
D
Daniel Veillard 已提交
789

790 791
        /* if net is ethernet and the user has specified guest interface name,
         * let's use it; otherwise generate a new one */
792 793
        if (net->ifname_guest) {
            if (VIR_STRDUP(guest_ifname, net->ifname_guest) < 0)
794 795 796 797
                goto cleanup;
        } else {
            guest_ifname = openvzGenerateContainerVethName(veid);
            if (guest_ifname == NULL) {
J
John Ferlan 已提交
798 799 800
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Could not generate eth name for container"));
                goto cleanup;
801
            }
802 803 804 805 806
        }

        /* if user doesn't specified host interface name,
         * than we need to generate it */
        if (net->ifname == NULL) {
807
            net->ifname = openvzGenerateVethName(veid, guest_ifname);
808
            if (net->ifname == NULL) {
J
John Ferlan 已提交
809 810 811
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Could not generate veth name"));
                goto cleanup;
812 813 814
            }
        }

815
        virBufferAdd(&buf, guest_ifname, -1); /* Guest dev */
816 817 818
        virBufferAsprintf(&buf, ",%s", macaddr); /* Guest dev mac */
        virBufferAsprintf(&buf, ",%s", net->ifname); /* Host dev */
        virBufferAsprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
819

820 821
        if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
822
                virBufferAsprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
823
            } else {
824
                virBufferAsprintf(configBuf, "ifname=%s", guest_ifname);
825 826 827 828
                virBufferAsprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
                virBufferAsprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
                virBufferAsprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
                virBufferAsprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
829
            }
D
Daniel Veillard 已提交
830
        }
831

832 833 834
        /* --netif_add ifname[,mac,host_ifname,host_mac] */
        virCommandAddArg(cmd, "--netif_add");
        virCommandAddArgBuffer(cmd, &buf);
835
    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
J
John Ferlan 已提交
836
               net->guestIP.nips > 0) {
837 838
        size_t i;

839
        /* --ipadd ip */
840 841
        for (i = 0; i < net->guestIP.nips; i++) {
            char *ipStr = virSocketAddrFormat(&net->guestIP.ips[i]->address);
842 843
            if (!ipStr)
                goto cleanup;
844
            virCommandAddArgList(cmd, "--ipadd", ipStr, NULL);
845
            VIR_FREE(ipStr);
846
        }
D
Daniel Veillard 已提交
847 848
    }

849
    /* TODO: processing NAT and physical device */
D
Daniel Veillard 已提交
850

851 852
    virCommandAddArg(cmd, "--save");
    rc = virCommandRun(cmd, NULL);
D
Daniel Veillard 已提交
853

854 855
 cleanup:
    virCommandFree(cmd);
856
    VIR_FREE(guest_ifname);
D
Daniel Veillard 已提交
857 858 859
    return rc;
}

860 861 862 863 864

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
865
    size_t i;
866 867 868
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
869
    struct openvz_driver *driver =  conn->privateData;
870

871
    for (i = 0; i < def->nnets; i++) {
872 873 874 875 876 877 878 879 880
        if (driver->version < VZCTL_BRIDGE_MIN_VERSION &&
            def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            if (first)
                first = 0;
            else
                virBufferAddLit(&buf, ";");
        }

        if (openvzDomainSetNetwork(conn, def->name, def->nets[i], &buf) < 0) {
881 882
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not configure network"));
883 884 885 886 887 888 889
            goto exit;
        }
    }

    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
        param = virBufferContentAndReset(&buf);
        if (param) {
890
            if (openvzWriteVPSConfigParam(strtoI(def->name), "NETIF", param) < 0) {
891
                VIR_FREE(param);
892 893
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot replace NETIF config"));
894 895 896 897 898 899 900 901
                return -1;
            }
            VIR_FREE(param);
        }
    }

    return 0;

902
 exit:
903
    virBufferFreeAndReset(&buf);
904 905 906 907
    return -1;
}


908
static virDomainPtr
909
openvzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
910
{
911
    struct openvz_driver *driver =  conn->privateData;
912 913
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
914
    virDomainPtr dom = NULL;
915
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
916

917 918 919
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
920
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
921

922
    openvzDriverLock(driver);
923
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
924
                                         NULL, parse_flags)) == NULL)
925
        goto cleanup;
926

927 928 929
    if (virXMLCheckIllegalChars("name", vmdef->name, "\n") < 0)
        goto cleanup;

930
    if (!(vm = virDomainObjListAdd(driver->domains, vmdef,
931
                                   driver->xmlopt,
932
                                   0, NULL)))
933 934
        goto cleanup;
    vmdef = NULL;
935
    vm->persistent = 1;
936

937
    if (openvzSetInitialConfig(vm->def) < 0) {
938
        VIR_ERROR(_("Error creating initial configuration"));
939
        goto cleanup;
940 941
    }

942
    if (vm->def->nfss == 1) {
943
        if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
944 945
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set disk quota"));
946 947 948
            goto cleanup;
        }
    }
D
Daniel Veillard 已提交
949

950
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
951 952
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set UUID"));
953
        goto cleanup;
954 955
    }

956 957
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
958

959
    if (virDomainDefHasVcpusOffline(vm->def)) {
960 961
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
962 963
        goto cleanup;
    }
964
    if (virDomainDefGetVcpusMax(vm->def)) {
965 966
        if (openvzDomainSetVcpusInternal(vm, virDomainDefGetVcpusMax(vm->def),
                                         driver->xmlopt) < 0) {
967
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
968
                           _("Could not set number of vCPUs"));
J
John Ferlan 已提交
969
            goto cleanup;
970 971 972
        }
    }

973 974
    if (vm->def->mem.cur_balloon > 0) {
        if (openvzDomainSetMemoryInternal(vm, vm->def->mem.cur_balloon) < 0) {
975 976
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set memory size"));
J
John Ferlan 已提交
977
            goto cleanup;
978 979 980
        }
    }

981
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, -1);
982

983
 cleanup:
984
    virDomainDefFree(vmdef);
985
    if (vm)
986
        virObjectUnlock(vm);
987
    openvzDriverUnlock(driver);
988 989 990
    return dom;
}

991 992 993 994 995 996
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return openvzDomainDefineXMLFlags(conn, xml, 0);
}

997
static virDomainPtr
998
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
999
                      unsigned int flags)
1000
{
1001
    struct openvz_driver *driver =  conn->privateData;
1002 1003
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
1004
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
1005
    const char *progstart[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL};
1006
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
1007

1008 1009 1010
    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1011
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1012

1013
    openvzDriverLock(driver);
1014
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1015
                                         NULL, parse_flags)) == NULL)
1016
        goto cleanup;
1017

1018
    if (!(vm = virDomainObjListAdd(driver->domains,
1019
                                   vmdef,
1020
                                   driver->xmlopt,
1021
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1022 1023
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1024 1025
        goto cleanup;
    vmdef = NULL;
1026 1027 1028
    /* All OpenVZ domains seem to be persistent - this is a bit of a violation
     * of this libvirt API which is intended for transient domain creation */
    vm->persistent = 1;
1029

1030
    if (openvzSetInitialConfig(vm->def) < 0) {
1031
        VIR_ERROR(_("Error creating initial configuration"));
1032
        goto cleanup;
1033
    }
1034

1035
    if (vm->def->nfss == 1) {
1036
        if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
1037 1038
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set disk quota"));
1039 1040 1041 1042
            goto cleanup;
        }
    }

1043
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
1044 1045
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set UUID"));
1046
        goto cleanup;
1047 1048
    }

1049 1050
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1051

1052
    openvzSetProgramSentinal(progstart, vm->def->name);
1053

1054
    if (virRun(progstart, NULL) < 0)
1055
        goto cleanup;
1056

1057
    vm->pid = strtoI(vm->def->name);
1058
    vm->def->id = vm->pid;
J
Jiri Denemark 已提交
1059
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1060

1061
    if (virDomainDefGetVcpusMax(vm->def) > 0) {
1062 1063
        if (openvzDomainSetVcpusInternal(vm, virDomainDefGetVcpusMax(vm->def),
                                         driver->xmlopt) < 0) {
1064
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1065
                           _("Could not set number of vCPUs"));
1066
            goto cleanup;
1067 1068 1069
        }
    }

1070
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1071

1072
 cleanup:
1073
    virDomainDefFree(vmdef);
1074
    if (vm)
1075
        virObjectUnlock(vm);
1076
    openvzDriverUnlock(driver);
1077 1078 1079 1080
    return dom;
}

static int
1081
openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
1082
{
1083 1084
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1085
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL };
1086
    int ret = -1;
1087
    int status;
1088

1089 1090
    virCheckFlags(0, -1);

1091
    openvzDriverLock(driver);
1092
    vm = virDomainObjListFindByName(driver->domains, dom->name);
1093 1094
    openvzDriverUnlock(driver);

1095
    if (!vm) {
1096 1097
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dom->name);
1098
        goto cleanup;
1099
    }
1100

1101 1102 1103 1104
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

    if (status != VIR_DOMAIN_SHUTOFF) {
1105 1106
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("domain is not in shutoff state"));
1107
        goto cleanup;
1108 1109
    }

1110
    openvzSetProgramSentinal(prog, vm->def->name);
1111
    if (virRun(prog, NULL) < 0)
1112
        goto cleanup;
1113

1114 1115
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
1116
    dom->id = vm->pid;
J
Jiri Denemark 已提交
1117
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1118
    ret = 0;
1119

1120
 cleanup:
1121
    virDomainObjEndAPI(&vm);
1122
    return ret;
1123 1124
}

1125 1126 1127 1128 1129 1130
static int
openvzDomainCreate(virDomainPtr dom)
{
    return openvzDomainCreateWithFlags(dom, 0);
}

1131
static int
1132 1133
openvzDomainUndefineFlags(virDomainPtr dom,
                          unsigned int flags)
1134
{
1135 1136
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1137
    const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINEL, NULL };
1138
    int ret = -1;
1139
    int status;
1140

1141 1142
    virCheckFlags(0, -1);

1143
    openvzDriverLock(driver);
1144
    if (!(vm = openvzDomObjFromDomainLocked(driver, dom->uuid)))
1145
        goto cleanup;
1146

1147 1148 1149
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

1150
    openvzSetProgramSentinal(prog, vm->def->name);
1151
    if (virRun(prog, NULL) < 0)
1152
        goto cleanup;
1153

1154 1155 1156
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
1157
        virDomainObjListRemove(driver->domains, vm);
1158
        virObjectLock(vm);
1159 1160
    }

1161
    ret = 0;
1162

1163
 cleanup:
1164
    virDomainObjEndAPI(&vm);
1165
    openvzDriverUnlock(driver);
1166
    return ret;
1167 1168
}

1169 1170 1171 1172 1173
static int
openvzDomainUndefine(virDomainPtr dom)
{
    return openvzDomainUndefineFlags(dom, 0);
}
1174 1175 1176
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
1177 1178
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1179
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
D
Daniel Veillard 已提交
1180
                           "--onboot", autostart ? "yes" : "no",
1181
                           "--save", NULL };
1182
    int ret = -1;
1183

1184 1185
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
1186

1187
    openvzSetProgramSentinal(prog, vm->def->name);
1188
    if (virRun(prog, NULL) < 0)
1189 1190
        goto cleanup;
    ret = 0;
1191

1192
 cleanup:
1193
    virDomainObjEndAPI(&vm);
1194
    return ret;
1195 1196 1197 1198 1199
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
1200 1201
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1202
    char *value = NULL;
1203
    int ret = -1;
1204

1205 1206
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
1207

1208
    if (openvzReadVPSConfigParam(strtoI(vm->def->name), "ONBOOT", &value) < 0) {
1209 1210
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not read container config"));
1211
        goto cleanup;
1212 1213 1214
    }

    *autostart = 0;
1215
    if (STREQ(value, "yes"))
D
Daniel Veillard 已提交
1216
        *autostart = 1;
1217
    ret = 0;
1218

1219
 cleanup:
1220 1221
    VIR_FREE(value);

1222
    virDomainObjEndAPI(&vm);
1223
    return ret;
1224 1225
}

1226 1227
static int openvzConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
                                    const char *type)
1228 1229 1230
{
    if (type == NULL || STRCASEEQ(type, "openvz"))
        return 1028; /* OpenVZ has no limitation */
1231

1232 1233
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1234 1235 1236
    return -1;
}

1237 1238 1239 1240
static int
openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED,
                          unsigned int flags)
{
1241
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1242 1243
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported flags (0x%x)"), flags);
1244 1245
        return -1;
    }
1246

1247
    return openvzConnectGetMaxVcpus(NULL, "openvz");
1248 1249
}

1250 1251
static int openvzDomainGetMaxVcpus(virDomainPtr dom)
{
1252
    return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
1253 1254 1255
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}

1256
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
1257 1258
                                        unsigned int nvcpus,
                                        virDomainXMLOptionPtr xmlopt)
1259 1260
{
    char        str_vcpus[32];
E
Eric Blake 已提交
1261
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
1262
                           "--cpus", str_vcpus, "--save", NULL };
1263
    unsigned int pcpus;
1264
    pcpus = virHostCPUGetCount();
1265 1266 1267
    if (pcpus > 0 && pcpus < nvcpus)
        nvcpus = pcpus;

J
Ján Tomko 已提交
1268
    snprintf(str_vcpus, sizeof(str_vcpus), "%d", nvcpus);
1269 1270

    openvzSetProgramSentinal(prog, vm->def->name);
1271
    if (virRun(prog, NULL) < 0)
1272 1273
        return -1;

1274
    if (virDomainDefSetVcpusMax(vm->def, nvcpus, xmlopt) < 0)
1275 1276
        return -1;

1277 1278 1279
    if (virDomainDefSetVcpus(vm->def, nvcpus) < 0)
        return -1;

1280 1281 1282
    return 0;
}

1283 1284
static int openvzDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                                     unsigned int flags)
1285 1286 1287 1288
{
    virDomainObjPtr         vm;
    struct openvz_driver   *driver = dom->conn->privateData;
    int                     ret = -1;
1289

1290
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
1291 1292
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported flags (0x%x)"), flags);
1293 1294 1295
        return -1;
    }

1296 1297
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
1298

1299
    if (nvcpus <= 0) {
1300
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1301 1302 1303 1304
                       _("Number of vCPUs should be >= 1"));
        goto cleanup;
    }

1305
    if (openvzDomainSetVcpusInternal(vm, nvcpus, driver->xmlopt) < 0) {
1306 1307
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set number of vCPUs"));
1308
        goto cleanup;
1309 1310
    }

1311 1312
    ret = 0;

1313
 cleanup:
1314
    virDomainObjEndAPI(&vm);
1315
    return ret;
1316 1317
}

1318 1319 1320
static int
openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
1321
    return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
1322 1323
}

1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337

static int
openvzConnectURIProbe(char **uri)
{
    if (!virFileExists("/proc/vz"))
        return 0;

    if (access("/proc/vz", W_OK) < 0)
        return 0;

    return VIR_STRDUP(*uri, "openvz:///system");
}


1338 1339
static virDrvOpenStatus openvzConnectOpen(virConnectPtr conn,
                                          virConnectAuthPtr auth ATTRIBUTE_UNUSED,
1340
                                          virConfPtr conf ATTRIBUTE_UNUSED,
1341
                                          unsigned int flags)
1342
{
1343
    struct openvz_driver *driver;
1344

E
Eric Blake 已提交
1345 1346
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1347
    /* If path isn't /system, then they typoed, so tell them correct path */
1348
    if (STRNEQ(conn->uri->path, "/system")) {
1349 1350 1351 1352 1353
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected OpenVZ URI path '%s', try openvz:///system"),
                       conn->uri->path);
        return VIR_DRV_OPEN_ERROR;
    }
1354

1355 1356 1357 1358 1359
    if (!virFileExists("/proc/vz")) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("OpenVZ control file /proc/vz does not exist"));
        return VIR_DRV_OPEN_ERROR;
    }
1360

1361 1362 1363 1364
    if (access("/proc/vz", W_OK) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("OpenVZ control file /proc/vz is not accessible"));
        return VIR_DRV_OPEN_ERROR;
1365 1366
    }

1367 1368 1369
    /* We now know the URI is definitely for this driver, so beyond
     * here, don't return DECLINED, always use ERROR */

1370
    if (VIR_ALLOC(driver) < 0)
1371 1372
        return VIR_DRV_OPEN_ERROR;

1373
    if (!(driver->domains = virDomainObjListNew()))
1374 1375
        goto cleanup;

1376 1377
    if (!(driver->caps = openvzCapsInit()))
        goto cleanup;
1378

1379
    if (!(driver->xmlopt = virDomainXMLOptionNew(&openvzDomainDefParserConfig,
1380
                                                 NULL, NULL, NULL, NULL)))
1381 1382
        goto cleanup;

1383 1384
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1385

1386
    if (openvzExtractVersion(driver) < 0)
1387 1388
        goto cleanup;

1389
    conn->privateData = driver;
1390

1391
    return VIR_DRV_OPEN_SUCCESS;
1392

1393
 cleanup:
1394 1395
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1396
};
1397

1398 1399
static int openvzConnectClose(virConnectPtr conn)
{
1400
    struct openvz_driver *driver = conn->privateData;
1401

1402
    openvzFreeDriver(driver);
1403 1404 1405 1406 1407
    conn->privateData = NULL;

    return 0;
}

1408
static const char *openvzConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1409
    return "OpenVZ";
1410 1411
}

1412 1413
static int openvzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1414 1415 1416 1417
    /* Encryption is not relevant / applicable to way we talk to openvz */
    return 0;
}

1418 1419
static int openvzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1420 1421 1422 1423
    /* We run CLI tools directly so this is secure */
    return 1;
}

1424
static int
1425
openvzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1426 1427 1428 1429
{
    return 1;
}

1430
static char *openvzConnectGetCapabilities(virConnectPtr conn) {
1431 1432 1433
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1434
    openvzDriverLock(driver);
1435
    ret = virCapabilitiesFormatXML(driver->caps);
1436
    openvzDriverUnlock(driver);
1437

1438
    return ret;
1439 1440
}

1441
static int openvzConnectListDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
1442 1443
                                    int *ids, int nids)
{
1444
    int got = 0;
1445
    int veid;
1446
    int outfd = -1;
1447
    int rc = -1;
1448 1449
    int ret;
    char buf[32];
1450
    char *endptr;
1451
    virCommandPtr cmd = virCommandNewArgList(VZLIST, "-ovpsid", "-H", NULL);
1452 1453 1454 1455

    virCommandSetOutputFD(cmd, &outfd);
    if (virCommandRunAsync(cmd, NULL) < 0)
        goto cleanup;
1456

E
Eric Blake 已提交
1457
    while (got < nids) {
1458
        ret = openvz_readline(outfd, buf, 32);
E
Eric Blake 已提交
1459 1460
        if (!ret)
            break;
1461
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1462 1463
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse VPS ID %s"), buf);
1464 1465
            continue;
        }
1466 1467 1468
        ids[got] = veid;
        got ++;
    }
1469 1470 1471

    if (virCommandWait(cmd, NULL) < 0)
        goto cleanup;
1472

G
Guido Günther 已提交
1473 1474
    if (VIR_CLOSE(outfd) < 0) {
        virReportSystemError(errno, "%s", _("failed to close file"));
1475
        goto cleanup;
G
Guido Günther 已提交
1476
    }
1477 1478

    rc = got;
1479
 cleanup:
1480 1481 1482
    VIR_FORCE_CLOSE(outfd);
    virCommandFree(cmd);
    return rc;
1483 1484
}

1485 1486
static int openvzConnectNumOfDomains(virConnectPtr conn)
{
1487
    struct openvz_driver *driver = conn->privateData;
1488
    int n;
1489

1490
    openvzDriverLock(driver);
1491
    n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
1492
    openvzDriverUnlock(driver);
1493

1494
    return n;
1495 1496
}

1497 1498
static int openvzConnectListDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           char **const names, int nnames) {
1499
    int got = 0;
G
Guido Günther 已提交
1500
    int veid, outfd = -1, ret;
1501
    int rc = -1;
1502
    char vpsname[32];
1503
    char buf[32];
1504
    char *endptr;
1505 1506
    virCommandPtr cmd = virCommandNewArgList(VZLIST,
                                             "-ovpsid", "-H", "-S", NULL);
1507 1508

    /* the -S options lists only stopped domains */
1509 1510
    virCommandSetOutputFD(cmd, &outfd);
    if (virCommandRunAsync(cmd, NULL) < 0)
G
Guido Günther 已提交
1511
        goto out;
1512

E
Eric Blake 已提交
1513
    while (got < nnames) {
1514
        ret = openvz_readline(outfd, buf, 32);
E
Eric Blake 已提交
1515 1516
        if (!ret)
            break;
1517
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1518 1519
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse VPS ID %s"), buf);
1520 1521
            continue;
        }
1522
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
1523
        if (VIR_STRDUP(names[got], vpsname) < 0)
G
Guido Günther 已提交
1524
            goto out;
1525 1526
        got ++;
    }
1527 1528 1529 1530

    if (virCommandWait(cmd, NULL) < 0)
        goto out;

G
Guido Günther 已提交
1531 1532 1533 1534
    if (VIR_CLOSE(outfd) < 0) {
        virReportSystemError(errno, "%s", _("failed to close file"));
        goto out;
    }
1535

1536
    rc = got;
1537
 out:
G
Guido Günther 已提交
1538
    VIR_FORCE_CLOSE(outfd);
1539
    virCommandFree(cmd);
1540
    if (rc < 0) {
1541
        for (; got >= 0; got--)
1542 1543 1544
            VIR_FREE(names[got]);
    }
    return rc;
1545 1546
}

1547 1548 1549 1550 1551
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid)
{
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
D
Daniel Veillard 已提交
1552
    unsigned long long usertime, systime, nicetime;
1553
    int readvps = vpsid + 1;  /* ensure readvps is initially different */
1554
    ssize_t ret;
1555
    int err = 0;
D
Daniel Veillard 已提交
1556 1557

/* read statistic from /proc/vz/vestat.
1558
 sample:
D
Daniel Veillard 已提交
1559
Version: 2.2
1560 1561 1562
   VEID     user      nice     system     uptime                 idle   other..
     33       78         0       1330   59454597      142650441835148   other..
     55      178         0       5340   59424597      542650441835148   other..
D
Daniel Veillard 已提交
1563 1564
*/

1565
    if ((fp = fopen("/proc/vz/vestat", "r")) == NULL)
D
Daniel Veillard 已提交
1566 1567 1568
        return -1;

    /*search line with VEID=vpsid*/
E
Eric Blake 已提交
1569
    while (1) {
1570
        ret = getline(&line, &line_size, fp);
1571 1572
        if (ret < 0) {
            err = !feof(fp);
D
Daniel Veillard 已提交
1573
            break;
1574
        }
D
Daniel Veillard 已提交
1575

1576 1577
        if (sscanf(line, "%d %llu %llu %llu",
                   &readvps, &usertime, &nicetime, &systime) == 4
1578 1579 1580 1581 1582 1583 1584
            && readvps == vpsid) { /*found vpsid*/
            /* convert jiffies to nanoseconds */
            *cpuTime = (1000ull * 1000ull * 1000ull
                        * (usertime + nicetime  + systime)
                        / (unsigned long long)sysconf(_SC_CLK_TCK));
            break;
        }
D
Daniel Veillard 已提交
1585 1586
    }

1587 1588
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
1589
    if (err)
D
Daniel Veillard 已提交
1590 1591 1592 1593 1594 1595 1596 1597
        return -1;

    if (readvps != vpsid) /*not found*/
        return -1;

    return 0;
}

1598 1599
static int openvzConnectNumOfDefinedDomains(virConnectPtr conn)
{
1600
    struct openvz_driver *driver =  conn->privateData;
1601
    int n;
1602

1603
    openvzDriverLock(driver);
1604
    n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
1605
    openvzDriverUnlock(driver);
1606

1607
    return n;
1608 1609
}

1610
static int
1611
openvzDomainSetMemoryInternal(virDomainObjPtr vm,
1612
                              unsigned long long mem)
1613 1614
{
    char str_mem[16];
E
Eric Blake 已提交
1615
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
1616 1617 1618 1619
        "--kmemsize", str_mem, "--save", NULL
    };

    /* memory has to be changed its format from kbyte to byte */
1620
    snprintf(str_mem, sizeof(str_mem), "%llu", mem * 1024);
1621 1622

    openvzSetProgramSentinal(prog, vm->def->name);
1623
    if (virRun(prog, NULL) < 0)
1624 1625 1626 1627
        goto cleanup;

    return 0;

1628
 cleanup:
1629 1630 1631
    return -1;
}

1632 1633 1634 1635 1636 1637 1638

static int
openvzDomainGetBarrierLimit(virDomainPtr domain,
                            const char *param,
                            unsigned long long *barrier,
                            unsigned long long *limit)
{
1639
    int ret = -1;
1640 1641 1642 1643 1644 1645 1646
    char *endp, *output = NULL;
    const char *tmp;
    virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL);

    virCommandSetOutputBuffer(cmd, &output);
    virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param);
    virCommandAddArg(cmd, domain->name);
1647
    if (virCommandRun(cmd, NULL) < 0)
1648 1649 1650 1651 1652
        goto cleanup;

    tmp = output;
    virSkipSpaces(&tmp);
    if (virStrToLong_ull(tmp, &endp, 10, barrier) < 0) {
1653 1654
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Can't parse limit from "VZLIST" output '%s'"), output);
1655 1656 1657 1658 1659
        goto cleanup;
    }
    tmp = endp;
    virSkipSpaces(&tmp);
    if (virStrToLong_ull(tmp, &endp, 10, limit) < 0) {
1660 1661
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Can't parse barrier from "VZLIST" output '%s'"), output);
1662 1663 1664 1665
        goto cleanup;
    }

    ret = 0;
1666
 cleanup:
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
    VIR_FREE(output);
    virCommandFree(cmd);
    return ret;
}


static int
openvzDomainSetBarrierLimit(virDomainPtr domain,
                            const  char *param,
                            unsigned long long barrier,
                            unsigned long long limit)
{
1679
    int ret = -1;
1680 1681 1682 1683
    virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL);

    /* LONG_MAX indicates unlimited so reject larger values */
    if (barrier > LONG_MAX || limit > LONG_MAX) {
1684 1685 1686
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Failed to set %s for %s: value too large"), param,
                       domain->name);
1687 1688 1689 1690 1691 1692 1693
        goto cleanup;
    }

    virCommandAddArg(cmd, domain->name);
    virCommandAddArgFormat(cmd, "--%s", param);
    virCommandAddArgFormat(cmd, "%llu:%llu", barrier, limit);
    virCommandAddArg(cmd, "--save");
1694
    if (virCommandRun(cmd, NULL) < 0)
1695 1696 1697
        goto cleanup;

    ret = 0;
1698
 cleanup:
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
    virCommandFree(cmd);
    return ret;
}


static int
openvzDomainGetMemoryParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
{
1710 1711
    size_t i;
    int result = -1;
1712 1713 1714 1715 1716 1717
    const char *name;
    long kb_per_pages;
    unsigned long long barrier, limit, val;

    virCheckFlags(0, -1);

1718 1719
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
        goto cleanup;

    if (*nparams == 0) {
        *nparams = OPENVZ_NB_MEM_PARAM;
        return 0;
    }

    for (i = 0; i <= *nparams; i++) {
        virMemoryParameterPtr param = &params[i];

        switch (i) {
        case 0:
            name = "privvmpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

1736
            val = (limit == LONG_MAX) ? VIR_DOMAIN_MEMORY_PARAM_UNLIMITED : limit * kb_per_pages;
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;

        case 1:
            name = "privvmpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

1747
            val = (barrier == LONG_MAX) ? VIR_DOMAIN_MEMORY_PARAM_UNLIMITED : barrier * kb_per_pages;
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;

        case 2:
            name = "vmguarpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

            val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;
        }
    }

    if (*nparams > OPENVZ_NB_MEM_PARAM)
        *nparams = OPENVZ_NB_MEM_PARAM;
    result = 0;

1770
 cleanup:
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
    return result;
}


static int
openvzDomainSetMemoryParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
{
1781 1782
    size_t i;
    int result = -1;
1783 1784
    long kb_per_pages;

1785 1786
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
1787 1788 1789
        goto cleanup;

    virCheckFlags(0, -1);
1790 1791 1792 1793 1794 1795 1796 1797
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_MEMORY_HARD_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
        return -1;

    for (i = 0; i < nparams; i++) {
        virTypedParameterPtr param = &params[i];
        unsigned long long barrier, limit;

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
                                            &barrier, &limit) < 0)
                goto cleanup;
            limit = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
                                            barrier, limit) < 0)
                goto cleanup;
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
                                            &barrier, &limit) < 0)
                goto cleanup;
            barrier = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
                                            barrier, limit) < 0)
                goto cleanup;
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
            barrier = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "vmguarpages",
                                            barrier, LONG_MAX) < 0)
                goto cleanup;
        }
    }
    result = 0;
1828
 cleanup:
1829 1830 1831 1832
    return result;
}


1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
static int
openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason)
{
    virCommandPtr cmd;
    char *outbuf;
    char *line;
    int state;
    int ret = -1;

    cmd = virCommandNewArgList(VZLIST, vm->def->name, "-ostatus", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    if ((line = strchr(outbuf, '\n')) == NULL) {
1848 1849
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to parse vzlist output"));
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868
        goto cleanup;
    }
    *line++ = '\0';

    state = virDomainObjGetState(vm, reason);

    if (STREQ(outbuf, "running")) {
        /* There is no way to detect whether a domain is paused or not
         * with vzlist */
        if (state == VIR_DOMAIN_PAUSED)
            *status = state;
        else
            *status = VIR_DOMAIN_RUNNING;
    } else {
        *status = VIR_DOMAIN_SHUTOFF;
    }

    ret = 0;

1869
 cleanup:
1870 1871 1872 1873 1874
    virCommandFree(cmd);
    VIR_FREE(outbuf);
    return ret;
}

1875
static int
1876
openvzDomainInterfaceStats(virDomainPtr dom,
1877
                           const char *device,
1878
                           virDomainInterfaceStatsPtr stats)
1879 1880 1881
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
1882
    virDomainNetDefPtr net = NULL;
1883 1884
    int ret = -1;

1885 1886
    if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;
1887

1888
    if (virDomainObjCheckActive(vm) < 0)
1889 1890
        goto cleanup;

1891
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
1892 1893
        goto cleanup;

1894
    if (virNetDevTapInterfaceStats(net->ifname, stats,
1895
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
1896 1897 1898
        goto cleanup;

    ret = 0;
1899

1900
 cleanup:
1901
    virDomainObjEndAPI(&vm);
1902 1903 1904 1905
    return ret;
}


1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
static int
openvzUpdateDevice(virDomainDefPtr vmdef,
                   virDomainDeviceDefPtr dev,
                   bool persist)
{
    virDomainFSDefPtr fs, cur;
    int pos;

    if (dev->type == VIR_DOMAIN_DEVICE_FS) {
        fs = dev->data.fs;
        pos = virDomainFSIndexByName(vmdef, fs->dst);

        if (pos < 0) {
1919 1920
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), fs->dst);
1921 1922 1923 1924 1925
            return -1;
        }
        cur = vmdef->fss[pos];

        /* We only allow updating the quota */
1926
        if (STRNEQ(cur->src->path, fs->src->path)
1927 1928 1929 1930
            || cur->type != fs->type
            || cur->accessmode != fs->accessmode
            || cur->wrpolicy != fs->wrpolicy
            || cur->readonly != fs->readonly) {
1931
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1932
                           _("Can only modify disk quota"));
1933 1934 1935
            return -1;
        }

1936
        if (openvzSetDiskQuota(vmdef, fs, persist) < 0)
1937 1938 1939 1940
            return -1;
        cur->space_hard_limit = fs->space_hard_limit;
        cur->space_soft_limit = fs->space_soft_limit;
    } else {
1941 1942 1943
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can't modify device type '%s'"),
                       virDomainDeviceTypeToString(dev->type));
1944 1945 1946 1947 1948 1949 1950 1951 1952
        return -1;
    }

    return 0;
}


static int
openvzDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
J
John Ferlan 已提交
1953
                              unsigned int flags)
1954 1955 1956 1957 1958 1959
{
    int ret = -1;
    int veid;
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainDeviceDefPtr dev = NULL;
    virDomainObjPtr vm = NULL;
1960
    virDomainDefPtr def = NULL;
1961 1962 1963 1964 1965 1966
    bool persist = false;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

    openvzDriverLock(driver);
1967
    if (!(vm = openvzDomObjFromDomainLocked(driver, dom->uuid)))
1968 1969
        goto cleanup;

1970
    if (virStrToLong_i(vm->def->name, NULL, 10, &veid) < 0) {
1971 1972
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not convert domain name to VEID"));
1973 1974 1975
        goto cleanup;
    }

1976
    if (!(def = virDomainObjGetOneDef(vm, flags)))
1977 1978
        goto cleanup;

1979
    dev = virDomainDeviceDefParse(xml, def, driver->caps, driver->xmlopt,
1980
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
1981 1982 1983 1984 1985 1986
    if (!dev)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG)
        persist = true;

1987
    if (openvzUpdateDevice(def, dev, persist) < 0)
1988 1989 1990 1991
        goto cleanup;

    ret = 0;

1992
 cleanup:
1993 1994
    openvzDriverUnlock(driver);
    virDomainDeviceDefFree(dev);
1995
    virDomainObjEndAPI(&vm);
1996 1997 1998
    return ret;
}

1999
static int
2000 2001 2002
openvzConnectListAllDomains(virConnectPtr conn,
                            virDomainPtr **domains,
                            unsigned int flags)
2003 2004 2005 2006
{
    struct openvz_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2007
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2008 2009

    openvzDriverLock(driver);
2010 2011
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 NULL, flags);
2012 2013 2014 2015 2016
    openvzDriverUnlock(driver);

    return ret;
}

2017

2018 2019 2020 2021 2022

static int
openvzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                  virNodeInfoPtr nodeinfo)
{
M
Martin Kletzander 已提交
2023
    return virCapabilitiesGetNodeInfo(nodeinfo);
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
}


static int
openvzNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                      int cpuNum,
                      virNodeCPUStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
2034
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
}


static int
openvzNodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                         int cellNum,
                         virNodeMemoryStatsPtr params,
                         int *nparams,
                         unsigned int flags)
{
2045
    return virHostMemGetStats(cellNum, params, nparams, flags);
2046 2047 2048 2049 2050 2051 2052 2053 2054
}


static int
openvzNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                             unsigned long long *freeMems,
                             int startCell,
                             int maxCells)
{
2055
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
2056 2057 2058 2059 2060 2061
}


static unsigned long long
openvzNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
2062
    unsigned long long freeMem;
2063
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
2064 2065
        return 0;
    return freeMem;
2066 2067 2068 2069 2070 2071 2072 2073 2074
}


static int
openvzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
                    unsigned char **cpumap,
                    unsigned int *online,
                    unsigned int flags)
{
2075
    return virHostCPUGetMap(cpumap, online, flags);
2076 2077 2078
}


2079 2080 2081
static int
openvzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
2082
    switch ((virDrvFeature) feature) {
2083 2084 2085
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
    case VIR_DRV_FEATURE_MIGRATION_V3:
        return 1;
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
    case VIR_DRV_FEATURE_FD_PASSING:
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
    case VIR_DRV_FEATURE_MIGRATION_DIRECT:
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
    case VIR_DRV_FEATURE_MIGRATION_V1:
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
    case VIR_DRV_FEATURE_REMOTE:
    case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121
    default:
        return 0;
    }
}


static char *
openvzDomainMigrateBegin3Params(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams,
                                char **cookieout ATTRIBUTE_UNUSED,
                                int *cookieoutlen ATTRIBUTE_UNUSED,
                                unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    struct openvz_driver *driver = domain->conn->privateData;
    char *xml = NULL;
    int status;

    virCheckFlags(OPENVZ_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
        return NULL;

2122 2123
    if (!(vm = openvzDomObjFromDomain(driver, domain->uuid)))
        return NULL;
2124

2125
    if (virDomainObjCheckActive(vm) < 0)
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136
        goto cleanup;

    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

    if (status != VIR_DOMAIN_RUNNING) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
        goto cleanup;
    }

2137 2138
    xml = virDomainDefFormat(vm->def, driver->caps,
                             VIR_DOMAIN_DEF_FORMAT_SECURE);
2139 2140

 cleanup:
2141
    virDomainObjEndAPI(&vm);
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160
    return xml;
}

static int
openvzDomainMigratePrepare3Params(virConnectPtr dconn,
                                  virTypedParameterPtr params,
                                  int nparams,
                                  const char *cookiein ATTRIBUTE_UNUSED,
                                  int cookieinlen ATTRIBUTE_UNUSED,
                                  char **cookieout ATTRIBUTE_UNUSED,
                                  int *cookieoutlen ATTRIBUTE_UNUSED,
                                  char **uri_out,
                                  unsigned int fflags ATTRIBUTE_UNUSED)
{
    struct openvz_driver *driver = dconn->privateData;
    const char *dom_xml = NULL;
    const char *uri_in = NULL;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
2161 2162
    char *my_hostname = NULL;
    const char *hostname = NULL;
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183
    virURIPtr uri = NULL;
    int ret = -1;

    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
        goto error;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri_in) < 0)
        goto error;

    if (!dom_xml) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no domain XML passed"));
        goto error;
    }

    if (!(def = virDomainDefParseString(dom_xml, driver->caps, driver->xmlopt,
2184
                                        NULL,
2185 2186
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                        VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
        goto error;

    if (!(vm = virDomainObjListAdd(driver->domains, def,
                                   driver->xmlopt,
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
        goto error;
    def = NULL;

    if (!uri_in) {
2198
        if ((my_hostname = virGetHostname()) == NULL)
2199 2200
            goto error;

2201
        if (STRPREFIX(my_hostname, "localhost")) {
2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("hostname on destination resolved to localhost,"
                             " but migration requires an FQDN"));
            goto error;
        }
    } else {
        uri = virURIParse(uri_in);

        if (uri == NULL) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unable to parse URI: %s"),
                           uri_in);
            goto error;
        }

        if (uri->server == NULL) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("missing host in migration URI: %s"),
                           uri_in);
            goto error;
        } else {
            hostname = uri->server;
        }
    }

    if (virAsprintf(uri_out, "ssh://%s", hostname) < 0)
        goto error;

    ret = 0;
    goto done;

 error:
    virDomainDefFree(def);
    if (vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }

 done:
2241
    VIR_FREE(my_hostname);
2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
    virURIFree(uri);
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

static int
openvzDomainMigratePerform3Params(virDomainPtr domain,
                                  const char *dconnuri ATTRIBUTE_UNUSED,
                                  virTypedParameterPtr params,
                                  int nparams,
                                  const char *cookiein ATTRIBUTE_UNUSED,
                                  int cookieinlen ATTRIBUTE_UNUSED,
                                  char **cookieout ATTRIBUTE_UNUSED,
                                  int *cookieoutlen ATTRIBUTE_UNUSED,
                                  unsigned int flags)
{
    struct openvz_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    const char *uri_str = NULL;
    virURIPtr uri = NULL;
2263
    virCommandPtr cmd = NULL;
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
    int ret = -1;

    virCheckFlags(OPENVZ_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
        goto cleanup;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri_str) < 0)
        goto cleanup;

2275
    if (!(vm = openvzDomObjFromDomain(driver, domain->uuid)))
2276 2277 2278 2279 2280 2281 2282
        goto cleanup;

    /* parse dst host:port from uri */
    uri = virURIParse(uri_str);
    if (uri == NULL || uri->server == NULL)
        goto cleanup;

2283
    cmd = virCommandNew(VZMIGRATE);
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
    if (flags & VIR_MIGRATE_LIVE)
        virCommandAddArg(cmd, "--live");
    virCommandAddArg(cmd, uri->server);
    virCommandAddArg(cmd, vm->def->name);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virCommandFree(cmd);
    virURIFree(uri);
2297
    virDomainObjEndAPI(&vm);
2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
    return ret;
}

static virDomainPtr
openvzDomainMigrateFinish3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 char **cookieout ATTRIBUTE_UNUSED,
                                 int *cookieoutlen ATTRIBUTE_UNUSED,
                                 unsigned int flags,
                                 int cancelled)
{
    struct openvz_driver *driver = dconn->privateData;
    virDomainObjPtr vm = NULL;
    const char *dname = NULL;
    virDomainPtr dom = NULL;
    int status;

    if (cancelled)
        goto cleanup;

    virCheckFlags(OPENVZ_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
        goto cleanup;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0)
        goto cleanup;

    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
        /* Migration obviously failed if the domain doesn't exist */
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Migration failed. No domain on destination host "
                         "with matching name '%s'"),
                       NULLSTR(dname));
        goto cleanup;
    }

    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

    if (status != VIR_DOMAIN_RUNNING) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not running on destination host"));
        goto cleanup;
    }

    vm->def->id = strtoI(vm->def->name);
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_MIGRATED);

2352
    dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, vm->def->id);
2353 2354

 cleanup:
2355
    virDomainObjEndAPI(&vm);
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376
    return dom;
}

static int
openvzDomainMigrateConfirm3Params(virDomainPtr domain,
                                  virTypedParameterPtr params,
                                  int nparams,
                                  const char *cookiein ATTRIBUTE_UNUSED,
                                  int cookieinlen ATTRIBUTE_UNUSED,
                                  unsigned int flags,
                                  int cancelled)
{
    struct openvz_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int status;
    int ret = -1;

    virCheckFlags(OPENVZ_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
        goto cleanup;

2377
    if (!(vm = openvzDomObjFromDomain(driver, domain->uuid)))
2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398
        goto cleanup;

    if (cancelled) {
        if (openvzGetVEStatus(vm, &status, NULL) == -1)
            goto cleanup;

        if (status == VIR_DOMAIN_RUNNING) {
            ret = 0;
        } else {
            VIR_DEBUG("Domain '%s' does not recover after failed migration",
                      vm->def->name);
        }

        goto cleanup;
    }

    vm->def->id = -1;

    VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name);

    virDomainObjListRemove(driver->domains, vm);
2399
    virObjectLock(vm);
2400 2401 2402 2403

    ret = 0;

 cleanup:
2404
    virDomainObjEndAPI(&vm);
2405 2406 2407
    return ret;
}

2408 2409 2410 2411 2412 2413 2414 2415 2416
static int
openvzDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    virCheckFlags(0, -1);

2417 2418 2419
    if (!(obj = openvzDomObjFromDomain(driver, dom->uuid)))
        return -1;

2420 2421
    ret = 0;

2422
    virDomainObjEndAPI(&obj);
2423 2424 2425 2426
    return ret;
}


2427

2428
static virHypervisorDriver openvzHypervisorDriver = {
2429
    .name = "OPENVZ",
2430
    .connectURIProbe = openvzConnectURIProbe,
2431 2432 2433 2434
    .connectOpen = openvzConnectOpen, /* 0.3.1 */
    .connectClose = openvzConnectClose, /* 0.3.1 */
    .connectGetType = openvzConnectGetType, /* 0.3.1 */
    .connectGetVersion = openvzConnectGetVersion, /* 0.5.0 */
2435
    .connectGetHostname = openvzConnectGetHostname, /* 0.9.12 */
2436
    .connectGetMaxVcpus = openvzConnectGetMaxVcpus, /* 0.4.6 */
2437 2438 2439 2440 2441 2442
    .nodeGetInfo = openvzNodeGetInfo, /* 0.3.2 */
    .nodeGetCPUStats = openvzNodeGetCPUStats, /* 0.9.12 */
    .nodeGetMemoryStats = openvzNodeGetMemoryStats, /* 0.9.12 */
    .nodeGetCellsFreeMemory = openvzNodeGetCellsFreeMemory, /* 0.9.12 */
    .nodeGetFreeMemory = openvzNodeGetFreeMemory, /* 0.9.12 */
    .nodeGetCPUMap = openvzNodeGetCPUMap, /* 1.0.0 */
2443 2444 2445 2446
    .connectGetCapabilities = openvzConnectGetCapabilities, /* 0.4.6 */
    .connectListDomains = openvzConnectListDomains, /* 0.3.1 */
    .connectNumOfDomains = openvzConnectNumOfDomains, /* 0.3.1 */
    .connectListAllDomains = openvzConnectListAllDomains, /* 0.9.13 */
2447 2448 2449 2450 2451 2452 2453
    .domainCreateXML = openvzDomainCreateXML, /* 0.3.3 */
    .domainLookupByID = openvzDomainLookupByID, /* 0.3.1 */
    .domainLookupByUUID = openvzDomainLookupByUUID, /* 0.3.1 */
    .domainLookupByName = openvzDomainLookupByName, /* 0.3.1 */
    .domainSuspend = openvzDomainSuspend, /* 0.8.3 */
    .domainResume = openvzDomainResume, /* 0.8.3 */
    .domainShutdown = openvzDomainShutdown, /* 0.3.1 */
2454
    .domainShutdownFlags = openvzDomainShutdownFlags, /* 0.9.10 */
2455
    .domainReboot = openvzDomainReboot, /* 0.3.1 */
2456 2457 2458
    .domainDestroy = openvzDomainDestroy, /* 0.3.1 */
    .domainDestroyFlags = openvzDomainDestroyFlags, /* 0.9.4 */
    .domainGetOSType = openvzDomainGetOSType, /* 0.3.1 */
2459 2460
    .domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */
    .domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */
2461 2462 2463 2464 2465 2466 2467
    .domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */
    .domainGetState = openvzDomainGetState, /* 0.9.2 */
    .domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */
    .domainSetVcpusFlags = openvzDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = openvzDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = openvzDomainGetMaxVcpus, /* 0.4.6 */
    .domainGetXMLDesc = openvzDomainGetXMLDesc, /* 0.4.6 */
2468 2469
    .connectListDefinedDomains = openvzConnectListDefinedDomains, /* 0.3.1 */
    .connectNumOfDefinedDomains = openvzConnectNumOfDefinedDomains, /* 0.3.1 */
2470 2471 2472
    .domainCreate = openvzDomainCreate, /* 0.3.1 */
    .domainCreateWithFlags = openvzDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = openvzDomainDefineXML, /* 0.3.3 */
2473
    .domainDefineXMLFlags = openvzDomainDefineXMLFlags, /* 1.2.12 */
2474
    .domainUndefine = openvzDomainUndefine, /* 0.3.3 */
2475
    .domainUndefineFlags = openvzDomainUndefineFlags, /* 0.9.4 */
2476 2477
    .domainGetAutostart = openvzDomainGetAutostart, /* 0.4.6 */
    .domainSetAutostart = openvzDomainSetAutostart, /* 0.4.6 */
2478
    .domainInterfaceStats = openvzDomainInterfaceStats, /* 0.9.12 */
2479 2480
    .connectIsEncrypted = openvzConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = openvzConnectIsSecure, /* 0.7.3 */
2481 2482 2483
    .domainIsActive = openvzDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = openvzDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = openvzDomainIsUpdated, /* 0.8.6 */
2484
    .connectIsAlive = openvzConnectIsAlive, /* 0.9.8 */
2485
    .domainUpdateDeviceFlags = openvzDomainUpdateDeviceFlags, /* 0.9.13 */
2486
    .domainGetHostname = openvzDomainGetHostname, /* 0.10.0 */
2487 2488 2489 2490 2491 2492
    .connectSupportsFeature = openvzConnectSupportsFeature, /* 1.2.8 */
    .domainMigrateBegin3Params = openvzDomainMigrateBegin3Params, /* 1.2.8 */
    .domainMigratePrepare3Params = openvzDomainMigratePrepare3Params, /* 1.2.8 */
    .domainMigratePerform3Params = openvzDomainMigratePerform3Params, /* 1.2.8 */
    .domainMigrateFinish3Params = openvzDomainMigrateFinish3Params, /* 1.2.8 */
    .domainMigrateConfirm3Params = openvzDomainMigrateConfirm3Params, /* 1.2.8 */
2493
    .domainHasManagedSaveImage = openvzDomainHasManagedSaveImage, /* 1.2.13 */
2494 2495
};

2496
static virConnectDriver openvzConnectDriver = {
2497
    .localOnly = true,
2498
    .uriSchemes = (const char *[]){ "openvz", NULL },
2499 2500 2501
    .hypervisorDriver = &openvzHypervisorDriver,
};

2502 2503
int openvzRegister(void)
{
2504 2505
    return virRegisterConnectDriver(&openvzConnectDriver,
                                    false);
2506
}