openvz_driver.c 43.4 KB
Newer Older
1 2 3
/*
 * openvz_driver.c: core driver methods for managing OpenVZ VEs
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2010 Red Hat, Inc.
5 6
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
7
 * Copyright (C) 2007 Anoop Joe Cyriac
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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
 *
23
 * Authors:
24 25 26
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
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 <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
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
72
                                        unsigned int nvcpus);
73
static int openvzDomainSetMemoryInternal(virDomainObjPtr vm,
74
                                         unsigned long memory);
D
Daniel Veillard 已提交
75

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

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

86 87
struct openvz_driver ovz_driver;

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

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

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

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

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

150 151
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Failed to parse vzlist output"));
152 153 154 155 156 157 158 159 160 161 162 163 164 165
            goto cleanup;
        }
        if (veid > max_veid) {
            max_veid = veid;
        }
    }
    fclose(fp);

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

166
    sprintf(str_id, "%d", max_veid);
167 168 169
    ADD_ARG_LIT(str_id);

    ADD_ARG_LIT("--name");
170
    ADD_ARG_LIT(vmdef->name);
171

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

    ADD_ARG(NULL);
    return 0;
186 187

no_memory:
188
    openvzError(VIR_ERR_INTERNAL_ERROR,
189 190
                _("Could not put argument to %s"), VZCTL);
    return -1;
191 192 193 194 195

cleanup:
    fclose(fp);
    return -1;

196 197 198 199 200
#undef ADD_ARG
#undef ADD_ARG_LIT
}


201
static int openvzSetInitialConfig(virDomainDefPtr vmdef)
202 203 204 205 206 207 208 209
{
    int ret = -1;
    int vpsid;
    char * confdir = NULL;
    const char *prog[OPENVZ_MAX_ARG];
    prog[0] = NULL;

    if (vmdef->nfss > 1) {
210 211
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("only one filesystem supported"));
212 213 214 215 216 217 218
        goto cleanup;
    }

    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
    {
219 220
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("filesystem is not of type 'template' or 'mount'"));
221 222 223 224 225 226 227 228 229
        goto cleanup;
    }


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

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

        if (openvzCopyDefaultConfig(vpsid) < 0) {
236 237
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Could not copy default config"));
238 239 240 241
            goto cleanup;
        }

        if (openvzWriteVPSConfigParam(vpsid, "VE_PRIVATE", vmdef->fss[0]->src) < 0) {
242 243
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Could not set the source dir for the filesystem"));
244 245 246 247 248
            goto cleanup;
        }
    }
    else
    {
249 250 251
        if (openvzDomainDefineCmd(prog, OPENVZ_MAX_ARG, vmdef) < 0) {
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Error creating command for container"));
252 253 254
            goto cleanup;
        }

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

    ret = 0;

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


271
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
272
                                           int id) {
273
    struct openvz_driver *driver = conn->privateData;
274
    virDomainObjPtr vm;
275
    virDomainPtr dom = NULL;
276

277
    openvzDriverLock(driver);
278
    vm = virDomainFindByID(&driver->domains, id);
279 280
    openvzDriverUnlock(driver);

281
    if (!vm) {
282
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
283
        goto cleanup;
284 285
    }

286
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
287 288
    if (dom)
        dom->id = vm->def->id;
289

290
cleanup:
291 292
    if (vm)
        virDomainObjUnlock(vm);
293 294 295
    return dom;
}

296
static int openvzGetVersion(virConnectPtr conn, unsigned long *version) {
297
    struct  openvz_driver *driver = conn->privateData;
298
    openvzDriverLock(driver);
299
    *version = driver->version;
300
    openvzDriverUnlock(driver);
301 302 303
    return 0;
}

304
static char *openvzGetOSType(virDomainPtr dom)
305
{
306 307 308
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
309

310
    openvzDriverLock(driver);
311
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
312 313
    openvzDriverUnlock(driver);

314
    if (!vm) {
315
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
316
        goto cleanup;
317 318 319
    }

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

322
cleanup:
323 324
    if (vm)
        virDomainObjUnlock(vm);
325
    return ret;
326 327 328 329
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
330
                                             const unsigned char *uuid) {
331 332 333
    struct  openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
334

335
    openvzDriverLock(driver);
336
    vm = virDomainFindByUUID(&driver->domains, uuid);
337 338
    openvzDriverUnlock(driver);

339
    if (!vm) {
340
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
341
        goto cleanup;
342 343
    }

344
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
345 346
    if (dom)
        dom->id = vm->def->id;
347

348
cleanup:
349 350
    if (vm)
        virDomainObjUnlock(vm);
351 352 353 354
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
355 356 357 358
                                             const char *name) {
    struct openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
359

360
    openvzDriverLock(driver);
361
    vm = virDomainFindByName(&driver->domains, name);
362 363
    openvzDriverUnlock(driver);

364
    if (!vm) {
365
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
366
        goto cleanup;
367 368
    }

369
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
370 371
    if (dom)
        dom->id = vm->def->id;
372

373
cleanup:
374 375
    if (vm)
        virDomainObjUnlock(vm);
376 377 378 379
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
380
                               virDomainInfoPtr info) {
381 382 383
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
384

385
    openvzDriverLock(driver);
386
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
387 388
    openvzDriverUnlock(driver);

389
    if (!vm) {
390 391
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
392
        goto cleanup;
393 394
    }

395
    info->state = vm->state;
396

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

407 408 409
    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
410 411 412
    ret = 0;

cleanup:
413 414
    if (vm)
        virDomainObjUnlock(vm);
415
    return ret;
416 417 418
}


419 420 421 422 423 424 425 426 427 428
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) {
429
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
        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) {
451
        openvzError(VIR_ERR_NO_DOMAIN, NULL);
452 453 454 455 456 457 458 459 460 461 462
        goto cleanup;
    }
    ret = obj->persistent;

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


463
static char *openvzDomainDumpXML(virDomainPtr dom, int flags) {
464 465 466
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
467

468
    openvzDriverLock(driver);
469
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
470 471
    openvzDriverUnlock(driver);

472
    if (!vm) {
473 474
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
475
        goto cleanup;
476
    }
477

478
    ret = virDomainDefFormat(vm->def, flags);
479 480

cleanup:
481 482
    if (vm)
        virDomainObjUnlock(vm);
483
    return ret;
484
}
485

486

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
/*
 * 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++;
    }
}
505 506

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

512
    openvzDriverLock(driver);
513
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
514 515
    openvzDriverUnlock(driver);

516
    if (!vm) {
517 518
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
519
        goto cleanup;
520
    }
521

522
    openvzSetProgramSentinal(prog, vm->def->name);
523
    if (vm->state != VIR_DOMAIN_RUNNING) {
524 525
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("domain is not in running state"));
526
        goto cleanup;
527
    }
528

529
    if (virRun(prog, NULL) < 0)
530
        goto cleanup;
531

532 533
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;
534
    ret = 0;
535

536
cleanup:
537 538
    if (vm)
        virDomainObjUnlock(vm);
539
    return ret;
540 541
}

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

549
    openvzDriverLock(driver);
550
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
551 552
    openvzDriverUnlock(driver);

553
    if (!vm) {
554 555
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
556
        goto cleanup;
557
    }
558

559
    openvzSetProgramSentinal(prog, vm->def->name);
560
    if (vm->state != VIR_DOMAIN_RUNNING) {
561 562
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("domain is not in running state"));
563
        goto cleanup;
564
    }
565

566
    if (virRun(prog, NULL) < 0)
567 568
        goto cleanup;
    ret = 0;
569

570
cleanup:
571 572
    if (vm)
        virDomainObjUnlock(vm);
573
    return ret;
574 575
}

576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
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 */
595
    if (openvzReadVPSConfigParam(veid, "NETIF", temp, sizeof(temp)) <= 0) {
596 597
        snprintf(temp, sizeof(temp), "eth0");
    } else {
598
        char *saveptr;
599 600 601 602
        char   *s;
        int     max = 0;

        /* get maximum interface number (actually, it is the last one) */
603
        for (s=strtok_r(temp, ";", &saveptr); s; s=strtok_r(NULL, ";", &saveptr)) {
604 605 606 607 608 609 610 611 612 613 614 615
            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 已提交
616 617
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
618 619
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
620 621
{
    int rc = 0, narg;
622
    const char *prog[OPENVZ_MAX_ARG];
623
    char macaddr[VIR_MAC_STRING_BUFLEN];
624 625
    unsigned char host_mac[VIR_MAC_BUFLEN];
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
626
    struct openvz_driver *driver =  conn->privateData;
627
    char *opt = NULL;
D
Daniel Veillard 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640

#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) {
641 642
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Container ID is not specified"));
D
Daniel Veillard 已提交
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
        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);
    }

659
    virFormatMacAddr(net->mac, macaddr);
660 661
    virCapabilitiesGenerateMac(driver->caps, host_mac);
    virFormatMacAddr(host_mac, host_macaddr);
662 663 664 665

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        virBuffer buf = VIR_BUFFER_INITIALIZER;
        char *dev_name_ve;
666
        int veid = openvzGetVEID(vpsid);
D
Daniel Veillard 已提交
667 668 669

        //--netif_add ifname[,mac,host_ifname,host_mac]
        ADD_ARG_LIT("--netif_add") ;
670 671 672 673

        /* generate interface name in ve and copy it to options */
        dev_name_ve = openvzGenerateContainerVethName(veid);
        if (dev_name_ve == NULL) {
674 675
           openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate eth name for container"));
676 677 678 679 680 681 682 683 684
           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) {
685 686
               openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not generate veth name"));
687 688 689 690 691 692 693 694 695
               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 */
696
        virBufferVSprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
697 698 699 700 701 702 703

        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 */
704
            virBufferVSprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
705
            virBufferVSprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
D
Daniel Veillard 已提交
706
        }
707 708 709 710 711 712

        VIR_FREE(dev_name_ve);

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

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

 exit:
    cmdExecFree(prog);
    return rc;

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

#undef ADD_ARG_LIT
}

