openvz_driver.c 37.0 KB
Newer Older
1 2 3 4 5
/*
 * openvz_driver.c: core driver methods for managing OpenVZ VEs
 *
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
6
 * Copyright (C) 2007 Anoop Joe Cyriac
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
22
 * Authors:
23 24 25
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/wait.h>

50
#include "virterror_internal.h"
51
#include "datatypes.h"
52
#include "openvz_driver.h"
53 54
#include "event.h"
#include "buf.h"
55
#include "util.h"
56
#include "openvz_conf.h"
57
#include "nodeinfo.h"
58
#include "memory.h"
59
#include "bridge.h"
60

61 62 63
#define OPENVZ_MAX_ARG 28
#define CMDBUF_LEN 1488
#define CMDOP_LEN 288
64

D
Daniel Veillard 已提交
65
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
66 67 68
static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type);
static int openvzDomainGetMaxVcpus(virDomainPtr dom);
static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus);
69
static int openvzDomainSetVcpusInternal(virConnectPtr conn, virDomainObjPtr vm, unsigned int nvcpus);
D
Daniel Veillard 已提交
70

71 72 73 74 75 76 77 78 79 80
static void openvzDriverLock(struct openvz_driver *driver)
{
    pthread_mutex_lock(&driver->lock);
}

static void openvzDriverUnlock(struct openvz_driver *driver)
{
    pthread_mutex_unlock(&driver->lock);
}

81 82
struct openvz_driver ovz_driver;

83
static void cmdExecFree(const char *cmdExec[])
84 85 86 87
{
    int i=-1;
    while(cmdExec[++i])
    {
88
        VIR_FREE(cmdExec[i]);
89 90 91
    }
}

92 93 94 95 96
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
*/
static int openvzDomainDefineCmd(virConnectPtr conn,
97
                                 const char *args[],
98
                                 int maxarg,
99
                                 virDomainDefPtr vmdef)
100 101 102 103 104 105 106 107
{
    int narg;

    for (narg = 0; narg < maxarg; narg++)
        args[narg] = NULL;

    if (vmdef == NULL){
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
108
                   "%s", _("Container is not defined"));
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        return -1;
    }

#define ADD_ARG(thisarg)                                                \
    do {                                                                \
        if (narg >= maxarg)                                             \
                 goto no_memory;                                        \
        args[narg++] = thisarg;                                         \
    } while (0)

#define ADD_ARG_LIT(thisarg)                                            \
    do {                                                                \
        if (narg >= maxarg)                                             \
                 goto no_memory;                                        \
        if ((args[narg++] = strdup(thisarg)) == NULL)                   \
            goto no_memory;                                             \
    } while (0)

    narg = 0;
    ADD_ARG_LIT(VZCTL);
    ADD_ARG_LIT("--quiet");
    ADD_ARG_LIT("create");
    ADD_ARG_LIT(vmdef->name);
132

133 134
    if (vmdef->nfss) {
        if (vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE) {
135 136 137 138
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("only filesystem templates are supported"));
            return -1;
        }
139

140
        if (vmdef->nfss > 1) {
141 142 143 144
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("only one filesystem supported"));
            return -1;
        }
145 146

        ADD_ARG_LIT("--ostemplate");
147
        ADD_ARG_LIT(vmdef->fss[0]->src);
148
    }
149
#if 0
150 151 152 153
    if ((vmdef->profile && *(vmdef->profile))) {
        ADD_ARG_LIT("--config");
        ADD_ARG_LIT(vmdef->profile);
    }
154
#endif
155 156 157 158 159 160 161 162 163 164 165 166

    ADD_ARG(NULL);
    return 0;
 no_memory:
    openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not put argument to %s"), VZCTL);
    return -1;
#undef ADD_ARG
#undef ADD_ARG_LIT
}


167
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
168
                                           int id) {
169
    struct openvz_driver *driver = conn->privateData;
170
    virDomainObjPtr vm;
171
    virDomainPtr dom = NULL;
172

173
    openvzDriverLock(driver);
174
    vm = virDomainFindByID(&driver->domains, id);
175 176
    openvzDriverUnlock(driver);

177
    if (!vm) {
178
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
179
        goto cleanup;
180 181
    }

182
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
183 184
    if (dom)
        dom->id = vm->def->id;
185

186
cleanup:
187 188
    if (vm)
        virDomainObjUnlock(vm);
189 190 191
    return dom;
}

