openvz_driver.c 43.0 KB
Newer Older
1 2 3 4 5
/*
 * openvz_driver.c: core driver methods for managing OpenVZ VEs
 *
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
6
 * Copyright (C) 2007 Anoop Joe Cyriac
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
22
 * Authors:
23 24 25
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/wait.h>

50
#include "virterror_internal.h"
51
#include "datatypes.h"
52
#include "openvz_driver.h"
53 54
#include "event.h"
#include "buf.h"
55
#include "util.h"
56
#include "openvz_conf.h"
57
#include "nodeinfo.h"
58
#include "memory.h"
59
#include "bridge.h"
60

61 62
#define VIR_FROM_THIS VIR_FROM_OPENVZ

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

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

78 79
static void openvzDriverLock(struct openvz_driver *driver)
{
80
    virMutexLock(&driver->lock);
81 82 83 84
}

static void openvzDriverUnlock(struct openvz_driver *driver)
{
85
    virMutexUnlock(&driver->lock);
86 87
}

88 89
struct openvz_driver ovz_driver;

90
static void cmdExecFree(const char *cmdExec[])
91 92 93 94
{
    int i=-1;
    while(cmdExec[++i])
    {
95
        VIR_FREE(cmdExec[i]);
96 97 98
    }
}

99 100 101 102
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
*/
103 104 105 106
static int
openvzDomainDefineCmd(virConnectPtr conn,
                      const char *args[],
                      int maxarg, virDomainDefPtr vmdef)
107 108
{
    int narg;
109 110 111 112
    int veid;
    int max_veid;
    char str_id[10];
    FILE *fp;
113 114 115 116

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

117
    if (vmdef == NULL) {
118
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
119
                    "%s", _("Container is not defined"));
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        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");
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

    if ((fp = popen(VZLIST " -a -ovpsid -H 2>/dev/null", "r")) == NULL) {
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                    _("popen  failed"));
        return -1;
    }
    max_veid = 0;
    while (!feof(fp)) {
        if (fscanf(fp, "%d\n", &veid) != 1) {
            if (feof(fp))
                break;

            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Failed to parse vzlist output"));
            goto cleanup;
        }
        if (veid > max_veid) {
            max_veid = veid;
        }
    }
    fclose(fp);

    if (max_veid == 0) {
        max_veid = 100;
    } else {
        max_veid++;
    }

169
    sprintf(str_id, "%d", max_veid);
170 171 172
    ADD_ARG_LIT(str_id);

    ADD_ARG_LIT("--name");
173
    ADD_ARG_LIT(vmdef->name);
174

175
    if (vmdef->nfss == 1 &&
176
        vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
177
        ADD_ARG_LIT("--ostemplate");
178
        ADD_ARG_LIT(vmdef->fss[0]->src);
179
    }
180
#if 0
181 182 183 184
    if ((vmdef->profile && *(vmdef->profile))) {
        ADD_ARG_LIT("--config");
        ADD_ARG_LIT(vmdef->profile);
    }
185
#endif
186 187 188

    ADD_ARG(NULL);
    return 0;
189 190

no_memory:
191 192 193
    openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not put argument to %s"), VZCTL);
    return -1;
194 195 196 197 198

cleanup:
    fclose(fp);
    return -1;

199 200 201 202 203
#undef ADD_ARG
#undef ADD_ARG_LIT
}


