openvz_driver.c 29.4 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 "internal.h"
51
#include "openvz_driver.h"
52 53
#include "event.h"
#include "buf.h"
54
#include "util.h"
55
#include "openvz_conf.h"
56
#include "nodeinfo.h"
57
#include "memory.h"
58

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

static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, int id);
static char *openvzGetOSType(virDomainPtr dom);
65
static int openvzGetNodeInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo);
66 67 68 69 70 71
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);
72 73 74 75
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
                                 xmlURIPtr uri,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED);
76 77 78 79 80 81 82 83 84 85
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);
86 87

static virDomainPtr openvzDomainDefineXML(virConnectPtr conn, const char *xml);
88
static virDomainPtr openvzDomainCreateLinux(virConnectPtr conn, const char *xml,
89 90 91
        unsigned int flags ATTRIBUTE_UNUSED);

static int openvzDomainUndefine(virDomainPtr dom);
92
static void cmdExecFree(const char *cmdExec[]);
93

D
Daniel Veillard 已提交
94
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
95 96 97
static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type);
static int openvzDomainGetMaxVcpus(virDomainPtr dom);
static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus);
D
Daniel Veillard 已提交
98

99 100
struct openvz_driver ovz_driver;

101
static void cmdExecFree(const char *cmdExec[])
102 103 104 105
{
    int i=-1;
    while(cmdExec[++i])
    {
106
        VIR_FREE(cmdExec[i]);
107 108 109
    }
}

110 111 112 113 114
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
*/
static int openvzDomainDefineCmd(virConnectPtr conn,
115
                                 const char *args[],
116 117 118 119 120 121 122 123 124 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
                                 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);
    }

    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
}


171 172 173
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
                                   int id) {
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
174
    struct openvz_vm *vm;
175 176
    virDomainPtr dom;

177 178
    vm = openvzFindVMByID(driver, id);

179
    if (!vm) {
180
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
181 182 183 184 185
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
186
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
187 188 189 190 191 192 193
        return NULL;
    }

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

194
static char *openvzGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
195 196
{
    /* OpenVZ runs on Linux and runs only Linux */
197
    return strdup("linux");
198 199 200 201 202 203 204 205 206 207
}


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) {
208
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
209 210 211 212 213
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
214
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
215 216 217 218 219 220 221 222 223 224 225 226 227 228
        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) {
229
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
230 231 232 233 234
        return NULL;
    }

    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (!dom) {
D
Daniel Veillard 已提交
235
        openvzError(conn, VIR_ERR_NO_MEMORY, _("virDomainPtr"));
236 237 238 239 240 241 242 243 244 245 246
        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);
247

248
    if (!vm) {
D
Daniel Veillard 已提交
249
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
250
              _("no domain with matching uuid"));
251 252 253 254 255
        return -1;
    }

    info->state = vm->status;

D
Daniel Veillard 已提交
256 257 258 259 260 261 262 263 264 265
    if (!openvzIsActiveVM(vm)) {
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
            openvzError(dom->conn, VIR_ERR_OPERATION_FAILED,
                            _("cannot read cputime for domain %d"), dom->id);
            return -1;
        }
    }

266
    /* TODO These need to be calculated differently for OpenVZ */
267
    //info->cpuTime =
268 269
    //info->maxMem = vm->def->maxmem;
    //info->memory = vm->def->memory;
270
    info->nrVirtCpu = vm->vmdef->vcpus;
271 272 273 274 275
    return 0;
}

static int openvzDomainShutdown(virDomainPtr dom) {
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
276
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
277
    const char *prog[] = {VZCTL, "--quiet", "stop", vm->vmdef->name, NULL};
278 279

    if (!vm) {
D
Daniel Veillard 已提交
280
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
281
              _("no domain with matching id"));
282 283
        return -1;
    }
284

285
    if (vm->status != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
286
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
287
              _("domain is not in running state"));
288 289
        return -1;
    }
290

291
    if (virRun(dom->conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
292
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
293
              _("Could not exec %s"), VZCTL);
294 295
        return -1;
    }
296

297 298 299 300
    vm->vpsid = -1;
    vm->status = VIR_DOMAIN_SHUTOFF;
    ovz_driver.num_inactive ++;
    ovz_driver.num_active --;
301

302
    return 0;
303 304
}

