openvz_driver.c 23.2 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 50 51
 */

#ifdef WITH_OPENVZ

#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>

52
#include "internal.h"
53
#include "openvz_driver.h"
54 55
#include "event.h"
#include "buf.h"
56
#include "util.h"
57
#include "openvz_conf.h"
58
#include "nodeinfo.h"
59
#include "memory.h"
60

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

static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, int id);
static char *openvzGetOSType(virDomainPtr dom);
67
static int openvzGetNodeInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo);
68 69 70 71 72 73
static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid);
static virDomainPtr openvzDomainLookupByName(virConnectPtr conn, const char *name);
static int openvzDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info);
static int openvzDomainShutdown(virDomainPtr dom);
static int openvzDomainReboot(virDomainPtr dom, unsigned int flags);
static int openvzDomainCreate(virDomainPtr dom);
74 75 76 77
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
                                 xmlURIPtr uri,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED);
78 79 80 81 82 83 84 85 86 87
static int openvzClose(virConnectPtr conn);
static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED);
static int openvzListDomains(virConnectPtr conn, int *ids, int nids);
static int openvzNumDomains(virConnectPtr conn);
static int openvzListDefinedDomains(virConnectPtr conn, char **const names, int nnames);
static int openvzNumDefinedDomains(virConnectPtr conn);
static int openvzStartup(void);
static int openvzShutdown(void);
static int openvzReload(void);
static int openvzActive(void);
88 89

static virDomainPtr openvzDomainDefineXML(virConnectPtr conn, const char *xml);
90
static virDomainPtr openvzDomainCreateLinux(virConnectPtr conn, const char *xml,
91 92 93 94 95 96
        unsigned int flags ATTRIBUTE_UNUSED);

static int openvzDomainUndefine(virDomainPtr dom);
static int convCmdbufExec(char cmdbuf[], char *cmdExec[]);
static void cmdExecFree(char *cmdExec[]);

97 98
struct openvz_driver ovz_driver;

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
static int convCmdbufExec(char cmdbuf[], char *cmdExec[])
{
    int i=0, limit = OPENVZ_MAX_ARG - 1;
    char cmdWord[CMDOP_LEN];
    while(*cmdbuf)
    {
        if(i >= limit)
        {
            cmdExec[i] = NULL;
            return -1;
        }
        sscanf(cmdbuf, "%s", cmdWord);
        cmdbuf += strlen(cmdWord);
        while(*cmdbuf == ' ') cmdbuf++;
        cmdExec[i++] = strdup(cmdWord);
    }
    cmdExec[i] = NULL;
    return i;
}

static void cmdExecFree(char *cmdExec[])
{
    int i=-1;
    while(cmdExec[++i])
    {
124
        VIR_FREE(cmdExec[i]);
125 126 127
    }
}

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
*/
static int openvzDomainDefineCmd(virConnectPtr conn,
                                 char *args[],
                                 int maxarg,
                                 struct openvz_vm_def *vmdef)
{
    int narg;

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

    if (vmdef == NULL){
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                   _("Container is not defined"));
        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);

    if ((vmdef->fs.tmpl && *(vmdef->fs.tmpl))) {
        ADD_ARG_LIT("--ostemplate");
        ADD_ARG_LIT(vmdef->fs.tmpl);
    }
    if ((vmdef->profile && *(vmdef->profile))) {
        ADD_ARG_LIT("--config");
        ADD_ARG_LIT(vmdef->profile);
    }
    if ((vmdef->net.ips->ip && *(vmdef->net.ips->ip))) {
        ADD_ARG_LIT("--ipadd");
        ADD_ARG_LIT(vmdef->net.ips->ip);
    }
    if ((vmdef->net.hostname && *(vmdef->net.hostname))) {
        ADD_ARG_LIT("--hostname");
        ADD_ARG_LIT(vmdef->net.hostname);
    }

    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
}


