openvz_driver.c 37.1 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
#define VIR_FROM_THIS VIR_FROM_OPENVZ

63 64 65
#define OPENVZ_MAX_ARG 28
#define CMDBUF_LEN 1488
#define CMDOP_LEN 288
66

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

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

static void openvzDriverUnlock(struct openvz_driver *driver)
{
80
    virMutexUnlock(&driver->lock);
81 82
}

83 84
struct openvz_driver ovz_driver;

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

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

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

    if (vmdef == NULL){
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
110
                   "%s", _("Container is not defined"));
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
        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);
134

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

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

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

    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
}


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

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

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

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

188
cleanup:
189 190
    if (vm)
        virDomainObjUnlock(vm);
191 192 193
    return dom;
}

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

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

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

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

    if (!(ret = strdup(vm->def->os.type)))
218
        virReportOOMError(dom->conn);
219

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


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

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

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

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

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

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

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

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

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

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

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

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

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

293
    info->state = vm->state;
294

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

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

cleanup:
311 312
    if (vm)
        virDomainObjUnlock(vm);
313
    return ret;
314 315 316
}


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

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

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

332 333 334
    ret = virDomainDefFormat(dom->conn, vm->def, flags);

cleanup:
335 336
    if (vm)
        virDomainObjUnlock(vm);
337
    return ret;
338
}
339

340

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
/*
 * 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++;
    }
}
359 360

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

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

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

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

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

386 387
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;
388
    ret = 0;
389

390
cleanup:
391 392
    if (vm)
        virDomainObjUnlock(vm);
393
    return ret;
394 395
}

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

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

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

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

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

424
cleanup:
425 426
    if (vm)
        virDomainObjUnlock(vm);
427
    return ret;
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
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 {
453
        char *saveptr;
454 455 456 457
        char   *s;
        int     max = 0;

        /* get maximum interface number (actually, it is the last one) */
458
        for (s=strtok_r(temp, ";", &saveptr); s; s=strtok_r(NULL, ";", &saveptr)) {
459 460 461 462 463 464 465 466 467 468 469 470
            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 已提交
471 472
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
473 474
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
475 476
{
    int rc = 0, narg;
477
    const char *prog[OPENVZ_MAX_ARG];
478
    char macaddr[VIR_MAC_STRING_BUFLEN];
479 480
    unsigned char host_mac[VIR_MAC_BUFLEN];
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
481
    struct openvz_driver *driver =  conn->privateData;
482
    char *opt = NULL;
D
Daniel Veillard 已提交
483 484 485 486 487 488 489 490 491 492 493 494 495 496

#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 已提交
497
                    "%s", _("Container ID is not specified"));
D
Daniel Veillard 已提交
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
        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);
    }

514
    virFormatMacAddr(net->mac, macaddr);
515 516
    virCapabilitiesGenerateMac(driver->caps, host_mac);
    virFormatMacAddr(host_mac, host_macaddr);
517 518 519 520 521

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

        //--netif_add ifname[,mac,host_ifname,host_mac]
        ADD_ARG_LIT("--netif_add") ;
525 526 527 528 529

        /* 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 已提交
530
                       "%s", _("Could not generate eth name for container"));
531 532 533 534 535 536 537 538 539 540
           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 已提交
541
                           "%s", _("Could not generate veth name"));
542 543 544 545 546 547 548 549 550
               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 */
551
        virBufferVSprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
552 553 554 555 556 557 558

        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 */
559
            virBufferVSprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
560
            virBufferVSprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
D
Daniel Veillard 已提交
561
        }
562 563 564 565 566 567

        VIR_FREE(dev_name_ve);

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

D
Daniel Veillard 已提交
568
        ADD_ARG_LIT(opt) ;
569 570
        VIR_FREE(opt);
    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
D
Daniel Veillard 已提交
571 572 573 574 575 576 577 578 579 580
              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");
581
        if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
582 583 584 585 586 587 588 589 590 591 592 593
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
           rc = -1;
           goto exit;
        }
    }

 exit:
    cmdExecFree(prog);
    return rc;

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

#undef ADD_ARG_LIT
}

603 604 605 606 607 608 609 610 611

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
    unsigned int i;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
612
    struct openvz_driver *driver =  conn->privateData;
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 649 650 651

    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;
}


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

662
    openvzDriverLock(driver);
663 664
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml,
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
665
        goto cleanup;
666

667 668
    if (vmdef->os.init == NULL &&
        !(vmdef->os.init = strdup("/sbin/init"))) {
669
        goto cleanup;
670 671
    }

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

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

D
Daniel Veillard 已提交
689 690
    //TODO: set quota

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

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

703 704
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
705

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

714 715 716 717 718 719
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

cleanup:
    virDomainDefFree(vmdef);
720
    cmdExecFree(prog);