192
static int openvzGetVersion(virConnectPtr conn, unsigned long *version) {
193
    struct  openvz_driver *driver = conn->privateData;
194
    openvzDriverLock(driver);
195
    *version = driver->version;
196
    openvzDriverUnlock(driver);
197 198 199
    return 0;
}

200
static char *openvzGetOSType(virDomainPtr dom)
201
{
202 203 204
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
205

206
    openvzDriverLock(driver);
207
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
208 209
    openvzDriverUnlock(driver);

210 211
    if (!vm) {
        openvzError(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
212
        goto cleanup;
213 214 215 216 217
    }

    if (!(ret = strdup(vm->def->os.type)))
        openvzError(dom->conn, VIR_ERR_NO_MEMORY, NULL);

218
cleanup:
219 220
    if (vm)
        virDomainObjUnlock(vm);
221
    return ret;
222 223 224 225
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
226
                                             const unsigned char *uuid) {
227 228 229
    struct  openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
230

231
    openvzDriverLock(driver);
232
    vm = virDomainFindByUUID(&driver->domains, uuid);
233 234
    openvzDriverUnlock(driver);

235
    if (!vm) {
236
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
237
        goto cleanup;
238 239
    }

240
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
241 242
    if (dom)
        dom->id = vm->def->id;
243

244
cleanup:
245 246
    if (vm)
        virDomainObjUnlock(vm);
247 248 249 250
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
251 252 253 254
                                             const char *name) {
    struct openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
255

256
    openvzDriverLock(driver);
257
    vm = virDomainFindByName(&driver->domains, name);
258 259
    openvzDriverUnlock(driver);

260
    if (!vm) {
261
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
262
        goto cleanup;
263 264
    }

265
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
266 267
    if (dom)
        dom->id = vm->def->id;
268

269
cleanup:
270 271
    if (vm)
        virDomainObjUnlock(vm);
272 273 274 275
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
276
                               virDomainInfoPtr info) {
277 278 279
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
280

281
    openvzDriverLock(driver);
282
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
283 284
    openvzDriverUnlock(driver);

285
    if (!vm) {
D
Daniel Veillard 已提交
286
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
287
                    "%s", _("no domain with matching uuid"));
288
        goto cleanup;
289 290
    }

291
    info->state = vm->state;
292

293
    if (!virDomainIsActive(vm)) {
D
Daniel Veillard 已提交
294 295 296 297
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
            openvzError(dom->conn, VIR_ERR_OPERATION_FAILED,
298
                        _("cannot read cputime for domain %d"), dom->id);
299
            goto cleanup;
D
Daniel Veillard 已提交
300 301 302
        }
    }

303 304 305
    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
306 307 308
    ret = 0;

cleanup:
309 310
    if (vm)
        virDomainObjUnlock(vm);
311
    return ret;
312 313 314
}


315
static char *openvzDomainDumpXML(virDomainPtr dom, int flags) {
316 317 318
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
319

320
    openvzDriverLock(driver);
321
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
322 323
    openvzDriverUnlock(driver);

324
    if (!vm) {
D
Daniel Veillard 已提交
325
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
326
                    "%s", _("no domain with matching uuid"));
327
        goto cleanup;
328
    }
329

330 331 332
    ret = virDomainDefFormat(dom->conn, vm->def, flags);

cleanup:
333 334
    if (vm)
        virDomainObjUnlock(vm);
335
    return ret;
336
}
337

338

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
/*
 * 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
 */
#define PROGRAM_SENTINAL ((char *)0x1)
static void openvzSetProgramSentinal(const char **prog, const char *key)
{
    const char **tmp = prog;
    while (tmp && *tmp) {
        if (*tmp == PROGRAM_SENTINAL) {
            *tmp = key;
            break;
        }
        tmp++;
    }
}
357 358

static int openvzDomainShutdown(virDomainPtr dom) {
359 360 361 362
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "stop", PROGRAM_SENTINAL, NULL};
    int ret = -1;
363

364
    openvzDriverLock(driver);
365
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
366 367
    openvzDriverUnlock(driver);