197 198 199
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
                                   int id) {
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
200
    struct openvz_vm *vm;
201 202
    virDomainPtr dom;

203 204 205 206 207 208 209 210 211 212 213
    vm = openvzFindVMByID(driver, id);

    if (!vm) { /*try to find by name*/
        char name[OPENVZ_NAME_MAX];
        if (snprintf(name, OPENVZ_NAME_MAX, "%d",id) >= OPENVZ_NAME_MAX) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Too long domain name"));
            return NULL;
        }
        vm = openvzFindVMByName(driver, name);
    }

214
    if (!vm) {
215
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
216 217 218 219 220
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
221
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
222 223 224 225 226 227 228
        return NULL;
    }

    dom->id = vm->vpsid;
    return dom;
}

229
static char *openvzGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
230 231
{
    /* OpenVZ runs on Linux and runs only Linux */
232
    return strdup("linux");
233 234 235 236 237 238 239 240 241 242
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
                                     const unsigned char *uuid) {
    struct  openvz_driver *driver = (struct openvz_driver *)conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, uuid);
    virDomainPtr dom;

    if (!vm) {
243
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
244 245 246 247 248
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
249
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
250 251 252 253 254 255 256 257 258 259 260 261 262 263
        return NULL;
    }

    dom->id = vm->vpsid;
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
                                     const char *name) {
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
    struct openvz_vm *vm = openvzFindVMByName(driver, name);
    virDomainPtr dom;

    if (!vm) {
264
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
265 266 267 268 269
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
270
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
271 272 273 274 275 276 277 278 279 280 281
        return NULL;
    }

    dom->id = vm->vpsid;
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
                       virDomainInfoPtr info) {
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
282

283
    if (!vm) {
D
Daniel Veillard 已提交
284
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
285
              _("no domain with matching uuid"));
286 287 288 289 290 291
        return -1;
    }

    info->state = vm->status;

    /* TODO These need to be calculated differently for OpenVZ */
292
    //info->cpuTime =
293 294 295 296 297 298 299 300 301
    //info->maxMem = vm->def->maxmem;
    //info->memory = vm->def->memory;
    //info->nrVirtCpu = vm->def->vcpus;
    return 0;
}

static int openvzDomainShutdown(virDomainPtr dom) {
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
    struct openvz_vm *vm = openvzFindVMByID(driver, dom->id);
302
    const char *prog[] = {VZCTL, "--quiet", "stop", vm->vmdef->name, NULL};
303 304

    if (!vm) {
D
Daniel Veillard 已提交
305
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
306
              _("no domain with matching id"));
307 308
        return -1;
    }
309

310
    if (vm->status != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
311
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
312
              _("domain is not in running state"));
313 314
        return -1;
    }
315

316
    if (virRun(dom->conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
317
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
318
              _("Could not exec %s"), VZCTL);
319 320
        return -1;
    }
321

322 323 324 325
    vm->vpsid = -1;
    vm->status = VIR_DOMAIN_SHUTOFF;
    ovz_driver.num_inactive ++;
    ovz_driver.num_active --;
326

327
    return 0;
328 329
}

330 331
static int openvzDomainReboot(virDomainPtr dom,
                              unsigned int flags ATTRIBUTE_UNUSED) {
332 333
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
    struct openvz_vm *vm = openvzFindVMByID(driver, dom->id);
334
    const char *prog[] = {VZCTL, "--quiet", "restart", vm->vmdef->name, NULL};
335 336

    if (!vm) {
D
Daniel Veillard 已提交
337
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
338
              _("no domain with matching id"));
339 340
        return -1;
    }
341

342
    if (vm->status != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
343
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
344
              _("domain is not in running state"));
345 346
        return -1;
    }
347

348
    if (virRun(dom->conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
349
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
350
               _("Could not exec %s"), VZCTL);
351 352
        return -1;
    }
353

354
    return 0;
355 356
}