204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
static int openvzSetInitialConfig(virConnectPtr conn,
                                  virDomainDefPtr vmdef)
{
    int ret = -1;
    int vpsid;
    char * confdir = NULL;
    const char *prog[OPENVZ_MAX_ARG];
    prog[0] = NULL;

    if (vmdef->nfss > 1) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("only one filesystem supported"));
        goto cleanup;
    }

    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
    {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("filesystem is not of type 'template' or 'mount'"));
        goto cleanup;
    }


    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_MOUNT)
    {

        if(virStrToLong_i(vmdef->name, NULL, 10, &vpsid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Could not convert domain name to VEID"));
            goto cleanup;
        }

        if (openvzCopyDefaultConfig(vpsid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Could not copy default config"));
            goto cleanup;
        }

        if (openvzWriteVPSConfigParam(vpsid, "VE_PRIVATE", vmdef->fss[0]->src) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Could not set the source dir for the filesystem"));
            goto cleanup;
        }
    }
    else
    {
        if (openvzDomainDefineCmd(conn, prog, OPENVZ_MAX_ARG, vmdef) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Error creating command for container"));
            goto cleanup;
        }

259
        if (virRun(prog, NULL) < 0) {
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                   _("Could not exec %s"), VZCTL);
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
  VIR_FREE(confdir);
  cmdExecFree(prog);
  return ret;
}


275
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
276
                                           int id) {
277
    struct openvz_driver *driver = conn->privateData;
278
    virDomainObjPtr vm;
279
    virDomainPtr dom = NULL;
280

281
    openvzDriverLock(driver);
282
    vm = virDomainFindByID(&driver->domains, id);
283 284
    openvzDriverUnlock(driver);

285
    if (!vm) {
286
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
287
        goto cleanup;
288 289
    }

290
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
291 292
    if (dom)
        dom->id = vm->def->id;
293

294
cleanup:
295 296
    if (vm)
        virDomainObjUnlock(vm);
297 298 299
    return dom;
}

300
static int openvzGetVersion(virConnectPtr conn, unsigned long *version) {
301
    struct  openvz_driver *driver = conn->privateData;
302
    openvzDriverLock(driver);
303
    *version = driver->version;
304
    openvzDriverUnlock(driver);
305 306 307
    return 0;
}

308
static char *openvzGetOSType(virDomainPtr dom)
309
{
310 311 312
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
313

314
    openvzDriverLock(driver);
315
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
316 317
    openvzDriverUnlock(driver);

318 319
    if (!vm) {
        openvzError(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
320
        goto cleanup;
321 322 323
    }

    if (!(ret = strdup(vm->def->os.type)))
324
        virReportOOMError();
325

326
cleanup:
327 328
    if (vm)
        virDomainObjUnlock(vm);
329
    return ret;
330 331 332 333
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
334
                                             const unsigned char *uuid) {
335 336 337
    struct  openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
338

339
    openvzDriverLock(driver);
340
    vm = virDomainFindByUUID(&driver->domains, uuid);
341 342
    openvzDriverUnlock(driver);

343
    if (!vm) {
344
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
345
        goto cleanup;
346 347
    }

348
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
349 350
    if (dom)
        dom->id = vm->def->id;
351

352
cleanup:
353 354
    if (vm)
        virDomainObjUnlock(vm);
355 356 357 358
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
359 360 361 362
                                             const char *name) {
    struct openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
363

364
    openvzDriverLock(driver);
365
    vm = virDomainFindByName(&driver->domains, name);
366 367
    openvzDriverUnlock(driver);

368
    if (!vm) {
369
        openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
370
        goto cleanup;
371 372
    }

373
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
374 375
    if (dom)
        dom->id = vm->def->id;
376

377
cleanup:
378 379
    if (vm)
        virDomainObjUnlock(vm);
380 381 382 383
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
384
                               virDomainInfoPtr info) {
385 386 387
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
388

389
    openvzDriverLock(driver);
390
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
391 392
    openvzDriverUnlock(driver);

393
    if (!vm) {
D
Daniel Veillard 已提交
394
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
395
                    "%s", _("no domain with matching uuid"));
396
        goto cleanup;
397 398
    }

399
    info->state = vm->state;
400

D
Daniel P. Berrange 已提交
401
    if (!virDomainObjIsActive(vm)) {
D
Daniel Veillard 已提交
402 403 404 405
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
            openvzError(dom->conn, VIR_ERR_OPERATION_FAILED,
406
                        _("cannot read cputime for domain %d"), dom->id);
407
            goto cleanup;
D
Daniel Veillard 已提交
408 409 410
        }
    }

411 412 413
    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
414 415 416
    ret = 0;

cleanup:
417 418
    if (vm)
        virDomainObjUnlock(vm);
419
    return ret;
420 421 422
}