368 369
    if (!vm) {
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
370
                    "%s", _("no domain with matching uuid"));
371
        goto cleanup;
372
    }
373

374
    openvzSetProgramSentinal(prog, vm->def->name);
375
    if (vm->state != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
376
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
377
                    "%s", _("domain is not in running state"));
378
        goto cleanup;
379
    }
380

381
    if (virRun(dom->conn, prog, NULL) < 0)
382
        goto cleanup;
383

384 385
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;
386
    ret = 0;
387

388
cleanup:
389 390
    if (vm)
        virDomainObjUnlock(vm);
391
    return ret;
392 393
}

394 395
static int openvzDomainReboot(virDomainPtr dom,
                              unsigned int flags ATTRIBUTE_UNUSED) {
396 397 398 399
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "restart", PROGRAM_SENTINAL, NULL};
    int ret = -1;
400

401
    openvzDriverLock(driver);
402
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
403 404
    openvzDriverUnlock(driver);

405
    if (!vm) {
D
Daniel Veillard 已提交
406
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
407
                    "%s", _("no domain with matching uuid"));
408
        goto cleanup;
409
    }
410

411
    openvzSetProgramSentinal(prog, vm->def->name);
412 413
    if (vm->state != VIR_DOMAIN_RUNNING) {
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
414
                    "%s", _("domain is not in running state"));
415
        goto cleanup;
416
    }
417

418
    if (virRun(dom->conn, prog, NULL) < 0)
419 420
        goto cleanup;
    ret = 0;
421

422
cleanup:
423 424
    if (vm)
        virDomainObjUnlock(vm);
425
    return ret;
426 427
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
static char *
openvzGenerateVethName(int veid, char *dev_name_ve)
{
    char    dev_name[32];
    int     ifNo = 0;

    if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
        return NULL;
    if (snprintf(dev_name, sizeof(dev_name), "veth%d.%d", veid, ifNo) < 7)
        return NULL;
    return strdup(dev_name);
}

static char *
openvzGenerateContainerVethName(int veid)
{
    int     ret;
    char    temp[1024];

    /* try to get line "^NETIF=..." from config */
    if ( (ret = openvzReadConfigParam(veid, "NETIF", temp, sizeof(temp))) <= 0) {
        snprintf(temp, sizeof(temp), "eth0");
    } else {
        char   *s;
        int     max = 0;

        /* get maximum interface number (actually, it is the last one) */
        for (s=strtok(temp, ";"); s; s=strtok(NULL, ";")) {
            int x;

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

        /* set new name */
        snprintf(temp, sizeof(temp), "eth%d", max+1);
    }
    return strdup(temp);
}

D
Daniel Veillard 已提交
468 469
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
470 471
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
472 473
{
    int rc = 0, narg;
474
    const char *prog[OPENVZ_MAX_ARG];
475
    char macaddr[VIR_MAC_STRING_BUFLEN];
476 477
    unsigned char host_mac[VIR_MAC_BUFLEN];
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
478
    struct openvz_driver *driver =  conn->privateData;
479
    char *opt = NULL;
D
Daniel Veillard 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492 493

#define ADD_ARG_LIT(thisarg)                                            \
    do {                                                                \
        if (narg >= OPENVZ_MAX_ARG)                                             \
                 goto no_memory;                                        \
        if ((prog[narg++] = strdup(thisarg)) == NULL)                   \
            goto no_memory;                                             \
    } while (0)


    if (net == NULL)
       return 0;
    if (vpsid == NULL) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
494
                    "%s", _("Container ID is not specified"));
D
Daniel Veillard 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
        return -1;
    }

    for (narg = 0; narg < OPENVZ_MAX_ARG; narg++)
        prog[narg] = NULL;

    narg = 0;

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_ETHERNET) {
        ADD_ARG_LIT(VZCTL);
        ADD_ARG_LIT("--quiet");
        ADD_ARG_LIT("set");
        ADD_ARG_LIT(vpsid);
    }

511
    virFormatMacAddr(net->mac, macaddr);
512 513
    virCapabilitiesGenerateMac(driver->caps, host_mac);
    virFormatMacAddr(host_mac, host_macaddr);
514 515 516 517 518

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        virBuffer buf = VIR_BUFFER_INITIALIZER;
        char *dev_name_ve;
        int veid = strtoI(vpsid);
