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 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 661
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml,
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
662
        goto cleanup;
663

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

777
    openvzSetProgramSentinal(progstart, vm->def->name);
778

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

872 873 874 875 876
    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;
877
    }
878

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

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

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

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

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

909 910 911 912
    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;
913
    }
914
    ret = 0;
915

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

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

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

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

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

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

951
cleanup:
952 953
    if (vm)
        virDomainObjUnlock(vm);
954
    return ret;
955 956
}

957 958 959 960 961 962 963 964 965 966 967 968 969 970
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");
}

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

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

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

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

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

cleanup:
1022 1023
    if (vm)
        virDomainObjUnlock(vm);
1024
    return ret;
1025 1026
}

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

    return 0;
1034 1035
}

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

    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")) {
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
        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;
1064

1065 1066
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1067

1068 1069 1070
    if (openvzExtractVersion(conn, driver) < 0)
        goto cleanup;

1071
    conn->privateData = driver;
1072

1073
    return VIR_DRV_OPEN_SUCCESS;
1074

1075 1076 1077
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1078
};
1079 1080

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

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

    return 0;
}

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

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

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

1102
    openvzDriverLock(driver);
1103
    ret = virCapabilitiesFormatXML(driver->caps);
1104
    openvzDriverUnlock(driver);
1105

1106
    return ret;
1107 1108
}

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

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

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

    return got;
}

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

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

1157
    return nactive;
1158 1159 1160
}

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

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

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

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

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

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

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

1260
    return ninactive;
1261 1262 1263 1264 1265 1266 1267
}

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

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