721 722 723
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
724 725 726 727
    return dom;
}

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

739
    openvzDriverLock(driver);
740 741
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml,
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
742
        goto cleanup;
743 744

    if (vmdef->os.init == NULL &&
745 746
        !(vmdef->os.init = strdup("/sbin/init")))
        goto cleanup;
747

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

759
    if (openvzDomainDefineCmd(conn, progcreate, OPENVZ_MAX_ARG, vm->def) < 0) {
760
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
761 762
                    "%s", _("Error creating command for container"));
        goto cleanup;
763 764
    }

765
    if (virRun(conn, progcreate, NULL) < 0) {
D
Daniel Veillard 已提交
766
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
767
               _("Could not exec %s"), VZCTL);
768
        goto cleanup;
769
    }
770

771
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
772
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
773
               "%s", _("Could not set UUID"));
774
        goto cleanup;
775 776
    }

777 778
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
779

780
    openvzSetProgramSentinal(progstart, vm->def->name);
781

782
    if (virRun(conn, progstart, NULL) < 0) {
D
Daniel Veillard 已提交
783
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
784
               _("Could not exec %s"), VZCTL);
785
        goto cleanup;
786
    }
787

788
    vm->pid = strtoI(vm->def->name);
789 790
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
791

792
    if (vm->def->vcpus > 0) {
793
        if (openvzDomainSetVcpusInternal(conn, vm, vm->def->vcpus) < 0) {
794
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
795
                    "%s", _("Could not set number of virtual cpu"));
796
            goto cleanup;
797 798 799
        }
    }

800 801 802 803 804 805
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

cleanup:
    virDomainDefFree(vmdef);
806
    cmdExecFree(progcreate);
807 808 809
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
810 811 812 813 814 815
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
816 817 818 819
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL };
    int ret = -1;
820

821
    openvzDriverLock(driver);
822
    vm = virDomainFindByName(&driver->domains, dom->name);
823 824
    openvzDriverUnlock(driver);

825
    if (!vm) {
D
Daniel Veillard 已提交
826
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
827 828
                    "%s", _("no domain with matching id"));
        goto cleanup;
829
    }
830

831
    if (vm->state != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
832
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
833 834
                    "%s", _("domain is not in shutoff state"));
        goto cleanup;
835 836
    }

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

844 845 846
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
847
    ret = 0;
848

849
cleanup:
850 851
    if (vm)
        virDomainObjUnlock(vm);
852
    return ret;
853 854 855 856 857
}

static int
openvzDomainUndefine(virDomainPtr dom)
{
858 859 860 861
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINAL, NULL };
    int ret = -1;
862

863
    openvzDriverLock(driver);
864
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
865
    if (!vm) {
866 867
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
868
    }
869

870
    if (virDomainIsActive(vm)) {
871 872
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete active domain"));
        goto cleanup;
873
    }
874

875 876 877 878 879
    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;
880
    }
881

882
    virDomainRemoveInactive(&driver->domains, vm);
883
    vm = NULL;
884
    ret = 0;
885

886
cleanup:
887 888 889
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
890
    return ret;
891 892
}

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

903
    openvzDriverLock(driver);
904
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
905 906
    openvzDriverUnlock(driver);

907
    if (!vm) {
908 909
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
910 911
    }

912 913 914 915
    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;
916
    }
917
    ret = 0;
918

919
cleanup:
920 921
    if (vm)
        virDomainObjUnlock(vm);
922
    return ret;
923 924 925 926 927
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
928 929
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
930
    char value[1024];
931
    int ret = -1;
932

933
    openvzDriverLock(driver);
934
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
935 936
    openvzDriverUnlock(driver);

937
    if (!vm) {
938 939 940
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                    "%s", _("no domain with matching uuid"));
        goto cleanup;
941 942
    }

943
    if (openvzReadConfigParam(strtoI(vm->def->name), "ONBOOT", value, sizeof(value)) < 0) {
944 945 946
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Could not read container config"));
        goto cleanup;
947 948 949 950
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
951
        *autostart = 1;
952
    ret = 0;
953

954
cleanup:
955 956
    if (vm)
        virDomainObjUnlock(vm);
957
    return ret;
958 959
}

960 961 962 963 964 965 966 967 968 969 970 971 972 973
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");
}

974 975 976 977
static int openvzDomainSetVcpusInternal(virConnectPtr conn, virDomainObjPtr vm,
    unsigned int nvcpus)
{
    char        str_vcpus[32];
978
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
979
                           "--cpus", str_vcpus, "--save", NULL };
980
    unsigned int pcpus;
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
    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;
1004

1005
    openvzDriverLock(driver);
1006
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1007 1008
    openvzDriverUnlock(driver);

1009
    if (!vm) {
1010
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
1011
                    "%s", _("no domain with matching uuid"));