D
Daniel Veillard 已提交
519 520 521

        //--netif_add ifname[,mac,host_ifname,host_mac]
        ADD_ARG_LIT("--netif_add") ;
522 523 524 525 526

        /* generate interface name in ve and copy it to options */
        dev_name_ve = openvzGenerateContainerVethName(veid);
        if (dev_name_ve == NULL) {
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
527
                       "%s", _("Could not generate eth name for container"));
528 529 530 531 532 533 534 535 536 537
           rc = -1;
           goto exit;
        }

        /* if user doesn't specified host interface name,
         * than we need to generate it */
        if (net->ifname == NULL) {
            net->ifname = openvzGenerateVethName(veid, dev_name_ve);
            if (net->ifname == NULL) {
               openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
538
                           "%s", _("Could not generate veth name"));
539 540 541 542 543 544 545 546 547
               rc = -1;
               VIR_FREE(dev_name_ve);
               goto exit;
            }
        }

        virBufferAdd(&buf, dev_name_ve, -1); /* Guest dev */
        virBufferVSprintf(&buf, ",%s", macaddr); /* Guest dev mac */
        virBufferVSprintf(&buf, ",%s", net->ifname); /* Host dev */
548
        virBufferVSprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
549 550 551 552 553 554 555

        if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
            virBufferVSprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
        } else {
            virBufferVSprintf(configBuf, "ifname=%s", dev_name_ve);
            virBufferVSprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
            virBufferVSprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
556
            virBufferVSprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
557
            virBufferVSprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
D
Daniel Veillard 已提交
558
        }
559 560 561 562 563 564

        VIR_FREE(dev_name_ve);

        if (!(opt = virBufferContentAndReset(&buf)))
            goto no_memory;

D
Daniel Veillard 已提交
565
        ADD_ARG_LIT(opt) ;
566 567
        VIR_FREE(opt);
    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
D
Daniel Veillard 已提交
568 569 570 571 572 573 574 575 576 577
              net->data.ethernet.ipaddr != NULL) {
        //--ipadd ip
        ADD_ARG_LIT("--ipadd") ;
        ADD_ARG_LIT(net->data.ethernet.ipaddr) ;
    }

    //TODO: processing NAT and physical device

    if (prog[0] != NULL){
        ADD_ARG_LIT("--save");
578
        if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
579 580 581 582 583 584 585 586 587 588 589 590
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
           rc = -1;
           goto exit;
        }
    }

 exit:
    cmdExecFree(prog);
    return rc;

 no_memory:
591
    VIR_FREE(opt);
D
Daniel Veillard 已提交
592 593 594 595 596 597 598 599
    openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not put argument to %s"), VZCTL);
    cmdExecFree(prog);
    return -1;

#undef ADD_ARG_LIT
}

600 601 602 603 604 605 606 607 608

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
    unsigned int i;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
609
    struct openvz_driver *driver =  conn->privateData;
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648

    for (i = 0 ; i < def->nnets ; i++) {
        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) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Could not configure network"));
            goto exit;
        }
    }

    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
        param = virBufferContentAndReset(&buf);
        if (param) {
            if (openvzWriteConfigParam(strtoI(def->name), "NETIF", param) < 0) {
                VIR_FREE(param);
                openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                            "%s", _("cannot replace NETIF config"));
                return -1;
            }
            VIR_FREE(param);
        }
    }

    return 0;

exit:
    param = virBufferContentAndReset(&buf);
    VIR_FREE(param);
    return -1;
}


649 650 651
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
652
    struct openvz_driver *driver =  conn->privateData;
653 654
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
655
    virDomainPtr dom = NULL;
656
    const char *prog[OPENVZ_MAX_ARG];
657
    prog[0] = NULL;
658

659
    openvzDriverLock(driver);
660
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml)) == NULL)
661
        goto cleanup;
662

663 664
    if (vmdef->os.init == NULL &&
        !(vmdef->os.init = strdup("/sbin/init"))) {
665
        goto cleanup;
666 667
    }

668
    vm = virDomainFindByName(&driver->domains, vmdef->name);
669
    if (vm) {
670 671
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM active with the id '%s'"),
672
                  vmdef->name);
673
        goto cleanup;