423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
static int openvzDomainIsActive(virDomainPtr dom)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    openvzDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    openvzDriverUnlock(driver);
    if (!obj) {
        openvzError(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


static int openvzDomainIsPersistent(virDomainPtr dom)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    openvzDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    openvzDriverUnlock(driver);
    if (!obj) {
        openvzError(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


467
static char *openvzDomainDumpXML(virDomainPtr dom, int flags) {
468 469 470
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
471

472
    openvzDriverLock(driver);
473
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
474 475
    openvzDriverUnlock(driver);

476
    if (!vm) {
D
Daniel Veillard 已提交
477
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
478
                    "%s", _("no domain with matching uuid"));
479
        goto cleanup;
480
    }
481

482
    ret = virDomainDefFormat(vm->def, flags);
483 484

cleanup:
485 486
    if (vm)
        virDomainObjUnlock(vm);
487
    return ret;
488
}
489

490

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
/*
 * Convenient helper to target a command line argv
 * and fill in an empty slot with the supplied
 * key value. This lets us declare the argv on the
 * stack and just splice in the domain name after
 */
#define PROGRAM_SENTINAL ((char *)0x1)
static void openvzSetProgramSentinal(const char **prog, const char *key)
{
    const char **tmp = prog;
    while (tmp && *tmp) {
        if (*tmp == PROGRAM_SENTINAL) {
            *tmp = key;
            break;
        }
        tmp++;
    }
}
509 510

static int openvzDomainShutdown(virDomainPtr dom) {
511 512 513 514
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "stop", PROGRAM_SENTINAL, NULL};
    int ret = -1;
515

516
    openvzDriverLock(driver);
517
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
518 519
    openvzDriverUnlock(driver);

520 521
    if (!vm) {
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
522
                    "%s", _("no domain with matching uuid"));
523
        goto cleanup;
524
    }
525

526
    openvzSetProgramSentinal(prog, vm->def->name);
527
    if (vm->state != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
528
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
529
                    "%s", _("domain is not in running state"));
530
        goto cleanup;
531
    }
532

533
    if (virRun(prog, NULL) < 0)
534
        goto cleanup;
535

536 537
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;
538
    ret = 0;
539

540
cleanup:
541 542
    if (vm)
        virDomainObjUnlock(vm);
543
    return ret;
544 545
}

546 547
static int openvzDomainReboot(virDomainPtr dom,
                              unsigned int flags ATTRIBUTE_UNUSED) {
548 549 550 551
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "restart", PROGRAM_SENTINAL, NULL};
    int ret = -1;
552

553
    openvzDriverLock(driver);
554
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
555 556
    openvzDriverUnlock(driver);

557
    if (!vm) {
D
Daniel Veillard 已提交
558
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
559
                    "%s", _("no domain with matching uuid"));
560
        goto cleanup;
561
    }
562

563
    openvzSetProgramSentinal(prog, vm->def->name);
564 565
    if (vm->state != VIR_DOMAIN_RUNNING) {
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
566
                    "%s", _("domain is not in running state"));
567
        goto cleanup;
568
    }
569

570
    if (virRun(prog, NULL) < 0)
571 572
        goto cleanup;
    ret = 0;
573

574
cleanup:
575 576
    if (vm)
        virDomainObjUnlock(vm);
577
    return ret;
578 579
}

580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
static char *
openvzGenerateVethName(int veid, char *dev_name_ve)
{
    char    dev_name[32];
    int     ifNo = 0;

    if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
        return NULL;
    if (snprintf(dev_name, sizeof(dev_name), "veth%d.%d", veid, ifNo) < 7)
        return NULL;
    return strdup(dev_name);
}

static char *
openvzGenerateContainerVethName(int veid)
{
    char    temp[1024];

    /* try to get line "^NETIF=..." from config */
599
    if (openvzReadVPSConfigParam(veid, "NETIF", temp, sizeof(temp)) <= 0) {
600 601
        snprintf(temp, sizeof(temp), "eth0");
    } else {
602
        char *saveptr;
603 604 605 606
        char   *s;
        int     max = 0;

        /* get maximum interface number (actually, it is the last one) */
607
        for (s=strtok_r(temp, ";", &saveptr); s; s=strtok_r(NULL, ";", &saveptr)) {
608 609 610 611 612 613 614 615 616 617 618 619
            int x;

            if (sscanf(s, "ifname=eth%d", &x) != 1) return NULL;
            if (x > max) max = x;
        }

        /* set new name */
        snprintf(temp, sizeof(temp), "eth%d", max+1);
    }
    return strdup(temp);
}

D
Daniel Veillard 已提交
620 621
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
622 623
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
624 625
{
    int rc = 0, narg;
626
    const char *prog[OPENVZ_MAX_ARG];
627
    char macaddr[VIR_MAC_STRING_BUFLEN];
628 629
    unsigned char host_mac[VIR_MAC_BUFLEN];
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
630
    struct openvz_driver *driver =  conn->privateData;
631
    char *opt = NULL;
D
Daniel Veillard 已提交
632 633 634 635 636 637 638 639 640 641 642 643 644 645

#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 已提交
646
                    "%s", _("Container ID is not specified"));
D
Daniel Veillard 已提交
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
        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);
    }

663
    virFormatMacAddr(net->mac, macaddr);
664 665
    virCapabilitiesGenerateMac(driver->caps, host_mac);
    virFormatMacAddr(host_mac, host_macaddr);
666 667 668 669

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        virBuffer buf = VIR_BUFFER_INITIALIZER;
        char *dev_name_ve;
