openvz_driver.c 29.7 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

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

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

69 70
struct openvz_driver ovz_driver;

71
static void cmdExecFree(const char *cmdExec[])
72 73 74 75
{
    int i=-1;
    while(cmdExec[++i])
    {
76
        VIR_FREE(cmdExec[i]);
77 78 79
    }
}

80 81 82 83 84
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
*/
static int openvzDomainDefineCmd(virConnectPtr conn,
85
                                 const char *args[],
86
                                 int maxarg,
87
                                 virDomainDefPtr vmdef)
88 89 90 91 92 93 94 95
{
    int narg;

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

    if (vmdef == NULL){
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
96
                   "%s", _("Container is not defined"));
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
        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);
120

121 122
    if (vmdef->nfss) {
        if (vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE) {
123 124 125 126
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("only filesystem templates are supported"));
            return -1;
        }
127

128
        if (vmdef->nfss > 1) {
129 130 131 132
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("only one filesystem supported"));
            return -1;
        }
133 134

        ADD_ARG_LIT("--ostemplate");
135
        ADD_ARG_LIT(vmdef->fss[0]->src);
136
    }
137
#if 0
138 139 140 141
    if ((vmdef->profile && *(vmdef->profile))) {
        ADD_ARG_LIT("--config");
        ADD_ARG_LIT(vmdef->profile);
    }
142
#endif
143 144 145 146 147 148 149 150 151 152 153 154

    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
}


155
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
156
                                           int id) {
157
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
158
    virDomainObjPtr vm;
159 160
    virDomainPtr dom;

161
    vm = virDomainFindByID(&driver->domains, id);
162

163
    if (!vm) {
164
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
165 166 167
        return NULL;
    }

168 169
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (!dom)
170 171
        return NULL;

172
    dom->id = vm->def->id;
173 174 175
    return dom;
}

176 177 178 179 180 181
static int openvzGetVersion(virConnectPtr conn, unsigned long *version) {
    struct  openvz_driver *driver = (struct openvz_driver *)conn->privateData;
    *version = driver->version;
    return 0;
}

182
static char *openvzGetOSType(virDomainPtr dom)
183
{
184
    struct  openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
185
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
186 187 188 189 190 191 192 193 194 195 196
    char *ret;

    if (!vm) {
        openvzError(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
        return NULL;
    }

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

    return ret;
197 198 199 200
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
201
                                             const unsigned char *uuid) {
202
    struct  openvz_driver *driver = (struct openvz_driver *)conn->privateData;
203
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, uuid);
204 205 206
    virDomainPtr dom;

    if (!vm) {
207
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
208 209 210
        return NULL;
    }

211 212
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (!dom)
213 214
        return NULL;

215
    dom->id = vm->def->id;
216 217 218 219 220 221
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
                                     const char *name) {
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;
222
    virDomainObjPtr vm = virDomainFindByName(&driver->domains, name);
223 224 225
    virDomainPtr dom;

    if (!vm) {
226
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
227 228 229
        return NULL;
    }

230 231
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (!dom)
232
        return NULL;
233

234
    dom->id = vm->def->id;
235 236 237 238
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
239
                               virDomainInfoPtr info) {
240
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
241
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
242

243
    if (!vm) {
D
Daniel Veillard 已提交
244
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
245
                    "%s", _("no domain with matching uuid"));
246 247 248
        return -1;
    }

249
    info->state = vm->state;
250

251
    if (!virDomainIsActive(vm)) {
D
Daniel Veillard 已提交
252 253 254 255
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
            openvzError(dom->conn, VIR_ERR_OPERATION_FAILED,
256
                        _("cannot read cputime for domain %d"), dom->id);
D
Daniel Veillard 已提交
257 258 259 260
            return -1;
        }
    }

261 262 263
    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
264 265 266 267
    return 0;
}


268 269
static char *openvzDomainDumpXML(virDomainPtr dom, int flags) {
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
270
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
271

272
    if (!vm) {
D
Daniel Veillard 已提交
273
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
274
                    "%s", _("no domain with matching uuid"));
275
        return NULL;
276
    }