674
    }
675 676 677
    if (!(vm = virDomainAssignDef(conn, &driver->domains, vmdef)))
        goto cleanup;
    vmdef = NULL;
678

679
    if (openvzDomainDefineCmd(conn, prog, OPENVZ_MAX_ARG, vm->def) < 0) {
680
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
681
                "%s", _("Error creating command for container"));
682
        goto cleanup;
683 684
    }

D
Daniel Veillard 已提交
685 686
    //TODO: set quota

687
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
688
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
689
               _("Could not exec %s"), VZCTL);
690
        goto cleanup;
691
    }
692

693
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
694
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
695
               "%s", _("Could not set UUID"));
696
        goto cleanup;
697 698
    }

699 700
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
701

702
    if (vm->def->vcpus > 0) {
703
        if (openvzDomainSetVcpusInternal(conn, vm, vm->def->vcpus) < 0) {
704
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
705
                     "%s", _("Could not set number of virtual cpu"));
706
             goto cleanup;
707 708 709
        }
    }

710 711 712 713 714 715
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

cleanup:
    virDomainDefFree(vmdef);
716
    cmdExecFree(prog);
717 718 719
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
720 721 722 723
    return dom;
}

static virDomainPtr
724
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
725
                      unsigned int flags ATTRIBUTE_UNUSED)
726
{
727
    struct openvz_driver *driver =  conn->privateData;
728 729
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
730
    virDomainPtr dom = NULL;
731
    const char *progstart[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL};
732
    const char *progcreate[OPENVZ_MAX_ARG];
733
    progcreate[0] = NULL;
734

735
    openvzDriverLock(driver);
736
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml)) == NULL)
737
        goto cleanup;
738 739

    if (vmdef->os.init == NULL &&
740 741
        !(vmdef->os.init = strdup("/sbin/init")))
        goto cleanup;
742

743
    vm = virDomainFindByName(&driver->domains, vmdef->name);
744
    if (vm) {
745 746 747
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM defined with the id '%s'"),
                  vmdef->name);
748
        goto cleanup;
749
    }
750 751 752
    if (!(vm = virDomainAssignDef(conn, &driver->domains, vmdef)))
        goto cleanup;
    vmdef = NULL;
753

754
    if (openvzDomainDefineCmd(conn, progcreate, OPENVZ_MAX_ARG, vm->def) < 0) {
755
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
756 757
                    "%s", _("Error creating command for container"));
        goto cleanup;
758 759
    }

760
    if (virRun(conn, progcreate, NULL) < 0) {
D
Daniel Veillard 已提交
761
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
762
               _("Could not exec %s"), VZCTL);
763
        goto cleanup;
764
    }
765

766
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
767
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
768
               "%s", _("Could not set UUID"));
769
        goto cleanup;
770 771
    }

772 773
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
774

775
    openvzSetProgramSentinal(progstart, vm->def->name);
776

777
    if (virRun(conn, progstart, NULL) < 0) {
D
Daniel Veillard 已提交
778
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
779
               _("Could not exec %s"), VZCTL);
780
        goto cleanup;
781
    }
782

783
    vm->pid = strtoI(vm->def->name);
784 785
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
786

787
    if (vm->def->vcpus > 0) {
788
        if (openvzDomainSetVcpusInternal(conn, vm, vm->def->vcpus) < 0) {
789
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
790
                    "%s", _("Could not set number of virtual cpu"));
791
            goto cleanup;
792 793 794
        }
    }

795 796 797 798 799 800
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

cleanup:
    virDomainDefFree(vmdef);
801
    cmdExecFree(progcreate);
802 803 804
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
805 806 807 808 809 810
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
811 812 813 814
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL };
    int ret = -1;
815

816
    openvzDriverLock(driver);
817
    vm = virDomainFindByName(&driver->domains, dom->name);
818 819
    openvzDriverUnlock(driver);

820
    if (!vm) {
D
Daniel Veillard 已提交
821
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
822 823
                    "%s", _("no domain with matching id"));
        goto cleanup;
824
    }
825

826
    if (vm->state != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
827
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
828 829
                    "%s", _("domain is not in shutoff state"));
        goto cleanup;
830 831
    }

832
    openvzSetProgramSentinal(prog, vm->def->name);