670
        int veid = openvzGetVEID(vpsid);
D
Daniel Veillard 已提交
671 672 673

        //--netif_add ifname[,mac,host_ifname,host_mac]
        ADD_ARG_LIT("--netif_add") ;
674 675 676 677 678

        /* generate interface name in ve and copy it to options */
        dev_name_ve = openvzGenerateContainerVethName(veid);
        if (dev_name_ve == NULL) {
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
679
                       "%s", _("Could not generate eth name for container"));
680 681 682 683 684 685 686 687 688 689
           rc = -1;
           goto exit;
        }

        /* if user doesn't specified host interface name,
         * than we need to generate it */
        if (net->ifname == NULL) {
            net->ifname = openvzGenerateVethName(veid, dev_name_ve);
            if (net->ifname == NULL) {
               openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
690
                           "%s", _("Could not generate veth name"));
691 692 693 694 695 696 697 698 699
               rc = -1;
               VIR_FREE(dev_name_ve);
               goto exit;
            }
        }

        virBufferAdd(&buf, dev_name_ve, -1); /* Guest dev */
        virBufferVSprintf(&buf, ",%s", macaddr); /* Guest dev mac */
        virBufferVSprintf(&buf, ",%s", net->ifname); /* Host dev */
700
        virBufferVSprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
701 702 703 704 705 706 707

        if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
            virBufferVSprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
        } else {
            virBufferVSprintf(configBuf, "ifname=%s", dev_name_ve);
            virBufferVSprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
            virBufferVSprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
708
            virBufferVSprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
709
            virBufferVSprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
D
Daniel Veillard 已提交
710
        }
711 712 713 714 715 716

        VIR_FREE(dev_name_ve);

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

D
Daniel Veillard 已提交
717
        ADD_ARG_LIT(opt) ;
718 719
        VIR_FREE(opt);
    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
D
Daniel Veillard 已提交
720 721 722 723 724 725 726 727 728 729
              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");
730
        if (virRun(prog, NULL) < 0) {
D
Daniel Veillard 已提交
731 732 733 734 735 736 737 738 739 740 741 742
           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
           rc = -1;
           goto exit;
        }
    }

 exit:
    cmdExecFree(prog);
    return rc;

 no_memory:
743
    VIR_FREE(opt);
D
Daniel Veillard 已提交
744 745 746 747 748 749 750 751
    openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not put argument to %s"), VZCTL);
    cmdExecFree(prog);
    return -1;

#undef ADD_ARG_LIT
}

752 753 754 755 756 757 758 759 760

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
    unsigned int i;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
761
    struct openvz_driver *driver =  conn->privateData;
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781

    for (i = 0 ; i < def->nnets ; i++) {
        if (driver->version < VZCTL_BRIDGE_MIN_VERSION &&
            def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            if (first)
                first = 0;
            else
                virBufferAddLit(&buf, ";");
        }

        if (openvzDomainSetNetwork(conn, def->name, def->nets[i], &buf) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Could not configure network"));
            goto exit;
        }
    }

    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
        param = virBufferContentAndReset(&buf);
        if (param) {
782
            if (openvzWriteVPSConfigParam(strtoI(def->name), "NETIF", param) < 0) {
783 784 785 786 787 788 789 790 791 792 793 794
                VIR_FREE(param);
                openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                            "%s", _("cannot replace NETIF config"));
                return -1;
            }
            VIR_FREE(param);
        }
    }

    return 0;

exit:
795
    virBufferFreeAndReset(&buf);
796 797 798 799
    return -1;
}


800 801 802
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
803
    struct openvz_driver *driver =  conn->privateData;
804 805
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
806
    virDomainPtr dom = NULL;
807

808
    openvzDriverLock(driver);
809
    if ((vmdef = virDomainDefParseString(driver->caps, xml,
810
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
811
        goto cleanup;
812

813 814
    if (vmdef->os.init == NULL) {
        if (!(vmdef->os.init = strdup("/sbin/init"))) {
815
            virReportOOMError();
816 817
            goto cleanup;
        }
818 819
    }

820
    vm = virDomainFindByName(&driver->domains, vmdef->name);
821
    if (vm) {
822 823
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM active with the id '%s'"),
824
                  vmdef->name);
825
        goto cleanup;
826
    }
827
    if (!(vm = virDomainAssignDef(driver->caps,
828
                                  &driver->domains, vmdef)))
829 830
        goto cleanup;
    vmdef = NULL;
831
    vm->persistent = 1;
832

833
    if (openvzSetInitialConfig(conn, vm->def) < 0) {
834
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
835
                "%s", _("Error creating initial configuration"));
836
        goto cleanup;
837 838
    }

D
Daniel Veillard 已提交
839 840
    //TODO: set quota

841
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
842
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
843
               "%s", _("Could not set UUID"));