277

278 279
    return virDomainDefFormat(dom->conn, vm->def, flags);
}
280

281 282 283 284


static int openvzDomainShutdown(virDomainPtr dom) {
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
285
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
286
    const char *prog[] = {VZCTL, "--quiet", "stop", vm ? vm->def->name : NULL, NULL};
287 288 289

    if (!vm) {
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
290
                    "%s", _("no domain with matching uuid"));
291 292
        return -1;
    }
293

294
    if (vm->state != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
295
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
296
                    "%s", _("domain is not in running state"));
297 298
        return -1;
    }
299

300 301
    if (virRun(dom->conn, prog, NULL) < 0)
        return -1;
302

303 304
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;
305

306
    return 0;
307 308
}

309 310
static int openvzDomainReboot(virDomainPtr dom,
                              unsigned int flags ATTRIBUTE_UNUSED) {
311
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
312
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
313
    const char *prog[] = {VZCTL, "--quiet", "restart", vm ? vm->def->name : NULL, NULL};
314 315

    if (!vm) {
D
Daniel Veillard 已提交
316
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
317
                    "%s", _("no domain with matching uuid"));
318 319
        return -1;
    }
320

321 322
    if (vm->state != VIR_DOMAIN_RUNNING) {
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
323
                    "%s", _("domain is not in running state"));
324 325
        return -1;
    }
326

327
    if (virRun(dom->conn, prog, NULL) < 0)
328
        return -1;
329

330
    return 0;
331 332
}

D
Daniel Veillard 已提交
333 334 335 336 337
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
                        virDomainNetDefPtr net)
{
    int rc = 0, narg;
338
    const char *prog[OPENVZ_MAX_ARG];
D
Daniel Veillard 已提交
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    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,
J
Jim Meyering 已提交
354
                    "%s", _("Container ID is not specified"));
D
Daniel Veillard 已提交
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 395
        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");
396
        if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
           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
}

419 420 421 422
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
423 424
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
425
    virDomainPtr dom = NULL;
426
    int i;
427
    const char *prog[OPENVZ_MAX_ARG];
428
    prog[0] = NULL;
429

430
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml)) == NULL)
431
        return NULL;
432

433 434 435 436 437 438
    if (vmdef->os.init == NULL &&
        !(vmdef->os.init = strdup("/sbin/init"))) {
        virDomainDefFree(vmdef);
        return NULL;
    }

439
    vm = virDomainFindByName(&driver->domains, vmdef->name);
440
    if (vm) {
441 442
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM active with the id '%s'"),
443
                  vmdef->name);
444
        virDomainDefFree(vmdef);
445
        return NULL;
446
    }
447 448 449
    if (!(vm = virDomainAssignDef(conn, &driver->domains, vmdef))) {
        virDomainDefFree(vmdef);
        return NULL;
450 451
    }

452 453
    if (openvzDomainDefineCmd(conn, prog, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
454
                "%s", _("Error creating command for container"));
455
        goto exit;
456 457
    }

D
Daniel Veillard 已提交
458 459
    //TODO: set quota

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

466 467
    if (openvzSetDefinedUUID(strtoI(vmdef->name), vmdef->uuid) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
468
               "%s", _("Could not set UUID"));
469 470 471
        goto exit;
    }

472
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
473
    if (dom)
474
        dom->id = -1;
D
Daniel Veillard 已提交
475

476 477 478
    for (i = 0 ; i < vmdef->nnets ; i++) {
        if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->nets[i]) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
479
                        "%s", _("Could not configure network"));
480 481
            goto exit;
        }
D
Daniel Veillard 已提交
482 483
    }

484 485 486
    if (vmdef->vcpus > 0) {
        if (openvzDomainSetVcpus(dom, vmdef->vcpus) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
487
                     "%s", _("Could not set number of virtual cpu"));
488 489 490 491
             goto exit;
        }
    }