833
    if (virRun(dom->conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
834
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
835 836
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
837
    }
838

839 840 841
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
842
    ret = 0;
843

844
cleanup:
845 846
    if (vm)
        virDomainObjUnlock(vm);
847
    return ret;
848 849 850 851 852
}

static int
openvzDomainUndefine(virDomainPtr dom)
{
853 854 855 856
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINAL, NULL };
    int ret = -1;
857

858
    openvzDriverLock(driver);
859
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
860
    if (!vm) {
861 862
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
863
    }
864

865
    if (virDomainIsActive(vm)) {
866 867
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete active domain"));
        goto cleanup;
868
    }
869

870 871 872 873 874
    openvzSetProgramSentinal(prog, vm->def->name);
    if (virRun(dom->conn, prog, NULL) < 0) {
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
875
    }
876

877
    virDomainRemoveInactive(&driver->domains, vm);
878
    vm = NULL;
879
    ret = 0;
880

881
cleanup:
882 883 884
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
885
    return ret;
886 887
}

888 889 890
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
891 892 893
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
D
Daniel Veillard 已提交
894
                           "--onboot", autostart ? "yes" : "no",
895
                           "--save", NULL };
896
    int ret = -1;
897

898
    openvzDriverLock(driver);
899
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
900 901
    openvzDriverUnlock(driver);

902
    if (!vm) {
903 904
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
905 906
    }

907 908 909 910
    openvzSetProgramSentinal(prog, vm->def->name);
    if (virRun(dom->conn, prog, NULL) < 0) {
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL);
        goto cleanup;
911
    }
912
    ret = 0;
913

914
cleanup:
915 916
    if (vm)
        virDomainObjUnlock(vm);
917
    return ret;
918 919 920 921 922
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
923 924
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
925
    char value[1024];
926
    int ret = -1;
927

928
    openvzDriverLock(driver);
929
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
930 931
    openvzDriverUnlock(driver);

932
    if (!vm) {
933 934 935
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                    "%s", _("no domain with matching uuid"));
        goto cleanup;
936 937
    }

938
    if (openvzReadConfigParam(strtoI(vm->def->name), "ONBOOT", value, sizeof(value)) < 0) {
939 940 941
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Could not read container config"));
        goto cleanup;
942 943 944 945
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
946
        *autostart = 1;
947
    ret = 0;
948

949
cleanup:
950 951
    if (vm)
        virDomainObjUnlock(vm);
952
    return ret;
953 954
}

955 956 957 958 959 960 961 962 963 964 965 966 967 968
static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type) {
    if (STRCASEEQ(type, "openvz"))
        return 1028; //OpenVZ has no limitation

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


static int openvzDomainGetMaxVcpus(virDomainPtr dom) {
    return openvzGetMaxVCPUs(dom->conn, "openvz");
}

969 970 971 972
static int openvzDomainSetVcpusInternal(virConnectPtr conn, virDomainObjPtr vm,
    unsigned int nvcpus)
{
    char        str_vcpus[32];
973
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
974
                           "--cpus", str_vcpus, "--save", NULL };
975
    unsigned int pcpus;
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
    pcpus = openvzGetNodeCPUs();
    if (pcpus > 0 && pcpus < nvcpus)
        nvcpus = pcpus;

    snprintf(str_vcpus, 31, "%d", nvcpus);
    str_vcpus[31] = '\0';

    openvzSetProgramSentinal(prog, vm->def->name);
    if (virRun(conn, prog, NULL) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not exec %s"), VZCTL);
        return -1;
    }

    vm->def->vcpus = nvcpus;
    return 0;
}

static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    virDomainObjPtr         vm;
    struct openvz_driver   *driver = dom->conn->privateData;
    int                     ret = -1;
999

1000
    openvzDriverLock(driver);
1001
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1002 1003
    openvzDriverUnlock(driver);

1004
    if (!vm) {
1005
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
1006
                    "%s", _("no domain with matching uuid"));
1007
        goto cleanup;
1008 1009
    }

1010
    if (nvcpus <= 0) {
1011
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1012
                    "%s", _("VCPUs should be >= 1"));
1013
        goto cleanup;
1014 1015
    }

1016
    openvzDomainSetVcpusInternal(dom->conn, vm, nvcpus);