305 306
static int openvzDomainReboot(virDomainPtr dom,
                              unsigned int flags ATTRIBUTE_UNUSED) {
307
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
308
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
309
    const char *prog[] = {VZCTL, "--quiet", "restart", vm->vmdef->name, NULL};
310 311

    if (!vm) {
D
Daniel Veillard 已提交
312
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
313
              _("no domain with matching id"));
314 315
        return -1;
    }
316

317
    if (vm->status != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
318
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
319
              _("domain is not in running state"));
320 321
        return -1;
    }
322

323
    if (virRun(dom->conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
324
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
325
               _("Could not exec %s"), VZCTL);
326 327
        return -1;
    }
328

329
    return 0;
330 331
}

D
Daniel Veillard 已提交
332 333 334 335 336
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
                        virDomainNetDefPtr net)
{
    int rc = 0, narg;
337
    const char *prog[OPENVZ_MAX_ARG];
D
Daniel Veillard 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    char *mac = NULL;

#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,
                    _("Container ID is not specified"));
        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);
    }

    if (openvzCheckEmptyMac(net->mac) > 0)
          mac = openvzMacToString(net->mac);

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
           net->data.bridge.brname != NULL) {
        char opt[1024];
        //--netif_add ifname[,mac,host_ifname,host_mac]
        ADD_ARG_LIT("--netif_add") ;
        strncpy(opt, net->data.bridge.brname, 256);
        if (mac != NULL) {
            strcat(opt, ",");
            strcat(opt, mac);
        }
        ADD_ARG_LIT(opt) ;
    }else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
              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");
395
        if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
           rc = -1;
           goto exit;
        }
    }

    if (net->next != NULL)
       if (openvzDomainSetNetwork(conn, vpsid, net->next) < 0) {
          rc = -1;
          goto exit;
       }

 exit:
    cmdExecFree(prog);
    VIR_FREE(mac);
    return rc;

 no_memory:
    openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not put argument to %s"), VZCTL);
    cmdExecFree(prog);
    VIR_FREE(mac);
    return -1;

#undef ADD_ARG_LIT
}

424 425 426 427 428 429
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;
430
    virDomainPtr dom = NULL;
431
    const char *prog[OPENVZ_MAX_ARG];
432
    prog[0] = NULL;
433

434 435
    if ((vmdef = openvzParseVMDef(conn, xml, NULL)) == NULL)
        return NULL;
436

437
    vm = openvzFindVMByName(driver, vmdef->name);
438
    if (vm) {
439 440
        openvzLog(OPENVZ_ERR, _("Already an OPENVZ VM active with the id '%s'"),
                  vmdef->name);
441
        return NULL;
442 443 444
    }
    if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) {
        openvzFreeVMDef(vmdef);
445
        openvzLog(OPENVZ_ERR, "%s", _("Error creating OPENVZ VM"));
446 447
    }

448 449 450 451
    if (openvzDomainDefineCmd(conn, prog, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Error creating command for container"));
        goto exit;
452 453
    }

D
Daniel Veillard 已提交
454 455
    //TODO: set quota

456
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
457
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
458
               _("Could not exec %s"), VZCTL);
459
        goto exit;
460
    }
461

462 463 464 465 466 467
    if (openvzSetDefinedUUID(strtoI(vmdef->name), vmdef->uuid) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
               _("Could not set UUID"));
        goto exit;
    }

468 469 470
    dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid);
    if (dom)
        dom->id = vm->vpsid;
D
Daniel Veillard 已提交
471 472 473 474 475 476 477

    if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->net) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                  _("Could not configure network"));
        goto exit;
    }

478 479 480 481 482 483 484 485
    if (vmdef->vcpus > 0) {
        if (openvzDomainSetVcpus(dom, vmdef->vcpus) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                     _("Could not set number of virtual cpu"));
             goto exit;
        }
    }

D
Daniel Veillard 已提交
486
    exit:
487
    cmdExecFree(prog);
488 489 490 491 492 493 494 495 496
    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;
497
    virDomainPtr dom = NULL;
498
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
499
    const char *progstart[] = {VZCTL, "--quiet", "start", NULL, NULL};
500
    const char *progcreate[OPENVZ_MAX_ARG];
501
    progcreate[0] = NULL;
502 503 504 505

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

506
    vm = openvzFindVMByName(driver, vmdef->name);
507 508
    if (vm) {
        openvzFreeVMDef(vmdef);
509 510
        openvzLog(OPENVZ_ERR,
                  _("Already an OPENVZ VM defined with the id '%d'"),
511 512 513 514
                strtoI(vmdef->name));
        return NULL;
    }
    if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) {
515
        openvzLog(OPENVZ_ERR, "%s", _("Error creating OPENVZ VM"));
516 517 518
        return NULL;
    }