D
Daniel Veillard 已提交
492
    exit:
493
    cmdExecFree(prog);
494 495 496 497
    return dom;
}

static virDomainPtr
498
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
499 500
                        unsigned int flags ATTRIBUTE_UNUSED)
{
501 502
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
503
    virDomainPtr dom = NULL;
504
    int i;
505
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
506
    const char *progstart[] = {VZCTL, "--quiet", "start", NULL, NULL};
507
    const char *progcreate[OPENVZ_MAX_ARG];
508
    progcreate[0] = NULL;
509

510 511 512 513 514 515
    if ((vmdef = virDomainDefParseString(conn, driver->caps, xml)) == NULL)
        return NULL;

    if (vmdef->os.init == NULL &&
        !(vmdef->os.init = strdup("/sbin/init"))) {
        virDomainDefFree(vmdef);
516
        return NULL;
517
    }
518

519
    vm = virDomainFindByName(&driver->domains, vmdef->name);
520
    if (vm) {
521 522 523
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM defined with the id '%s'"),
                  vmdef->name);
524
        virDomainDefFree(vmdef);
525 526
        return NULL;
    }
527 528
    if (!(vm = virDomainAssignDef(conn, &driver->domains, vmdef))) {
        virDomainDefFree(vmdef);
529 530 531
        return NULL;
    }

532 533
    if (openvzDomainDefineCmd(conn, progcreate, OPENVZ_MAX_ARG, vmdef) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
534
                "%s", _("Error creating command for container"));
535
        goto exit;
536 537
    }

538
    if (virRun(conn, progcreate, NULL) < 0) {
D
Daniel Veillard 已提交
539
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
540
               _("Could not exec %s"), VZCTL);
541
        goto exit;
542
    }
543

544 545
    if (openvzSetDefinedUUID(strtoI(vmdef->name), vmdef->uuid) < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
546
               "%s", _("Could not set UUID"));
547 548 549
        goto exit;
    }

550 551 552
    for (i = 0 ; i < vmdef->nnets ; i++) {
        if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->nets[i]) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
553
                        "%s", _("Could not configure network"));
554 555
            goto exit;
        }
D
Daniel Veillard 已提交
556 557
    }

558
    progstart[3] = vmdef->name;
559

560
    if (virRun(conn, progstart, NULL) < 0) {
D
Daniel Veillard 已提交
561
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
562
               _("Could not exec %s"), VZCTL);
563
        goto exit;
564
    }
565

566 567 568
    vm->pid = strtoI(vmdef->name);
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
569

570
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
571
    if (dom)
572
        dom->id = vm->def->id;
573 574 575 576

    if (vmdef->vcpus > 0) {
        if (openvzDomainSetVcpus(dom, vmdef->vcpus) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
577
                        "%s", _("Could not set number of virtual cpu"));
578
            goto exit;
579 580 581
        }
    }

582 583
 exit:
    cmdExecFree(progcreate);
584 585 586 587 588 589
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
590
    struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData;
591
    virDomainObjPtr vm = virDomainFindByName(&driver->domains, dom->name);
592
    const char *prog[] = {VZCTL, "--quiet", "start", vm ? vm->def->name : NULL, NULL };
593 594

    if (!vm) {
D
Daniel Veillard 已提交
595
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
596
              "%s", _("no domain with matching id"));
597 598
        return -1;
    }
599

600
    if (vm->state != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
601
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
J
Jim Meyering 已提交
602
              "%s", _("domain is not in shutoff state"));
603 604 605
        return -1;
    }

606
    if (virRun(dom->conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
607
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
608
               _("Could not exec %s"), VZCTL);
609 610
        return -1;
    }
611

612 613 614
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
615

616
    return 0;
617 618 619 620 621 622 623
}

static int
openvzDomainUndefine(virDomainPtr dom)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
624
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
625
    const char *prog[] = { VZCTL, "--quiet", "destroy", vm ? vm->def->name : NULL, NULL };