748 749 750 751 752 753 754 755 756

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
    unsigned int i;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
757
    struct openvz_driver *driver =  conn->privateData;
758 759 760 761 762 763 764 765 766 767 768

    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) {
769 770
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Could not configure network"));
771 772 773 774 775 776 777
            goto exit;
        }
    }

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

    return 0;

exit:
791
    virBufferFreeAndReset(&buf);
792 793 794 795
    return -1;
}


796 797 798
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
799
    struct openvz_driver *driver =  conn->privateData;
800 801
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
802
    virDomainPtr dom = NULL;
803

804
    openvzDriverLock(driver);
805
    if ((vmdef = virDomainDefParseString(driver->caps, xml,
806
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
807
        goto cleanup;
808

809 810
    if (vmdef->os.init == NULL) {
        if (!(vmdef->os.init = strdup("/sbin/init"))) {
811
            virReportOOMError();
812 813
            goto cleanup;
        }
814 815
    }

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

829 830 831
    if (openvzSetInitialConfig(vm->def) < 0) {
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Error creating initial configuration"));
832
        goto cleanup;
833 834
    }

D
Daniel Veillard 已提交
835 836
    //TODO: set quota

837
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
838 839
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Could not set UUID"));
840
        goto cleanup;
841 842
    }

843 844
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
845

846
    if (vm->def->vcpus > 0) {
847 848 849
        if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) {
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Could not set number of virtual cpu"));
850
             goto cleanup;
851 852 853
        }
    }

854
    if (vm->def->memory > 0) {
855 856 857
        if (openvzDomainSetMemoryInternal(vm, vm->def->memory) < 0) {
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Could not set memory size"));
858 859 860 861
             goto cleanup;
        }
    }

862 863 864 865 866 867
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

cleanup:
    virDomainDefFree(vmdef);
868 869 870
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
871 872 873 874
    return dom;
}

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