844
        goto cleanup;
845 846
    }

847 848
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
849

850
    if (vm->def->vcpus > 0) {
851
        if (openvzDomainSetVcpusInternal(conn, vm, vm->def->vcpus) < 0) {
852
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
853
                     "%s", _("Could not set number of virtual cpu"));
854
             goto cleanup;
855 856 857
        }
    }

858 859 860 861 862 863 864 865
    if (vm->def->memory > 0) {
        if (openvzDomainSetMemoryInternal(conn, vm, vm->def->memory) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                     "%s", _("Could not set memory size"));
             goto cleanup;
        }
    }

866 867 868 869 870 871
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

cleanup:
    virDomainDefFree(vmdef);
872 873 874
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
875 876 877 878
    return dom;
}

static virDomainPtr
879
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
880
                      unsigned int flags ATTRIBUTE_UNUSED)
881
{
882
    struct openvz_driver *driver =  conn->privateData;
883 884
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
885
    virDomainPtr dom = NULL;
886
    const char *progstart[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL};
887

888
    openvzDriverLock(driver);
889
    if ((vmdef = virDomainDefParseString(driver->caps, xml,
890
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
891
        goto cleanup;
892

893 894
    if (vmdef->os.init == NULL) {
        if (!(vmdef->os.init = strdup("/sbin/init"))) {
895
            virReportOOMError();
896 897 898
            goto cleanup;
        }
    }
899

900
    vm = virDomainFindByName(&driver->domains, vmdef->name);
901
    if (vm) {
902 903 904
        openvzError(conn, VIR_ERR_OPERATION_FAILED,
                  _("Already an OPENVZ VM defined with the id '%s'"),
                  vmdef->name);
905
        goto cleanup;
906
    }
907
    if (!(vm = virDomainAssignDef(driver->caps,
908
                                  &driver->domains, vmdef)))
909 910
        goto cleanup;
    vmdef = NULL;
911 912 913
    /* All OpenVZ domains seem to be persistent - this is a bit of a violation
     * of this libvirt API which is intended for transient domain creation */
    vm->persistent = 1;
914

915
    if (openvzSetInitialConfig(conn, vm->def) < 0) {
D
Daniel Veillard 已提交
916
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
917
                "%s", _("Error creating initial configuration"));
918
        goto cleanup;
919
    }
920

921
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
922
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
923
               "%s", _("Could not set UUID"));
924
        goto cleanup;
925 926
    }

927 928
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
929

930
    openvzSetProgramSentinal(progstart, vm->def->name);
931

932
    if (virRun(progstart, NULL) < 0) {
D
Daniel Veillard 已提交
933
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
934
               _("Could not exec %s"), VZCTL);
935
        goto cleanup;
936
    }
937

938
    vm->pid = strtoI(vm->def->name);
939 940
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
941

942
    if (vm->def->vcpus > 0) {
943
        if (openvzDomainSetVcpusInternal(conn, vm, vm->def->vcpus) < 0) {
944
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
945
                    "%s", _("Could not set number of virtual cpu"));
946
            goto cleanup;
947 948 949
        }
    }

950 951 952 953 954 955
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

cleanup:
    virDomainDefFree(vmdef);
956 957 958
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
959 960 961 962 963 964
    return dom;
}

static int
openvzDomainCreate(virDomainPtr dom)
{
965 966 967 968
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL };
    int ret = -1;
969

970
    openvzDriverLock(driver);
971
    vm = virDomainFindByName(&driver->domains, dom->name);
972 973
    openvzDriverUnlock(driver);

974
    if (!vm) {
D
Daniel Veillard 已提交
975
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
976 977
                    "%s", _("no domain with matching id"));
        goto cleanup;
978
    }
979

980
    if (vm->state != VIR_DOMAIN_SHUTOFF) {
D
Daniel Veillard 已提交
981
        openvzError(dom->conn, VIR_ERR_OPERATION_DENIED,
982 983
                    "%s", _("domain is not in shutoff state"));
        goto cleanup;
984 985
    }

986
    openvzSetProgramSentinal(prog, vm->def->name);
987
    if (virRun(prog, NULL) < 0) {
D
Daniel Veillard 已提交
988
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
989 990
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
991
    }
992

993 994 995
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
    vm->state = VIR_DOMAIN_RUNNING;