626 627

    if (!vm) {
J
Jim Meyering 已提交
628
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
629 630
        return -1;
    }
631

632
    if (virDomainIsActive(vm)) {
J
Jim Meyering 已提交
633
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete active domain"));
634 635
        return -1;
    }
636

637
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
638
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
639
               _("Could not exec %s"), VZCTL);
640 641
        return -1;
    }
642

643 644
    virDomainRemoveInactive(&driver->domains, vm);

645
    return 0;
646 647
}

648 649 650 651 652
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
653
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
654
    const char *prog[] = { VZCTL, "--quiet", "set", vm ? vm->def->name : NULL,
D
Daniel Veillard 已提交
655
                           "--onboot", autostart ? "yes" : "no",
656 657 658
                           "--save", NULL };

    if (!vm) {
J
Jim Meyering 已提交
659
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
660 661 662
        return -1;
    }

663
    if (virRun(conn, prog, NULL) < 0) {
D
Daniel Veillard 已提交
664
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL);
665 666 667 668 669 670 671 672 673 674 675
        return -1;
    }

    return 0;
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virConnectPtr conn= dom->conn;
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
676
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
677 678 679
    char value[1024];

    if (!vm) {
J
Jim Meyering 已提交
680
        openvzError(conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
681 682 683
        return -1;
    }

684
    if (openvzReadConfigParam(strtoI(vm->def->name), "ONBOOT", value, sizeof(value)) < 0) {
J
Jim Meyering 已提交
685
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Could not read container config"));
686 687 688 689 690
        return -1;
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
691
        *autostart = 1;
692 693 694 695

    return 0;
}

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
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;
713
    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
714
    char   str_vcpus[32];
715
    const char *prog[] = { VZCTL, "--quiet", "set", vm ? vm->def->name : NULL,
716 717 718 719 720
                           "--cpus", str_vcpus, "--save", NULL };


    if (!vm) {
        openvzError(conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
721
                    "%s", _("no domain with matching uuid"));
722 723 724
        return -1;
    }

725 726
    if (nvcpus <= 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
727
                    "%s", _("VCPUs should be >= 1"));
728 729 730 731 732 733
        return -1;
    }

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

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

740
    vm->def->vcpus = nvcpus;
741 742 743
    return 0;
}

744 745 746
static const char *openvzProbe(void)
{
#ifdef __linux__
747
    if ((geteuid() == 0) && (virFileExists("/proc/vz")))
D
Daniel Veillard 已提交
748
        return("openvz:///system");
749 750 751 752
#endif
    return(NULL);
}

753
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
754 755 756 757
                                 xmlURIPtr uri,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED)
{
758
    struct openvz_driver *driver;
759
    /*Just check if the user is root. Nothing really to open for OpenVZ */
760 761 762 763 764 765 766 767 768 769
    if (geteuid()) { // OpenVZ tools can only be used by r00t
        return VIR_DRV_OPEN_DECLINED;
    } else {
        if (uri == NULL ||
            uri->scheme == NULL ||
            uri->path == NULL ||
            STRNEQ (uri->scheme, "openvz") ||
            STRNEQ (uri->path, "/system"))
            return VIR_DRV_OPEN_DECLINED;
    }
770
    /* See if we are running an OpenVZ enabled kernel */
771 772 773 774 775 776 777 778 779 780 781 782
    if(access("/proc/vz/veinfo", F_OK) == -1 ||
       access("/proc/user_beancounters", F_OK) == -1) {
        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;
783

784 785
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
786

787 788 789
    if (openvzExtractVersion(conn, driver) < 0)
        goto cleanup;

790
    conn->privateData = driver;
791

792
    return VIR_DRV_OPEN_SUCCESS;
793

794 795 796
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
797
};
798 799 800

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

802
    openvzFreeDriver(driver);
803 804 805 806 807 808 809 810 811
    conn->privateData = NULL;

    return 0;
}

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