884 885
    virCheckFlags(0, NULL);

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

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

898
    vm = virDomainFindByName(&driver->domains, vmdef->name);
899
    if (vm) {
900 901 902
        openvzError(VIR_ERR_OPERATION_FAILED,
                    _("Already an OPENVZ VM defined with the id '%s'"),
                   vmdef->name);
903
        goto cleanup;
904
    }
905
    if (!(vm = virDomainAssignDef(driver->caps,
906
                                  &driver->domains, vmdef, false)))
907 908
        goto cleanup;
    vmdef = NULL;
909 910 911
    /* 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;
912

913 914 915
    if (openvzSetInitialConfig(vm->def) < 0) {
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Error creating initial configuration"));
916
        goto cleanup;
917
    }
918

919
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
920 921
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Could not set UUID"));
922
        goto cleanup;
923 924
    }

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

928
    openvzSetProgramSentinal(progstart, vm->def->name);
929

930
    if (virRun(progstart, NULL) < 0) {
931 932
        openvzError(VIR_ERR_INTERNAL_ERROR,
                   _("Could not exec %s"), VZCTL);
933
        goto cleanup;
934
    }
935

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

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

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

cleanup:
    virDomainDefFree(vmdef);
954 955 956
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
957 958 959 960
    return dom;
}

static int
961
openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
962
{
963 964 965 966
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINAL, NULL };
    int ret = -1;
967

968 969
    virCheckFlags(0, -1);

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

974
    if (!vm) {
975 976
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching id"));
977
        goto cleanup;
978
    }
979

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

986
    openvzSetProgramSentinal(prog, vm->def->name);
987
    if (virRun(prog, NULL) < 0) {
988
        openvzError(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 1007 1008 1009
static int
openvzDomainCreate(virDomainPtr dom)
{
    return openvzDomainCreateWithFlags(dom, 0);
}

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

1018
    openvzDriverLock(driver);
1019
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1020
    if (!vm) {
1021 1022
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
1023
        goto cleanup;
1024
    }
1025

D
Daniel P. Berrange 已提交
1026
    if (virDomainObjIsActive(vm)) {
1027 1028
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("cannot delete active domain"));
1029
        goto cleanup;
1030
    }
1031

1032
    openvzSetProgramSentinal(prog, vm->def->name);
1033
    if (virRun(prog, NULL) < 0) {
1034
        openvzError(VIR_ERR_INTERNAL_ERROR,
1035 1036
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
1037
    }
1038

1039
    virDomainRemoveInactive(&driver->domains, vm);
1040
    vm = NULL;
1041
    ret = 0;
1042

1043
cleanup:
1044 1045 1046
    if (vm)
        virDomainObjUnlock(vm);
    openvzDriverUnlock(driver);
1047
    return ret;
1048 1049
}

1050 1051 1052
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
1053 1054 1055
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
D
Daniel Veillard 已提交
1056
                           "--onboot", autostart ? "yes" : "no",
1057
                           "--save", NULL };
1058
    int ret = -1;
1059

1060
    openvzDriverLock(driver);
1061
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1062 1063
    openvzDriverUnlock(driver);

1064
    if (!vm) {
1065 1066
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
1067
        goto cleanup;
1068 1069
    }

1070
    openvzSetProgramSentinal(prog, vm->def->name);
1071
    if (virRun(prog, NULL) < 0) {
1072 1073
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
1074
        goto cleanup;
1075
    }
1076
    ret = 0;
1077

1078
cleanup:
1079 1080
    if (vm)
        virDomainObjUnlock(vm);
1081
    return ret;
1082 1083 1084 1085 1086
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
1087 1088
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1089
    char value[1024];
1090
    int ret = -1;
1091

1092
    openvzDriverLock(driver);
1093
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1094 1095
    openvzDriverUnlock(driver);

1096
    if (!vm) {
1097 1098
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
1099
        goto cleanup;
1100 1101
    }

1102
    if (openvzReadVPSConfigParam(strtoI(vm->def->name), "ONBOOT", value, sizeof(value)) < 0) {
1103 1104
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Could not read container config"));
1105
        goto cleanup;
1106 1107 1108 1109
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
1110
        *autostart = 1;
1111
    ret = 0;
1112

1113
cleanup:
1114 1115
    if (vm)
        virDomainObjUnlock(vm);
1116
    return ret;
1117 1118
}

1119 1120
static int openvzGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED,
                             const char *type)
1121 1122 1123
{
    if (type == NULL || STRCASEEQ(type, "openvz"))
        return 1028; /* OpenVZ has no limitation */