357 358 359 360 361 362
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
    struct openvz_vm_def *vmdef = NULL;
    struct openvz_vm *vm = NULL;
363 364 365
    virDomainPtr dom = NULL;
    char *prog[OPENVZ_MAX_ARG];
    prog[0] = NULL;
366

367 368
    if ((vmdef = openvzParseVMDef(conn, xml, NULL)) == NULL)
        return NULL;
369 370 371

    vm = openvzFindVMByID(driver, strtoI(vmdef->name));
    if (vm) {
372 373
        openvzLog(OPENVZ_ERR, _("Already an OPENVZ VM active with the id '%s'"),
                  vmdef->name);
374
        return NULL;
375 376 377
    }
    if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) {
        openvzFreeVMDef(vmdef);
378
        openvzLog(OPENVZ_ERR, "%s", _("Error creating OPENVZ VM"));
379 380
    }

381 382 383 384
    if (openvzDomainDefineCmd(conn, prog, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Error creating command for container"));
        goto exit;
385 386
    }

387
    if (virRun(conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
388
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
389
               _("Could not exec %s"), VZCTL);
390
        goto exit;
391
    }
392

393 394 395
    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (dom)
        dom->id = vm->vpsid;
396 397
 exit:
    cmdExecFree(prog);
398 399 400 401 402 403 404 405 406
    return dom;
}

static virDomainPtr
openvzDomainCreateLinux(virConnectPtr conn, const char *xml,
                        unsigned int flags ATTRIBUTE_UNUSED)
{
    struct openvz_vm_def *vmdef = NULL;
    struct openvz_vm *vm = NULL;
407
    virDomainPtr dom = NULL;
408
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
409 410 411
    const char *progstart[] = {VZCTL, "--quiet", "start", NULL, NULL};
    char *progcreate[OPENVZ_MAX_ARG];
    progcreate[0] = NULL;
412 413 414 415 416 417 418

    if (!(vmdef = openvzParseVMDef(conn, xml, NULL)))
        return NULL;

    vm = openvzFindVMByID(driver, strtoI(vmdef->name));
    if (vm) {
        openvzFreeVMDef(vmdef);
419 420
        openvzLog(OPENVZ_ERR,
                  _("Already an OPENVZ VM defined with the id '%d'"),
421 422 423 424
                strtoI(vmdef->name));
        return NULL;
    }
    if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) {
425
        openvzLog(OPENVZ_ERR, "%s", _("Error creating OPENVZ VM"));
426 427 428
        return NULL;
    }

429 430 431 432
    if (openvzDomainDefineCmd(conn, progcreate, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Error creating command for container"));
        goto exit;
433 434
    }

435
    if (virRun(conn, (char **)progcreate, NULL) < 0) {
D
Daniel Veillard 已提交
436
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
437
               _("Could not exec %s"), VZCTL);
438
        goto exit;
439
    }
440

441
    progstart[3] = vmdef->name;
442

443
    if (virRun(conn, (char **)progstart, NULL) < 0) {
D
Daniel Veillard 已提交
444
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
445
               _("Could not exec %s"), VZCTL);
446
        goto exit;
447
    }
448

449 450 451 452 453 454 455 456
    sscanf(vmdef->name, "%d", &vm->vpsid);
    vm->status = VIR_DOMAIN_RUNNING;
    ovz_driver.num_inactive--;
    ovz_driver.num_active++;

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (dom)
        dom->id = vm->vpsid;
457 458
 exit:
    cmdExecFree(progcreate);
459 460 461 462 463 464
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
465
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
466
    struct openvz_vm *vm = openvzFindVMByName(driver, dom->name);
467
    const char *prog[] = {VZCTL, "--quiet", "start", vm->vmdef->name, NULL };
468 469

    if (!vm) {
D
Daniel Veillard 已提交
470
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
471
              _("no domain with matching id"));
472 473
        return -1;
    }
474

475
    if (vm->status != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
476
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
477
              _("domain is not in shutoff state"));