812 813 814 815 816
static int openvzGetNodeInfo(virConnectPtr conn,
                             virNodeInfoPtr nodeinfo) {
    return virNodeInfoPopulate(conn, nodeinfo);
}

817 818 819 820 821 822
static char *openvzGetCapabilities(virConnectPtr conn) {
    struct openvz_driver *driver = (struct openvz_driver *)conn->privateData;

    return virCapabilitiesFormatXML(driver->caps);
}

823 824
static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
    int got = 0;
825 826 827
    int veid, pid;
    int outfd = -1;
    int errfd = -1;
828 829
    int ret;
    char buf[32];
830
    char *endptr;
831
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
832

833 834
    ret = virExec(conn, cmd, NULL, NULL,
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
835
    if(ret == -1) {
D
Daniel Veillard 已提交
836
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
837
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
838
        return -1;
839 840
    }

841 842 843
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
844 845 846 847 848
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
849 850 851
        ids[got] = veid;
        got ++;
    }
852
    waitpid(pid, NULL, 0);
853 854 855 856

    return got;
}

857
static int openvzNumDomains(virConnectPtr conn) {
858
    struct openvz_driver *driver = conn->privateData;
859 860 861 862
    int nactive = 0, i;

    for (i = 0 ; i < driver->domains.count ; i++)
        if (virDomainIsActive(driver->domains.objs[i]))
863
            nactive++;
864

865
    return nactive;
866 867 868
}

static int openvzListDefinedDomains(virConnectPtr conn,
869
                                    char **const names, int nnames) {
870
    int got = 0;
871
    int veid, pid, outfd = -1, errfd = -1, ret;
872
    char vpsname[32];
873
    char buf[32];
874
    char *endptr;
875
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
876 877

    /* the -S options lists only stopped domains */
878 879
    ret = virExec(conn, cmd, NULL, NULL,
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
880
    if(ret == -1) {
D
Daniel Veillard 已提交
881
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
882
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
883
        return -1;
884 885
    }

886 887 888
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
889 890 891 892 893
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
894 895 896
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
        if (!(names[got] = strdup(vpsname)))
            goto no_memory;
897 898
        got ++;
    }
899
    waitpid(pid, NULL, 0);
900
    return got;
901 902 903 904 905 906

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

D
Daniel Veillard 已提交
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
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;
}

954 955
static int openvzNumDefinedDomains(virConnectPtr conn) {
    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
956 957 958 959
    int ninactive = 0, i;

    for (i = 0 ; i < driver->domains.count ; i++)
        if (!virDomainIsActive(driver->domains.objs[i]))
960
            ninactive++;
961

962
    return ninactive;
963 964 965 966 967 968
}

static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    LIBVIR_VERSION_NUMBER,
969
    openvzProbe, /* probe */
970 971
    openvzOpen, /* open */
    openvzClose, /* close */
972
    NULL, /* supports_feature */
973
    openvzGetType, /* type */
974
    openvzGetVersion, /* version */
975 976
    NULL, /* hostname */
    NULL, /* uri */
977
    openvzGetMaxVCPUs, /* getMaxVcpus */
978
    openvzGetNodeInfo, /* nodeGetInfo */
979
    openvzGetCapabilities, /* getCapabilities */
980 981
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
982
    openvzDomainCreateXML, /* domainCreateXML */
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
    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 */
999
    openvzDomainSetVcpus, /* domainSetVcpus */
1000 1001
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
1002
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
1003
    openvzDomainDumpXML, /* domainDumpXML */
1004 1005 1006
    openvzListDefinedDomains, /* listDomains */
    openvzNumDefinedDomains, /* numOfDomains */
    openvzDomainCreate, /* domainCreate */
1007 1008
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
1009 1010
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
1011 1012
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
1013 1014 1015
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
1016 1017 1018 1019 1020
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
1021 1022
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1023
    NULL, /* nodeGetCellsFreeMemory */
1024
    NULL, /* nodeGetFreeMemory */
1025 1026
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
1027 1028 1029 1030 1031 1032 1033
};

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