1124

1125 1126
    openvzError(VIR_ERR_INVALID_ARG,
                _("unknown type '%s'"), type);
1127 1128 1129 1130
    return -1;
}


1131 1132
static int openvzDomainGetMaxVcpus(virDomainPtr dom ATTRIBUTE_UNUSED) {
    return openvzGetMaxVCPUs(NULL, "openvz");
1133 1134
}

1135 1136
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
                                        unsigned int nvcpus)
1137 1138
{
    char        str_vcpus[32];
1139
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINAL,
1140
                           "--cpus", str_vcpus, "--save", NULL };
1141
    unsigned int pcpus;
1142 1143 1144 1145 1146 1147 1148 1149
    pcpus = openvzGetNodeCPUs();
    if (pcpus > 0 && pcpus < nvcpus)
        nvcpus = pcpus;

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

    openvzSetProgramSentinal(prog, vm->def->name);
1150
    if (virRun(prog, NULL) < 0) {
1151 1152
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZCTL);
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        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;
1165

1166
    openvzDriverLock(driver);
1167
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1168 1169
    openvzDriverUnlock(driver);

1170
    if (!vm) {
1171 1172
        openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
                    _("no domain with matching uuid"));
1173
        goto cleanup;
1174 1175
    }

1176
    if (nvcpus <= 0) {
1177 1178
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("VCPUs should be >= 1"));
1179
        goto cleanup;