1017 1018 1019
    ret = 0;

cleanup:
1020 1021
    if (vm)
        virDomainObjUnlock(vm);
1022
    return ret;
1023 1024
}

1025
static int openvzProbe(void)
1026
{
1027 1028 1029 1030 1031
    if (geteuid() == 0 &&
        virFileExists("/proc/vz"))
        return 1;

    return 0;
1032 1033
}

1034
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
1035 1036
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED)
1037
{
1038
    struct openvz_driver *driver;
1039
    if (!openvzProbe())
1040
        return VIR_DRV_OPEN_DECLINED;
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

    if (conn->uri == NULL) {
        conn->uri = xmlParseURI("openvz:///system");
        if (conn->uri == NULL) {
            openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
            return VIR_DRV_OPEN_ERROR;
        }
    } else if (conn->uri->scheme == NULL ||
               conn->uri->path == NULL ||
               STRNEQ (conn->uri->scheme, "openvz") ||
               STRNEQ (conn->uri->path, "/system")) {
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
        return VIR_DRV_OPEN_DECLINED;
    }

    if (VIR_ALLOC(driver) < 0) {
        openvzError(conn, VIR_ERR_NO_MEMORY, NULL);
        return VIR_DRV_OPEN_ERROR;
    }

    if (!(driver->caps = openvzCapsInit()))
        goto cleanup;
1062

1063 1064
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1065

1066 1067 1068
    if (openvzExtractVersion(conn, driver) < 0)
        goto cleanup;

1069
    conn->privateData = driver;
1070

1071
    return VIR_DRV_OPEN_SUCCESS;
1072

1073 1074 1075
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1076
};
1077 1078

static int openvzClose(virConnectPtr conn) {
1079
    struct openvz_driver *driver = conn->privateData;
1080

1081
    openvzFreeDriver(driver);
1082 1083 1084 1085 1086 1087 1088 1089 1090
    conn->privateData = NULL;

    return 0;
}

static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
    return strdup("OpenVZ");
}

1091 1092 1093 1094 1095
static int openvzGetNodeInfo(virConnectPtr conn,
                             virNodeInfoPtr nodeinfo) {
    return virNodeInfoPopulate(conn, nodeinfo);
}

1096
static char *openvzGetCapabilities(virConnectPtr conn) {
1097 1098 1099
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1100
    openvzDriverLock(driver);
1101
    ret = virCapabilitiesFormatXML(driver->caps);
1102
    openvzDriverUnlock(driver);
1103

1104
    return ret;
1105 1106
}

1107 1108
static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
    int got = 0;
1109 1110
    int veid;
    pid_t pid;
1111 1112
    int outfd = -1;
    int errfd = -1;
1113 1114
    int ret;
    char buf[32];
1115
    char *endptr;
1116
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
1117

1118 1119
    ret = virExec(conn, cmd, NULL, NULL,
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1120
    if(ret == -1) {
D
Daniel Veillard 已提交
1121
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
1122
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1123
        return -1;
1124 1125
    }

1126 1127 1128
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1129 1130 1131 1132 1133
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
1134 1135 1136
        ids[got] = veid;
        got ++;
    }
1137
    waitpid(pid, NULL, 0);
1138 1139 1140 1141

    return got;
}

1142
static int openvzNumDomains(virConnectPtr conn) {
1143
    struct openvz_driver *driver = conn->privateData;
1144 1145
    int nactive = 0, i;

1146 1147 1148
    openvzDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
1149
        if (virDomainIsActive(driver->domains.objs[i]))
1150
            nactive++;
1151 1152 1153
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    openvzDriverUnlock(driver);
1154

1155
    return nactive;
1156 1157 1158
}

static int openvzListDefinedDomains(virConnectPtr conn,
1159
                                    char **const names, int nnames) {
1160
    int got = 0;
1161 1162
    int veid, outfd = -1, errfd = -1, ret;
    pid_t pid;
1163
    char vpsname[32];
1164
    char buf[32];
1165
    char *endptr;
1166
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
1167 1168

    /* the -S options lists only stopped domains */
1169 1170
    ret = virExec(conn, cmd, NULL, NULL,
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1171
    if(ret == -1) {
D
Daniel Veillard 已提交
1172
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
1173
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1174
        return -1;
1175 1176
    }

1177 1178 1179
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1180 1181 1182 1183 1184
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
1185 1186 1187
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
        if (!(names[got] = strdup(vpsname)))
            goto no_memory;
1188 1189
        got ++;
    }
1190
    waitpid(pid, NULL, 0);
1191
    return got;
1192 1193 1194 1195 1196 1197

no_memory:
    openvzError(conn, VIR_ERR_NO_MEMORY, NULL);
    for ( ; got >= 0 ; got--)
        VIR_FREE(names[got]);
    return -1;
1198 1199
}