996
    ret = 0;
997

998
cleanup:
999 1000
    if (vm)
        virDomainObjUnlock(vm);
1001
    return ret;
1002 1003 1004 1005 1006
}

static int
openvzDomainUndefine(virDomainPtr dom)
{
1007 1008 1009 1010
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINAL, NULL };
    int ret = -1;
1011

1012
    openvzDriverLock(driver);
1013
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1014
    if (!vm) {
1015 1016
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
1017
    }
1018

D
Daniel P. Berrange 已提交
1019
    if (virDomainObjIsActive(vm)) {
1020 1021
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot delete active domain"));
        goto cleanup;
1022
    }
1023

1024
    openvzSetProgramSentinal(prog, vm->def->name);
1025
    if (virRun(prog, NULL) < 0) {
1026 1027 1028
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
1029
    }
1030

1031
    virDomainRemoveInactive(&driver->domains, vm);
1032
    vm = NULL;
1033
    ret = 0;
1034

1035
cleanup:
1036 1037 1038
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
1039
    return ret;
1040 1041
}

1042 1043 1044
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
1045 1046 1047
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
D
Daniel Veillard 已提交
1048
                           "--onboot", autostart ? "yes" : "no",
1049
                           "--save", NULL };
1050
    int ret = -1;
1051

1052
    openvzDriverLock(driver);
1053
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1054 1055
    openvzDriverUnlock(driver);

1056
    if (!vm) {
1057 1058
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN, "%s", _("no domain with matching uuid"));
        goto cleanup;
1059 1060
    }

1061
    openvzSetProgramSentinal(prog, vm->def->name);
1062
    if (virRun(prog, NULL) < 0) {
1063 1064
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL);
        goto cleanup;
1065
    }
1066
    ret = 0;
1067

1068
cleanup:
1069 1070
    if (vm)
        virDomainObjUnlock(vm);
1071
    return ret;
1072 1073 1074 1075 1076
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
1077 1078
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1079
    char value[1024];
1080
    int ret = -1;
1081

1082
    openvzDriverLock(driver);
1083
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1084 1085
    openvzDriverUnlock(driver);

1086
    if (!vm) {
1087 1088 1089
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
                    "%s", _("no domain with matching uuid"));
        goto cleanup;
1090 1091
    }

1092
    if (openvzReadVPSConfigParam(strtoI(vm->def->name), "ONBOOT", value, sizeof(value)) < 0) {
1093 1094 1095
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Could not read container config"));
        goto cleanup;
1096 1097 1098 1099
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
1100
        *autostart = 1;
1101
    ret = 0;
1102

1103
cleanup:
1104 1105
    if (vm)
        virDomainObjUnlock(vm);
1106
    return ret;
1107 1108
}

1109 1110 1111 1112
static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type)
{
    if (type == NULL || STRCASEEQ(type, "openvz"))
        return 1028; /* OpenVZ has no limitation */
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123

    openvzError(conn, VIR_ERR_INVALID_ARG,
                     _("unknown type '%s'"), type);
    return -1;
}


static int openvzDomainGetMaxVcpus(virDomainPtr dom) {
    return openvzGetMaxVCPUs(dom->conn, "openvz");
}

1124 1125 1126 1127
static int openvzDomainSetVcpusInternal(virConnectPtr conn, virDomainObjPtr vm,
    unsigned int nvcpus)
{
    char        str_vcpus[32];
1128
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
1129
                           "--cpus", str_vcpus, "--save", NULL };
1130
    unsigned int pcpus;
1131 1132 1133 1134 1135 1136 1137 1138
    pcpus = openvzGetNodeCPUs();
    if (pcpus > 0 && pcpus < nvcpus)
        nvcpus = pcpus;

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

    openvzSetProgramSentinal(prog, vm->def->name);
1139
    if (virRun(prog, NULL) < 0) {
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                _("Could not exec %s"), VZCTL);
        return -1;
    }

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

static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    virDomainObjPtr         vm;
    struct openvz_driver   *driver = dom->conn->privateData;
    int                     ret = -1;
1154

1155
    openvzDriverLock(driver);
1156
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1157 1158
    openvzDriverUnlock(driver);

1159
    if (!vm) {
1160
        openvzError(dom->conn, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
1161
                    "%s", _("no domain with matching uuid"));
1162
        goto cleanup;
1163 1164
    }

1165
    if (nvcpus <= 0) {
1166
        openvzError(dom->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1167
                    "%s", _("VCPUs should be >= 1"));
1168
        goto cleanup;
1169 1170
    }