1180 1181
    }

1182
    openvzDomainSetVcpusInternal(vm, nvcpus);
1183 1184 1185
    ret = 0;

cleanup:
1186 1187
    if (vm)
        virDomainObjUnlock(vm);
1188
    return ret;
1189 1190
}

1191
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
1192 1193
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED)
1194
{
1195
    struct openvz_driver *driver;
1196 1197

    if (conn->uri == NULL) {
1198 1199 1200 1201 1202 1203
        if (!virFileExists("/proc/vz"))
            return VIR_DRV_OPEN_DECLINED;

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

1204 1205
        conn->uri = xmlParseURI("openvz:///system");
        if (conn->uri == NULL) {
1206
            virReportOOMError();
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
            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")) {
1222
            openvzError(VIR_ERR_INTERNAL_ERROR,
1223 1224 1225 1226 1227 1228
                        _("unexpected OpenVZ URI path '%s', try openvz:///system"),
                        conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }

        if (!virFileExists("/proc/vz")) {
1229
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
1230 1231 1232 1233 1234
                        _("OpenVZ control file /proc/vz does not exist"));
            return VIR_DRV_OPEN_ERROR;
        }

        if (access("/proc/vz", W_OK) < 0) {
1235
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
1236
                        _("OpenVZ control file /proc/vz is not accessible"));
1237 1238
            return VIR_DRV_OPEN_ERROR;
        }
1239 1240
    }

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

1244
    if (VIR_ALLOC(driver) < 0) {
1245
        virReportOOMError();
1246 1247 1248
        return VIR_DRV_OPEN_ERROR;
    }

1249 1250 1251
    if (virDomainObjListInit(&driver->domains) < 0)
        goto cleanup;

1252 1253
    if (!(driver->caps = openvzCapsInit()))
        goto cleanup;
1254

1255 1256
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1257

1258
    if (openvzExtractVersion(driver) < 0)
1259 1260
        goto cleanup;

1261
    conn->privateData = driver;
1262

1263
    return VIR_DRV_OPEN_SUCCESS;
1264

1265 1266 1267
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1268
};
1269 1270

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

1273
    openvzFreeDriver(driver);
1274 1275 1276 1277 1278 1279
    conn->privateData = NULL;

    return 0;
}

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

1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
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;
}

1293
static char *openvzGetCapabilities(virConnectPtr conn) {
1294 1295 1296
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1297
    openvzDriverLock(driver);
1298
    ret = virCapabilitiesFormatXML(driver->caps);
1299
    openvzDriverUnlock(driver);
1300

1301
    return ret;
1302 1303
}