478 479 480
        return -1;
    }

481
    if (virRun(dom->conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
482
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
483
               _("Could not exec %s"), VZCTL);
484 485
        return -1;
    }
486

487
    sscanf(vm->vmdef->name, "%d", &vm->vpsid);
488 489 490
    vm->status = VIR_DOMAIN_RUNNING;
    ovz_driver.num_inactive --;
    ovz_driver.num_active ++;
491

492
    return 0;
493 494 495 496 497 498 499 500
}

static int
openvzDomainUndefine(virDomainPtr dom)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
501
    const char *prog[] = { VZCTL, "--quiet", "destroy", vm->vmdef->name, NULL };
502 503

    if (!vm) {
D
Daniel Veillard 已提交
504
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
505 506
        return -1;
    }
507

508
    if (openvzIsActiveVM(vm)) {
D
Daniel Veillard 已提交
509
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("cannot delete active domain"));
510 511
        return -1;
    }
512

513
    if (virRun(conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
514
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
515
               _("Could not exec %s"), VZCTL);
516 517
        return -1;
    }
518

519
    openvzRemoveInactiveVM(driver, vm);
520
    return 0;
521 522
}

523 524 525 526 527 528
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
529
    const char *prog[] = { VZCTL, "--quiet", "set", vm->vmdef->name,
D
Daniel Veillard 已提交
530
                           "--onboot", autostart ? "yes" : "no",
531 532 533
                           "--save", NULL };

    if (!vm) {
D
Daniel Veillard 已提交
534
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
535 536 537 538
        return -1;
    }

    if (virRun(conn, (char **)prog, NULL) < 0) {
D
Daniel Veillard 已提交
539
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL);
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
        return -1;
    }

    return 0;
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
    char value[1024];

    if (!vm) {
D
Daniel Veillard 已提交
555
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
556 557 558 559
        return -1;
    }

    if (openvzReadConfigParam(vm->vpsid , "ONBOOT", value, sizeof(value)) < 0) {
D
Daniel Veillard 已提交
560
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Cound not read container config"));
561 562 563 564 565
        return -1;
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
566
        *autostart = 1;
567 568 569 570

    return 0;
}

571 572 573 574
static const char *openvzProbe(void)
{
#ifdef __linux__
    if ((getuid() == 0) && (virFileExists("/proc/vz")))
D
Daniel Veillard 已提交
575
        return("openvz:///system");
576 577 578 579
#endif
    return(NULL);
}

580
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
                                 xmlURIPtr uri,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED)
{
   struct openvz_vm *vms;

    /*Just check if the user is root. Nothing really to open for OpenVZ */
   if (getuid()) { // OpenVZ tools can only be used by r00t
           return VIR_DRV_OPEN_DECLINED;
   } else {
       if (uri == NULL || uri->scheme == NULL || uri->path == NULL)
                   return VIR_DRV_OPEN_DECLINED;
       if (STRNEQ (uri->scheme, "openvz"))
                   return VIR_DRV_OPEN_DECLINED;
       if (STRNEQ (uri->path, "/system"))
                   return VIR_DRV_OPEN_DECLINED;
   }
598
    /* See if we are running an OpenVZ enabled kernel */
599 600 601 602
   if(access("/proc/vz/veinfo", F_OK) == -1 ||
               access("/proc/user_beancounters", F_OK) == -1) {
       return VIR_DRV_OPEN_DECLINED;
   }
603

604
   conn->privateData = &ovz_driver;
605

606 607 608
   virStateInitialize();
   vms = openvzGetVPSInfo(conn);
   ovz_driver.vms = vms;
609

610 611
   return VIR_DRV_OPEN_SUCCESS;
};
612 613