519 520 521 522
    if (openvzDomainDefineCmd(conn, progcreate, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Error creating command for container"));
        goto exit;
523 524
    }

525
    if (virRun(conn, progcreate, NULL) < 0) {
D
Daniel Veillard 已提交
526
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
527
               _("Could not exec %s"), VZCTL);
528
        goto exit;
529
    }
530

531 532 533 534 535 536
    if (openvzSetDefinedUUID(strtoI(vmdef->name), vmdef->uuid) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
               _("Could not set UUID"));
        goto exit;
    }

D
Daniel Veillard 已提交
537 538 539 540 541 542
    if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->net) < 0) {
       openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                  _("Could not configure network"));
        goto exit;
    }

543
    progstart[3] = vmdef->name;
544

545
    if (virRun(conn, progstart, NULL) < 0) {
D
Daniel Veillard 已提交
546
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
547
               _("Could not exec %s"), VZCTL);
548
        goto exit;
549
    }
550

551
    vm->vpsid = strtoI(vmdef->name);
552 553 554 555 556 557 558
    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;
559 560 561 562 563 564 565 566 567

    if (vmdef->vcpus > 0) {
        if (openvzDomainSetVcpus(dom, vmdef->vcpus) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                     _("Could not set number of virtual cpu"));
             goto exit;
        }
    }

568 569
 exit:
    cmdExecFree(progcreate);
570 571 572 573 574 575
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
576
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
577
    struct openvz_vm *vm = openvzFindVMByName(driver, dom->name);
578
    const char *prog[] = {VZCTL, "--quiet", "start", vm->vmdef->name, NULL };
579 580

    if (!vm) {
D
Daniel Veillard 已提交
581
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
582
              _("no domain with matching id"));
583 584
        return -1;
    }
585

586
    if (vm->status != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
587
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
588
              _("domain is not in shutoff state"));
589 590 591
        return -1;
    }

592
    if (virRun(dom->conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
593
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
594
               _("Could not exec %s"), VZCTL);
595 596
        return -1;
    }
597

598
    vm->vpsid = strtoI(vm->vmdef->name);
599 600 601
    vm->status = VIR_DOMAIN_RUNNING;
    ovz_driver.num_inactive --;
    ovz_driver.num_active ++;
602

603
    return 0;
604 605 606 607 608 609 610 611
}

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);
612
    const char *prog[] = { VZCTL, "--quiet", "destroy", vm->vmdef->name, NULL };
613 614

    if (!vm) {
D
Daniel Veillard 已提交
615
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
616 617
        return -1;
    }
618

619
    if (openvzIsActiveVM(vm)) {
D
Daniel Veillard 已提交
620
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("cannot delete active domain"));
621 622
        return -1;
    }
623

624
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
625
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
626
               _("Could not exec %s"), VZCTL);
627 628
        return -1;
    }
629

630
    openvzRemoveInactiveVM(driver, vm);
631
    return 0;
632 633
}

634 635 636 637 638 639
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);
640
    const char *prog[] = { VZCTL, "--quiet", "set", vm->vmdef->name,
D
Daniel Veillard 已提交
641
                           "--onboot", autostart ? "yes" : "no",
642 643 644
                           "--save", NULL };

    if (!vm) {
D
Daniel Veillard 已提交
645
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
646 647 648
        return -1;
    }

649
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
650
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL);
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
        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 已提交
666
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, _("no domain with matching uuid"));
667 668 669
        return -1;
    }

670
    if (openvzReadConfigParam(strtoI(vm->vmdef->name), "ONBOOT", value, sizeof(value)) < 0) {
671
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Could not read container config"));
672 673 674 675 676
        return -1;
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
677
        *autostart = 1;
678 679 680 681

    return 0;
}

682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
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");
}

static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
    struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid);
    char   str_vcpus[32];
    const char *prog[] = { VZCTL, "--quiet", "set", vm->vmdef->name,
                           "--cpus", str_vcpus, "--save", NULL };
    snprintf(str_vcpus, 31, "%d", nvcpus);
    str_vcpus[31] = '\0';

    if (nvcpus <= 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                         _("VCPUs should be >= 1"));
        return -1;
    }

    if (!vm) {
        openvzError(conn, VIR_ERR_INVALID_DOMAIN,
                         _("no domain with matching uuid"));
        return -1;
    }

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

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