1304 1305
static int openvzListDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
                             int *ids, int nids) {
1306
    int got = 0;
1307 1308
    int veid;
    pid_t pid;
1309 1310
    int outfd = -1;
    int errfd = -1;
1311 1312
    int ret;
    char buf[32];
1313
    char *endptr;
1314
    const char *cmd[] = {VZLIST, "-ovpsid", "-H" , NULL};
1315

1316
    ret = virExec(cmd, NULL, NULL,
1317
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1318
    if(ret == -1) {
1319 1320
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1321
        return -1;
1322 1323
    }

1324 1325 1326
    while(got < nids){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1327
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1328 1329
            openvzError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not parse VPS ID %s"), buf);
1330 1331
            continue;
        }
1332 1333 1334
        ids[got] = veid;
        got ++;
    }
1335
    waitpid(pid, NULL, 0);
1336 1337 1338 1339

    return got;
}

1340
static int openvzNumDomains(virConnectPtr conn) {
1341
    struct openvz_driver *driver = conn->privateData;
1342
    int n;
1343

1344
    openvzDriverLock(driver);
1345
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1346
    openvzDriverUnlock(driver);
1347

1348
    return n;
1349 1350
}

1351
static int openvzListDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
1352
                                    char **const names, int nnames) {
1353
    int got = 0;
1354 1355
    int veid, outfd = -1, errfd = -1, ret;
    pid_t pid;
1356
    char vpsname[32];
1357
    char buf[32];
1358
    char *endptr;
1359
    const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL};
1360 1361

    /* the -S options lists only stopped domains */
1362
    ret = virExec(cmd, NULL, NULL,
1363
                  &pid, -1, &outfd, &errfd, VIR_EXEC_NONE);
1364
    if(ret == -1) {
1365 1366
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not exec %s"), VZLIST);
D
Daniel P. Berrange 已提交
1367
        return -1;
1368 1369
    }

1370 1371 1372
    while(got < nnames){
        ret = openvz_readline(outfd, buf, 32);
        if(!ret) break;
1373
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1374 1375
            openvzError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not parse VPS ID %s"), buf);
1376 1377
            continue;
        }
1378 1379 1380
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
        if (!(names[got] = strdup(vpsname)))
            goto no_memory;
1381 1382
        got ++;
    }
1383
    waitpid(pid, NULL, 0);
1384
    return got;
1385 1386

no_memory:
1387
    virReportOOMError();
1388 1389 1390
    for ( ; got >= 0 ; got--)
        VIR_FREE(names[got]);
    return -1;
1391 1392
}

D
Daniel Veillard 已提交
1393 1394 1395 1396
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid) {
    int fd;
    char line[1024] ;
    unsigned long long usertime, systime, nicetime;
1397 1398
    int readvps = vpsid + 1;  /* ensure readvps is initially different */
    int ret;
D
Daniel Veillard 已提交
1399 1400 1401 1402

/* read statistic from /proc/vz/vestat.
sample:
Version: 2.2
1403 1404 1405
   VEID     user      nice     system     uptime                 idle   other..
     33       78         0       1330   59454597      142650441835148   other..
     55      178         0       5340   59424597      542650441835148   other..
D
Daniel Veillard 已提交
1406 1407 1408 1409 1410 1411 1412 1413
*/

    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));
1414
        if (ret <= 0)
D
Daniel Veillard 已提交
1415 1416
            break;

1417 1418 1419 1420 1421 1422 1423 1424 1425
        if (sscanf (line, "%d %llu %llu %llu",
                    &readvps, &usertime, &nicetime, &systime) == 4
            && readvps == vpsid) { /*found vpsid*/
            /* convert jiffies to nanoseconds */
            *cpuTime = (1000ull * 1000ull * 1000ull
                        * (usertime + nicetime  + systime)
                        / (unsigned long long)sysconf(_SC_CLK_TCK));
            break;
        }
D
Daniel Veillard 已提交
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
    }

    close(fd);
    if (ret < 0)
        return -1;

    if (readvps != vpsid) /*not found*/
        return -1;

    return 0;
}

1438
static int openvzNumDefinedDomains(virConnectPtr conn) {
1439
    struct openvz_driver *driver =  conn->privateData;
1440
    int n;
1441

1442
    openvzDriverLock(driver);
1443
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
1444
    openvzDriverUnlock(driver);
1445

1446
    return n;
1447 1448
}

1449
static int
1450
openvzDomainSetMemoryInternal(virDomainObjPtr vm,
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
                              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);
1462
    if (virRun(prog, NULL) < 0) {
1463
        openvzError(VIR_ERR_INTERNAL_ERROR,
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
                    _("Could not exec %s"), VZCTL);
        goto cleanup;
    }

    return 0;