1171
    openvzDomainSetVcpusInternal(dom->conn, vm, nvcpus);
1172 1173 1174
    ret = 0;

cleanup:
1175 1176
    if (vm)
        virDomainObjUnlock(vm);
1177
    return ret;
1178 1179
}

1180
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
1181 1182
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED)
1183
{
1184
    struct openvz_driver *driver;
1185 1186

    if (conn->uri == NULL) {
1187 1188 1189 1190 1191 1192
        if (!virFileExists("/proc/vz"))
            return VIR_DRV_OPEN_DECLINED;

        if (access("/proc/vz", W_OK) < 0)
            return VIR_DRV_OPEN_DECLINED;

1193 1194
        conn->uri = xmlParseURI("openvz:///system");
        if (conn->uri == NULL) {
1195
            virReportOOMError();
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
            return VIR_DRV_OPEN_ERROR;
        }
    } else {
        /* If scheme isn't 'openvz', then its for another driver */
        if (conn->uri->scheme == NULL ||
            STRNEQ (conn->uri->scheme, "openvz"))
            return VIR_DRV_OPEN_DECLINED;

        /* If server name is given, its for remote driver */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

        /* If path isn't /system, then they typoed, so tell them correct path */
        if (conn->uri->path == NULL ||
            STRNEQ (conn->uri->path, "/system")) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                        _("unexpected OpenVZ URI path '%s', try openvz:///system"),
                        conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }

        if (!virFileExists("/proc/vz")) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
                        _("OpenVZ control file /proc/vz does not exist"));
            return VIR_DRV_OPEN_ERROR;
        }

        if (access("/proc/vz", W_OK) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
                        _("OpenVZ control file /proc/vz is not accessible"));
1226 1227
            return VIR_DRV_OPEN_ERROR;
        }
1228 1229
    }

1230 1231 1232
    /* We now know the URI is definitely for this driver, so beyond
     * here, don't return DECLINED, always use ERROR */

1233
    if (VIR_ALLOC(driver) < 0) {
1234
        virReportOOMError();
1235 1236 1237
        return VIR_DRV_OPEN_ERROR;
    }

1238 1239 1240
    if (virDomainObjListInit(&driver->domains) < 0)
        goto cleanup;

1241 1242
    if (!(driver->caps = openvzCapsInit()))
        goto cleanup;
1243

1244 1245
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1246

1247 1248 1249
    if (openvzExtractVersion(conn, driver) < 0)
        goto cleanup;

1250
    conn->privateData = driver;
1251

1252
    return VIR_DRV_OPEN_SUCCESS;
1253

1254 1255 1256
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1257
};
1258 1259

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

1262
    openvzFreeDriver(driver);
1263 1264 1265 1266 1267 1268
    conn->privateData = NULL;

    return 0;
}

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

1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
static int openvzIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) {
    /* Encryption is not relevant / applicable to way we talk to openvz */
    return 0;
}

static int openvzIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) {
    /* We run CLI tools directly so this is secure */
    return 1;
}

1282
static char *openvzGetCapabilities(virConnectPtr conn) {
1283 1284 1285
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1286
    openvzDriverLock(driver);
1287
    ret = virCapabilitiesFormatXML(driver->caps);
1288
    openvzDriverUnlock(driver);
1289

1290
    return ret;
1291 1292
}

1293 1294
static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
    int got = 0;
1295 1296
    int veid;
    pid_t pid;
1297 1298
    int outfd = -1;
    int errfd = -1;
1299 1300
    int ret;
    char buf[32];
1301
    char *endptr;
1302
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
1303

1304
    ret = virExec(cmd, NULL, NULL,
1305
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1306
    if(ret == -1) {
D
Daniel Veillard 已提交
1307
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
1308
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1309
        return -1;
1310 1311
    }

1312 1313 1314
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1315 1316 1317 1318 1319
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
1320 1321 1322
        ids[got] = veid;
        got ++;
    }
1323
    waitpid(pid, NULL, 0);
1324 1325 1326 1327

    return got;
}

1328
static int openvzNumDomains(virConnectPtr conn) {
1329
    struct openvz_driver *driver = conn->privateData;
1330
    int n;
1331

1332
    openvzDriverLock(driver);
1333
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1334
    openvzDriverUnlock(driver);
1335

1336
    return n;
1337 1338 1339
}