728 729 730 731
static const char *openvzProbe(void)
{
#ifdef __linux__
    if ((getuid() == 0) && (virFileExists("/proc/vz")))
D
Daniel Veillard 已提交
732
        return("openvz:///system");
733 734 735 736
#endif
    return(NULL);
}

737
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
                                 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;
   }
755
    /* See if we are running an OpenVZ enabled kernel */
756 757 758 759
   if(access("/proc/vz/veinfo", F_OK) == -1 ||
               access("/proc/user_beancounters", F_OK) == -1) {
       return VIR_DRV_OPEN_DECLINED;
   }
760

761
   conn->privateData = &ovz_driver;
762

763 764 765
   virStateInitialize();
   vms = openvzGetVPSInfo(conn);
   ovz_driver.vms = vms;
766

767 768
   return VIR_DRV_OPEN_SUCCESS;
};
769 770

static int openvzClose(virConnectPtr conn) {
771

772 773 774 775 776 777 778 779 780 781 782 783 784
    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);
    }
785

786 787 788 789 790 791 792 793 794
    conn->privateData = NULL;

    return 0;
}

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

795 796 797 798 799
static int openvzGetNodeInfo(virConnectPtr conn,
                             virNodeInfoPtr nodeinfo) {
    return virNodeInfoPopulate(conn, nodeinfo);
}

800 801
static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
    int got = 0;
802 803 804
    int veid, pid;
    int outfd = -1;
    int errfd = -1;
805 806
    int ret;
    char buf[32];
807
    char *endptr;
808
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
809

810
    ret = virExec(conn, cmd, NULL, &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
811
    if(ret == -1) {
D
Daniel Veillard 已提交
812
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
813
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
814
        return -1;
815 816
    }

817 818 819
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
820 821 822 823 824
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
825 826 827
        ids[got] = veid;
        got ++;
    }
828
    waitpid(pid, NULL, 0);
829 830 831 832

    return got;
}

833
static int openvzNumDomains(virConnectPtr conn ATTRIBUTE_UNUSED) {
834 835 836 837 838 839
    return ovz_driver.num_active;
}

static int openvzListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
    int got = 0;
840
    int veid, pid, outfd = -1, errfd = -1, ret;
841
    char vpsname[OPENVZ_NAME_MAX];
842
    char buf[32];
843
    char *endptr;
844
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
845 846

    /* the -S options lists only stopped domains */
847
    ret = virExec(conn, cmd, NULL, &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
848
    if(ret == -1) {
D
Daniel Veillard 已提交
849
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
850
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
851
        return -1;
852 853
    }

854 855 856
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
857 858 859 860 861
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
862 863 864 865
        sprintf(vpsname, "%d", veid);
        names[got] = strdup(vpsname);
        got ++;
    }
866
    waitpid(pid, NULL, 0);
867 868 869
    return got;
}

D
Daniel Veillard 已提交
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
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;
}

915
static int openvzNumDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED) {
916
    return ovz_driver.num_inactive;
917 918 919 920
}

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

922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
    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,
944
    openvzProbe, /* probe */
945 946
    openvzOpen, /* open */
    openvzClose, /* close */
947
    NULL, /* supports_feature */
948 949 950 951
    openvzGetType, /* type */
    NULL, /* version */
    NULL, /* hostname */
    NULL, /* uri */
952
    openvzGetMaxVCPUs, /* getMaxVcpus */
953
    openvzGetNodeInfo, /* nodeGetInfo */
954 955 956
    NULL, /* getCapabilities */
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
957
    openvzDomainCreateLinux, /* domainCreateLinux */
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
    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 */
974
    openvzDomainSetVcpus, /* domainSetVcpus */
975 976
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
977
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
978 979 980 981
    NULL, /* domainDumpXML */
    openvzListDefinedDomains, /* listDomains */
    openvzNumDefinedDomains, /* numOfDomains */
    openvzDomainCreate, /* domainCreate */
982 983
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
984 985
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
986 987
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
988 989 990
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
991 992 993 994 995
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
996 997
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
998
    NULL, /* nodeGetCellsFreeMemory */
999
    NULL, /* nodeGetFreeMemory */
1000 1001 1002 1003 1004 1005 1006
};

static virStateDriver openvzStateDriver = {
    openvzStartup,
    openvzShutdown,
    openvzReload,
    openvzActive,
D
Daniel P. Berrange 已提交
1007
    NULL, /* sigHandler */
1008 1009 1010 1011 1012 1013 1014 1015
};

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