cleanup:
    return -1;
}

1474 1475 1476 1477 1478
static virDriver openvzDriver = {
    VIR_DRV_OPENVZ,
    "OPENVZ",
    openvzOpen, /* open */
    openvzClose, /* close */
1479
    NULL, /* supports_feature */
1480
    openvzGetType, /* type */
1481
    openvzGetVersion, /* version */
1482
    NULL, /* libvirtVersion (impl. in libvirt.c) */
1483
    NULL, /* getHostname */
1484
    openvzGetMaxVCPUs, /* getMaxVcpus */
1485
    nodeGetInfo, /* nodeGetInfo */
1486
    openvzGetCapabilities, /* getCapabilities */
1487 1488
    openvzListDomains, /* listDomains */
    openvzNumDomains, /* numOfDomains */
1489
    openvzDomainCreateXML, /* domainCreateXML */
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
    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 */
1506
    openvzDomainSetVcpus, /* domainSetVcpus */
1507 1508
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
1509
    openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */
1510 1511
    NULL, /* domainGetSecurityLabel */
    NULL, /* nodeGetSecurityModel */
1512
    openvzDomainDumpXML, /* domainDumpXML */
1513 1514
    NULL, /* domainXmlFromNative */
    NULL, /* domainXmlToNative */
1515 1516
    openvzListDefinedDomains, /* listDefinedDomains */
    openvzNumDefinedDomains, /* numOfDefinedDomains */
1517
    openvzDomainCreate, /* domainCreate */
1518
    openvzDomainCreateWithFlags, /* domainCreateWithFlags */
1519 1520
    openvzDomainDefineXML, /* domainDefineXML */
    openvzDomainUndefine, /* domainUndefine */
1521
    NULL, /* domainAttachDevice */
1522
    NULL, /* domainAttachDeviceFlags */
1523
    NULL, /* domainDetachDevice */
1524
    NULL, /* domainDetachDeviceFlags */
1525
    NULL, /* domainUpdateDeviceFlags */
1526 1527
    openvzDomainGetAutostart, /* domainGetAutostart */
    openvzDomainSetAutostart, /* domainSetAutostart */
1528 1529 1530
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
1531 1532 1533 1534 1535
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
1536
    NULL, /* domainMemoryStats */
D
Daniel P. Berrange 已提交
1537 1538
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1539
    NULL, /* domainGetBlockInfo */
1540
    NULL, /* nodeGetCellsFreeMemory */
1541
    NULL, /* getFreeMemory */
1542 1543
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
D
Daniel Veillard 已提交
1544 1545
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1546
    NULL, /* nodeDeviceDettach */
1547 1548
    NULL, /* nodeDeviceReAttach */
    NULL, /* nodeDeviceReset */
C
Chris Lalancette 已提交
1549
    NULL, /* domainMigratePrepareTunnel */
1550 1551 1552 1553
    openvzIsEncrypted,
    openvzIsSecure,
    openvzDomainIsActive,
    openvzDomainIsPersistent,
J
Jiri Denemark 已提交
1554
    NULL, /* cpuCompare */
1555
    NULL, /* cpuBaseline */
1556
    NULL, /* domainGetJobInfo */
1557
    NULL, /* domainAbortJob */
1558
    NULL, /* domainMigrateSetMaxDowntime */
1559 1560
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
1561 1562 1563
    NULL, /* domainManagedSave */
    NULL, /* domainHasManagedSaveImage */
    NULL, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
1564 1565 1566 1567 1568 1569 1570 1571 1572
    NULL, /* domainSnapshotCreateXML */
    NULL, /* domainSnapshotDumpXML */
    NULL, /* domainSnapshotNum */
    NULL, /* domainSnapshotListNames */
    NULL, /* domainSnapshotLookupByName */
    NULL, /* domainHasCurrentSnapshot */
    NULL, /* domainSnapshotCurrent */
    NULL, /* domainRevertToSnapshot */
    NULL, /* domainSnapshotDelete */
C
Chris Lalancette 已提交
1573
    NULL, /* qemuDomainMonitorCommand */
1574 1575 1576 1577 1578 1579
};

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