D
Daniel Veillard 已提交
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid) {
    int fd;
    char line[1024] ;
    unsigned long long usertime, systime, nicetime;
    int readvps = 0, ret;

/* read statistic from /proc/vz/vestat.
sample:
Version: 2.2
      VEID     user      nice     system     uptime                 idle   other..
        33       78         0       1330   59454597      142650441835148   other..
        55      178         0       5340   59424597      542650441835148   other..
*/

    if ((fd = open("/proc/vz/vestat", O_RDONLY)) == -1)
        return -1;

    /*search line with VEID=vpsid*/
    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
        if(ret <= 0)
            break;

        if (sscanf(line, "%d %llu %llu %llu",
                          &readvps, &usertime, &nicetime, &systime) != 4)
            continue;

        if (readvps == vpsid)
            break; /*found vpsid*/
    }

    close(fd);
    if (ret < 0)
        return -1;

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

    /* convert jiffies to nanoseconds */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + nicetime  + systime)
                                     / (unsigned long long)sysconf(_SC_CLK_TCK);

    return 0;
}

1245
static int openvzNumDefinedDomains(virConnectPtr conn) {
1246
    struct openvz_driver *driver =  conn->privateData;
1247 1248
    int ninactive = 0, i;

1249 1250 1251
    openvzDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
1252
        if (!virDomainIsActive(driver->domains.objs[i]))
1253
            ninactive++;
1254 1255 1256
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    openvzDriverUnlock(driver);
1257

1258
    return ninactive;
1259 1260 1261 1262 1263 1264 1265
}

static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    openvzOpen, /* open */
    openvzClose, /* close */
1266
    NULL, /* supports_feature */
1267
    openvzGetType, /* type */
1268
    openvzGetVersion, /* version */
1269 1270
    NULL, /* hostname */
    NULL, /* uri */
1271
    openvzGetMaxVCPUs, /* getMaxVcpus */
1272
    openvzGetNodeInfo, /* nodeGetInfo */
1273
    openvzGetCapabilities, /* getCapabilities */
1274 1275
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
1276
    openvzDomainCreateXML, /* domainCreateXML */
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
    openvzDomainLookupByID, /* domainLookupByID */
    openvzDomainLookupByUUID, /* domainLookupByUUID */
    openvzDomainLookupByName, /* domainLookupByName */
    NULL, /* domainSuspend */
    NULL, /* domainResume */
    openvzDomainShutdown, /* domainShutdown */
    openvzDomainReboot, /* domainReboot */
    openvzDomainShutdown, /* domainDestroy */
    openvzGetOSType, /* domainGetOSType */
    NULL, /* domainGetMaxMemory */
    NULL, /* domainSetMaxMemory */
    NULL, /* domainSetMemory */
    openvzDomainGetInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL, /* domainRestore */
    NULL, /* domainCoreDump */
1293
    openvzDomainSetVcpus, /* domainSetVcpus */
1294 1295
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
1296
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
1297
    openvzDomainDumpXML, /* domainDumpXML */
1298 1299 1300
    openvzListDefinedDomains, /* listDomains */
    openvzNumDefinedDomains, /* numOfDomains */
    openvzDomainCreate, /* domainCreate */
1301 1302
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
1303 1304
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
1305 1306
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
1307 1308 1309
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
1310 1311 1312 1313 1314
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
1315 1316
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1317
    NULL, /* nodeGetCellsFreeMemory */
1318
    NULL, /* nodeGetFreeMemory */
1319 1320
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
D
Daniel Veillard 已提交
1321 1322
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1323 1324 1325 1326 1327 1328 1329
};

int openvzRegister(void) {
    virRegisterDriver(&openvzDriver);
    return 0;
}