1012
        goto cleanup;
1013 1014
    }

1015
    if (nvcpus <= 0) {
1016
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1017
                    "%s", _("VCPUs should be >= 1"));
1018
        goto cleanup;
1019 1020
    }

1021
    openvzDomainSetVcpusInternal(dom->conn, vm, nvcpus);
1022 1023 1024
    ret = 0;

cleanup:
1025 1026
    if (vm)
        virDomainObjUnlock(vm);
1027
    return ret;
1028 1029
}

1030
static int openvzProbe(void)
1031
{
1032 1033 1034 1035 1036
    if (geteuid() == 0 &&
        virFileExists("/proc/vz"))
        return 1;

    return 0;
1037 1038
}

1039
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
1040 1041
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED)
1042
{
1043
    struct openvz_driver *driver;
1044
    if (!openvzProbe())
1045
        return VIR_DRV_OPEN_DECLINED;
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056

    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")) {
1057 1058 1059 1060
        return VIR_DRV_OPEN_DECLINED;
    }

    if (VIR_ALLOC(driver) < 0) {
1061
        virReportOOMError(conn);
1062 1063 1064 1065 1066
        return VIR_DRV_OPEN_ERROR;
    }

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

1068 1069
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1070

1071 1072 1073
    if (openvzExtractVersion(conn, driver) < 0)
        goto cleanup;

1074
    conn->privateData = driver;
1075

1076
    return VIR_DRV_OPEN_SUCCESS;
1077

1078 1079 1080
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1081
};
1082 1083

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

1086
    openvzFreeDriver(driver);
1087 1088 1089 1090 1091 1092 1093 1094 1095
    conn->privateData = NULL;

    return 0;
}

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

1096 1097 1098 1099 1100
static int openvzGetNodeInfo(virConnectPtr conn,
                             virNodeInfoPtr nodeinfo) {
    return virNodeInfoPopulate(conn, nodeinfo);
}

1101
static char *openvzGetCapabilities(virConnectPtr conn) {
1102 1103 1104
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1105
    openvzDriverLock(driver);
1106
    ret = virCapabilitiesFormatXML(driver->caps);
1107
    openvzDriverUnlock(driver);
1108

1109
    return ret;
1110 1111
}

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

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

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

    return got;
}

1147
static int openvzNumDomains(virConnectPtr conn) {
1148
    struct openvz_driver *driver = conn->privateData;
1149 1150
    int nactive = 0, i;

1151 1152 1153
    openvzDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
1154
        if (virDomainIsActive(driver->domains.objs[i]))
1155
            nactive++;
1156 1157 1158
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    openvzDriverUnlock(driver);
1159

1160
    return nactive;
1161 1162 1163
}

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

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

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

no_memory:
1199
    virReportOOMError(conn);
1200 1201 1202
    for ( ; got >= 0 ; got--)
        VIR_FREE(names[got]);
    return -1;
1203 1204
}

D
Daniel Veillard 已提交
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 1245 1246 1247 1248 1249
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;
}

1250
static int openvzNumDefinedDomains(virConnectPtr conn) {
1251
    struct openvz_driver *driver =  conn->privateData;
1252 1253
    int ninactive = 0, i;

1254 1255 1256
    openvzDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
1257
        if (!virDomainIsActive(driver->domains.objs[i]))
1258
            ninactive++;
1259 1260 1261
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    openvzDriverUnlock(driver);
1262

1263
    return ninactive;
1264 1265 1266 1267 1268 1269 1270
}

static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    openvzOpen, /* open */
    openvzClose, /* close */
1271
    NULL, /* supports_feature */
1272
    openvzGetType, /* type */
1273
    openvzGetVersion, /* version */
1274 1275
    NULL, /* hostname */
    NULL, /* uri */
1276
    openvzGetMaxVCPUs, /* getMaxVcpus */
1277
    openvzGetNodeInfo, /* nodeGetInfo */
1278
    openvzGetCapabilities, /* getCapabilities */
1279 1280
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
1281
    openvzDomainCreateXML, /* domainCreateXML */
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
    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 */
1298
    openvzDomainSetVcpus, /* domainSetVcpus */
1299 1300
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
1301
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
1302
    openvzDomainDumpXML, /* domainDumpXML */
1303 1304 1305
    openvzListDefinedDomains, /* listDomains */
    openvzNumDefinedDomains, /* numOfDomains */
    openvzDomainCreate, /* domainCreate */
1306 1307
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
1308 1309
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
1310 1311
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
1312 1313 1314
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
1315 1316 1317 1318 1319
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
1320 1321
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1322
    NULL, /* nodeGetCellsFreeMemory */
1323
    NULL, /* nodeGetFreeMemory */
1324 1325
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
D
Daniel Veillard 已提交
1326 1327
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1328 1329 1330 1331 1332 1333
};

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