static int openvzListDefinedDomains(virConnectPtr conn,
1340
                                    char **const names, int nnames) {
1341
    int got = 0;
1342 1343
    int veid, outfd = -1, errfd = -1, ret;
    pid_t pid;
1344
    char vpsname[32];
1345
    char buf[32];
1346
    char *endptr;
1347
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
1348 1349

    /* the -S options lists only stopped domains */
1350
    ret = virExec(cmd, NULL, NULL,
1351
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1352
    if(ret == -1) {
D
Daniel Veillard 已提交
1353
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
1354
               _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1355
        return -1;
1356 1357
    }

1358 1359 1360
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1361 1362 1363 1364 1365
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not parse VPS ID %s"), buf);
            continue;
        }
1366 1367 1368
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
        if (!(names[got] = strdup(vpsname)))
            goto no_memory;
1369 1370
        got ++;
    }
1371
    waitpid(pid, NULL, 0);
1372
    return got;
1373 1374

no_memory:
1375
    virReportOOMError();
1376 1377 1378
    for ( ; got >= 0 ; got--)
        VIR_FREE(names[got]);
    return -1;
1379 1380
}

D
Daniel Veillard 已提交
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
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;
}

1426
static int openvzNumDefinedDomains(virConnectPtr conn) {
1427
    struct openvz_driver *driver =  conn->privateData;
1428
    int n;
1429

1430
    openvzDriverLock(driver);
1431
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
1432
    openvzDriverUnlock(driver);
1433

1434
    return n;
1435 1436
}

1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
static int
openvzDomainSetMemoryInternal(virConnectPtr conn, virDomainObjPtr vm,
                              unsigned long mem)
{
    char str_mem[16];
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
        "--kmemsize", str_mem, "--save", NULL
    };

    /* memory has to be changed its format from kbyte to byte */
    snprintf(str_mem, sizeof(str_mem), "%lu", mem * 1024);

    openvzSetProgramSentinal(prog, vm->def->name);
1450
    if (virRun(prog, NULL) < 0) {
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
    }

    return 0;

cleanup:
    return -1;
}

1462 1463 1464 1465 1466
static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    openvzOpen, /* open */
    openvzClose, /* close */
1467
    NULL, /* supports_feature */
1468
    openvzGetType, /* type */
1469
    openvzGetVersion, /* version */
1470
    NULL, /* libvirtVersion (impl. in libvirt.c) */
1471
    NULL, /* getHostname */
1472
    openvzGetMaxVCPUs, /* getMaxVcpus */
1473
    nodeGetInfo, /* nodeGetInfo */
1474
    openvzGetCapabilities, /* getCapabilities */
1475 1476
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
1477
    openvzDomainCreateXML, /* domainCreateXML */
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
    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 */
1494
    openvzDomainSetVcpus, /* domainSetVcpus */
1495 1496
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
1497
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
1498 1499
    NULL, /* domainGetSecurityLabel */
    NULL, /* nodeGetSecurityModel */
1500
    openvzDomainDumpXML, /* domainDumpXML */
1501 1502
    NULL, /* domainXmlFromNative */
    NULL, /* domainXmlToNative */
1503 1504
    openvzListDefinedDomains, /* listDefinedDomains */
    openvzNumDefinedDomains, /* numOfDefinedDomains */
1505
    openvzDomainCreate, /* domainCreate */
1506 1507
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
1508
    NULL, /* domainAttachDevice */
1509
    NULL, /* domainAttachDeviceFlags */
1510
    NULL, /* domainDetachDevice */
1511
    NULL, /* domainDetachDeviceFlags */
1512 1513
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
1514 1515 1516
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
1517 1518 1519 1520 1521
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
1522
    NULL, /* domainMemoryStats */
D
Daniel P. Berrange 已提交
1523 1524
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1525
    NULL, /* nodeGetCellsFreeMemory */
1526
    NULL, /* getFreeMemory */
1527 1528
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
D
Daniel Veillard 已提交
1529 1530
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1531
    NULL, /* nodeDeviceDettach */
1532 1533
    NULL, /* nodeDeviceReAttach */
    NULL, /* nodeDeviceReset */
C
Chris Lalancette 已提交
1534
    NULL, /* domainMigratePrepareTunnel */
1535 1536 1537 1538
    openvzIsEncrypted,
    openvzIsSecure,
    openvzDomainIsActive,
    openvzDomainIsPersistent,
J
Jiri Denemark 已提交
1539
    NULL, /* cpuCompare */
1540
    NULL, /* cpuBaseline */
1541
    NULL, /* domainGetJobInfo */
1542
    NULL, /* domainAbortJob */
1543
    NULL, /* domainMigrateSetMaxDowntime */
1544 1545
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
1546 1547 1548 1549 1550 1551
};

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