static int openvzClose(virConnectPtr conn) {
614

615 616 617 618 619 620 621 622 623 624 625 626 627
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
    struct openvz_vm *vm = driver->vms;

    while(vm) {
        openvzFreeVMDef(vm->vmdef);
        vm = vm->next;
    }
    vm = driver->vms;
    while (vm) {
        struct openvz_vm *prev = vm;
        vm = vm->next;
        free(prev);
    }
628

629 630 631 632 633 634 635 636 637
    conn->privateData = NULL;

    return 0;
}

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

638 639 640 641 642
static int openvzGetNodeInfo(virConnectPtr conn,
                             virNodeInfoPtr nodeinfo) {
    return virNodeInfoPopulate(conn, nodeinfo);
}

643 644
static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
    int got = 0;
645 646 647 648
    int veid, pid, outfd, errfd;
    int ret;
    char buf[32];
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
649

650
    ret = virExec(conn, (char **)cmd, &pid, -1, &outfd, &errfd);
651
    if(ret == -1) {
D
Daniel Veillard 已提交
652
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
653
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
654
        return -1;
655 656
    }

657 658 659 660
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
        sscanf(buf, "%d", &veid);
661 662 663
        ids[got] = veid;
        got ++;
    }
664
    waitpid(pid, NULL, 0);
665 666 667 668

    return got;
}

669
static int openvzNumDomains(virConnectPtr conn ATTRIBUTE_UNUSED) {
670 671 672 673 674 675
    return ovz_driver.num_active;
}

static int openvzListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
    int got = 0;
676
    int veid, pid, outfd, errfd, ret;
677
    char vpsname[OPENVZ_NAME_MAX];
678
    char buf[32];
679
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
680 681

    /* the -S options lists only stopped domains */
682
    ret = virExec(conn, (char **)cmd, &pid, -1, &outfd, &errfd);
683
    if(ret == -1) {
D
Daniel Veillard 已提交
684
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
685
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
686
        return -1;
687 688
    }

689 690 691 692
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
        sscanf(buf, "%d\n", &veid);
693 694 695 696
        sprintf(vpsname, "%d", veid);
        names[got] = strdup(vpsname);
        got ++;
    }
697
    waitpid(pid, NULL, 0);
698 699 700
    return got;
}

701
static int openvzNumDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED) {
702
    return ovz_driver.num_inactive;
703 704 705 706
}

static int openvzStartup(void) {
    openvzAssignUUIDs();
707

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
    return 0;
}

static int openvzShutdown(void) {

    return 0;
}

static int openvzReload(void) {

    return 0;
}

static int openvzActive(void) {

    return 1;
}

static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    LIBVIR_VERSION_NUMBER,
730
    openvzProbe, /* probe */
731 732
    openvzOpen, /* open */
    openvzClose, /* close */
733
    NULL, /* supports_feature */
734 735 736 737 738
    openvzGetType, /* type */
    NULL, /* version */
    NULL, /* hostname */
    NULL, /* uri */
    NULL, /* getMaxVcpus */
739
    openvzGetNodeInfo, /* nodeGetInfo */
740 741 742
    NULL, /* getCapabilities */
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
743
    openvzDomainCreateLinux, /* domainCreateLinux */
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
    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 */
    NULL, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
    NULL, /* domainGetMaxVcpus */
    NULL, /* domainDumpXML */
    openvzListDefinedDomains, /* listDomains */
    openvzNumDefinedDomains, /* numOfDomains */
    openvzDomainCreate, /* domainCreate */
768 769
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
770 771
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
772 773
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
774 775 776
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
777 778 779 780 781
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
782 783
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
784
    NULL, /* nodeGetCellsFreeMemory */
785
    NULL, /* nodeGetFreeMemory */
786 787 788 789 790 791 792
};

static virStateDriver openvzStateDriver = {
    openvzStartup,
    openvzShutdown,
    openvzReload,
    openvzActive,
D
Daniel P. Berrange 已提交
793
    NULL, /* sigHandler */
794 795 796 797 798 799 800 801 802
};

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

#endif /* WITH_OPENVZ */