openvz_driver.c 63.5 KB
Newer Older
1 2 3
/*
 * openvz_driver.c: core driver methods for managing OpenVZ VEs
 *
4
 * Copyright (C) 2010-2013 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
 *
 * 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
20
 * License along with this library.  If not, see
O
Osier Yang 已提交
21
 * <http://www.gnu.org/licenses/>.
22
 *
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
 */

#include <config.h>

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

46
#include "virerror.h"
47
#include "datatypes.h"
48
#include "openvz_driver.h"
49
#include "openvz_util.h"
50
#include "virbuffer.h"
51
#include "openvz_conf.h"
52
#include "nodeinfo.h"
53
#include "viralloc.h"
E
Eric Blake 已提交
54
#include "virfile.h"
55
#include "virtypedparam.h"
56
#include "virlog.h"
57
#include "vircommand.h"
M
Martin Kletzander 已提交
58
#include "viruri.h"
59
#include "virstatslinux.h"
60
#include "virstring.h"
61

62 63
#define VIR_FROM_THIS VIR_FROM_OPENVZ

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

68 69
#define OPENVZ_NB_MEM_PARAM 3

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

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

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

89 90
struct openvz_driver ovz_driver;

91 92 93 94 95 96
static int
openvzDomainDefPostParse(virDomainDefPtr def,
                         virCapsPtr caps ATTRIBUTE_UNUSED,
                         void *opaque ATTRIBUTE_UNUSED)
{
    /* fill the init path */
97 98
    if (STREQ(def->os.type, "exe") && !def->os.init)
        return VIR_STRDUP(def->os.init, "/sbin/init") < 0 ? -1 : 0;
99 100 101 102
    return 0;
}


103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
static int
openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
                               virDomainDefPtr def ATTRIBUTE_UNUSED,
                               virCapsPtr caps ATTRIBUTE_UNUSED,
                               void *opaque ATTRIBUTE_UNUSED)
{
    if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
        dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
        dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;

    return 0;
}


118 119
virDomainDefParserConfig openvzDomainDefParserConfig = {
        .domainPostParseCallback = openvzDomainDefPostParse,
120
        .devicesPostParseCallback = openvzDomainDeviceDefPostParse,
121 122 123
};


124 125 126
/* generate arguments to create OpenVZ container
   return -1 - error
           0 - OK
127
   Caller has to free the cmd
128
*/
129 130
static virCommandPtr
openvzDomainDefineCmd(virDomainDefPtr vmdef)
131
{
132 133 134 135
    virCommandPtr cmd = virCommandNewArgList(VZCTL,
                                             "--quiet",
                                             "create",
                                             NULL);
136

137
    if (vmdef == NULL) {
138 139
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Container is not defined"));
140 141
        virCommandFree(cmd);
        return NULL;
142
    }
143

144
    virCommandAddArgList(cmd, vmdef->name, "--name", vmdef->name, NULL);
145

146
    if (vmdef->nfss == 1 &&
147
        vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
148
        virCommandAddArgList(cmd, "--ostemplate", vmdef->fss[0]->src, NULL);
149
    }
150

151
    return cmd;
152 153 154
}


155
static int openvzSetInitialConfig(virDomainDefPtr vmdef)
156 157 158 159
{
    int ret = -1;
    int vpsid;
    char * confdir = NULL;
160
    virCommandPtr cmd = NULL;
161 162

    if (vmdef->nfss > 1) {
163 164
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only one filesystem supported"));
165 166 167 168 169 170 171
        goto cleanup;
    }

    if (vmdef->nfss == 1 &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE &&
        vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
    {
172 173
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("filesystem is not of type 'template' or 'mount'"));
174 175 176 177 178 179 180 181
        goto cleanup;
    }


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

E
Eric Blake 已提交
182
        if (virStrToLong_i(vmdef->name, NULL, 10, &vpsid) < 0) {
183 184
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not convert domain name to VEID"));
185 186 187 188
            goto cleanup;
        }

        if (openvzCopyDefaultConfig(vpsid) < 0) {
189 190
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not copy default config"));
191 192 193 194
            goto cleanup;
        }

        if (openvzWriteVPSConfigParam(vpsid, "VE_PRIVATE", vmdef->fss[0]->src) < 0) {
195 196
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set the source dir for the filesystem"));
197 198
            goto cleanup;
        }
199 200 201
    } else {
        cmd = openvzDomainDefineCmd(vmdef);
        if (virCommandRun(cmd, NULL) < 0)
202 203 204 205 206 207 208
            goto cleanup;
    }

    ret = 0;

cleanup:
  VIR_FREE(confdir);
209 210
  virCommandFree(cmd);

211 212 213 214
  return ret;
}


215 216
static int
openvzSetDiskQuota(virDomainDefPtr vmdef,
217 218
                   virDomainFSDefPtr fss,
                   bool persist)
219 220 221 222 223 224 225 226
{
    int ret = -1;
    unsigned long long sl, hl;
    virCommandPtr cmd = virCommandNewArgList(VZCTL,
                                             "--quiet",
                                             "set",
                                             vmdef->name,
                                             NULL);
227 228
    if (persist)
        virCommandAddArg(cmd, "--save");
229 230 231 232 233 234 235 236 237 238 239 240 241

    if (fss->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
        if (fss->space_hard_limit) {
            hl = VIR_DIV_UP(fss->space_hard_limit, 1024);
            virCommandAddArg(cmd, "--diskspace");

            if (fss->space_soft_limit) {
                sl = VIR_DIV_UP(fss->space_soft_limit, 1024);
                virCommandAddArgFormat(cmd, "%lld:%lld", sl, hl);
            } else {
                virCommandAddArgFormat(cmd, "%lld", hl);
            }
        } else if (fss->space_soft_limit) {
242 243
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Can't set soft limit without hard limit"));
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
            goto cleanup;
        }

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }

    ret = 0;
cleanup:
  virCommandFree(cmd);

  return ret;
}


259 260 261 262 263 264 265 266 267
static char *
openvzDomainGetHostname(virDomainPtr dom, unsigned int flags)
{
    char *hostname = NULL;
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;

    virCheckFlags(0, NULL);
    openvzDriverLock(driver);
268
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    openvzDriverUnlock(driver);

    if (!vm) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        goto cleanup;
    }

    hostname = openvzVEGetStringParam(dom, "hostname");
    if (hostname == NULL)
        goto error;

    /* vzlist prints an unset hostname as '-' */
    if (STREQ(hostname, "-")) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Hostname of '%s' is unset"), vm->def->name);
        goto error;
    }

cleanup:
    if (vm)
290
        virObjectUnlock(vm);
291 292 293 294 295 296 297 298
    return hostname;

error:
    VIR_FREE(hostname);
    goto cleanup;
}


299
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
300
                                           int id) {
301
    struct openvz_driver *driver = conn->privateData;
302
    virDomainObjPtr vm;
303
    virDomainPtr dom = NULL;
304

305
    openvzDriverLock(driver);
306
    vm = virDomainObjListFindByID(driver->domains, id);
307 308
    openvzDriverUnlock(driver);

309
    if (!vm) {
310
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
311
        goto cleanup;
312 313
    }

314
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
315 316
    if (dom)
        dom->id = vm->def->id;
317

318
cleanup:
319
    if (vm)
320
        virObjectUnlock(vm);
321 322 323
    return dom;
}

324
static int openvzConnectGetVersion(virConnectPtr conn, unsigned long *version) {
325
    struct  openvz_driver *driver = conn->privateData;
326
    openvzDriverLock(driver);
327
    *version = driver->version;
328
    openvzDriverUnlock(driver);
329 330 331
    return 0;
}

332 333 334 335 336 337 338

static char *openvzConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return virGetHostname();
}


339
static char *openvzDomainGetOSType(virDomainPtr dom)
340
{
341 342 343
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
344

345
    openvzDriverLock(driver);
346
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
347 348
    openvzDriverUnlock(driver);

349
    if (!vm) {
350
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
351
        goto cleanup;
352 353
    }

354
    ignore_value(VIR_STRDUP(ret, vm->def->os.type));
355

356
cleanup:
357
    if (vm)
358
        virObjectUnlock(vm);
359
    return ret;
360 361 362 363
}


static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
364
                                             const unsigned char *uuid) {
365 366 367
    struct  openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
368

369
    openvzDriverLock(driver);
370
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
371 372
    openvzDriverUnlock(driver);

373
    if (!vm) {
374
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
375
        goto cleanup;
376 377
    }

378
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
379 380
    if (dom)
        dom->id = vm->def->id;
381

382
cleanup:
383
    if (vm)
384
        virObjectUnlock(vm);
385 386 387 388
    return dom;
}

static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
389 390 391 392
                                             const char *name) {
    struct openvz_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
393

394
    openvzDriverLock(driver);
395
    vm = virDomainObjListFindByName(driver->domains, name);
396 397
    openvzDriverUnlock(driver);

398
    if (!vm) {
399
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
400
        goto cleanup;
401 402
    }

403
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
404 405
    if (dom)
        dom->id = vm->def->id;
406

407
cleanup:
408
    if (vm)
409
        virObjectUnlock(vm);
410 411 412 413
    return dom;
}

static int openvzDomainGetInfo(virDomainPtr dom,
414
                               virDomainInfoPtr info) {
415 416
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
417
    int state;
418
    int ret = -1;
419

420
    openvzDriverLock(driver);
421
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
422 423
    openvzDriverUnlock(driver);

424
    if (!vm) {
425 426
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
427
        goto cleanup;
428 429
    }

430 431 432
    if (openvzGetVEStatus(vm, &state, NULL) == -1)
        goto cleanup;
    info->state = state;
433

434
    if (info->state != VIR_DOMAIN_RUNNING) {
D
Daniel Veillard 已提交
435 436 437
        info->cpuTime = 0;
    } else {
        if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
438 439
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("cannot read cputime for domain %d"), dom->id);
440
            goto cleanup;
D
Daniel Veillard 已提交
441 442 443
        }
    }

444 445
    info->maxMem = vm->def->mem.max_balloon;
    info->memory = vm->def->mem.cur_balloon;
446
    info->nrVirtCpu = vm->def->vcpus;
447 448 449
    ret = 0;

cleanup:
450
    if (vm)
451
        virObjectUnlock(vm);
452
    return ret;
453 454 455
}


456 457 458 459 460 461 462 463 464 465 466 467 468
static int
openvzDomainGetState(virDomainPtr dom,
                     int *state,
                     int *reason,
                     unsigned int flags)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    openvzDriverLock(driver);
469
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
470 471 472
    openvzDriverUnlock(driver);

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

478
    ret = openvzGetVEStatus(vm, state, reason);
479 480 481

cleanup:
    if (vm)
482
        virObjectUnlock(vm);
483 484 485 486
    return ret;
}


487 488 489 490 491 492 493
static int openvzDomainIsActive(virDomainPtr dom)
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    openvzDriverLock(driver);
494
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
495 496
    openvzDriverUnlock(driver);
    if (!obj) {
497
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
498 499 500 501 502 503
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
504
        virObjectUnlock(obj);
505 506 507 508 509 510 511 512 513 514 515
    return ret;
}


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

    openvzDriverLock(driver);
516
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
517 518
    openvzDriverUnlock(driver);
    if (!obj) {
519
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
520 521 522 523 524 525
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
526
        virObjectUnlock(obj);
527 528 529
    return ret;
}

530 531 532 533
static int openvzDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
    return 0;
}
534

535
static char *openvzDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
536 537 538
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
539

540 541
    /* Flags checked by virDomainDefFormat */

542
    openvzDriverLock(driver);
543
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
544 545
    openvzDriverUnlock(driver);

546
    if (!vm) {
547 548
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
549
        goto cleanup;
550
    }
551

552
    ret = virDomainDefFormat(vm->def, flags);
553 554

cleanup:
555
    if (vm)
556
        virObjectUnlock(vm);
557
    return ret;
558
}
559

560

561 562 563 564 565 566
/*
 * 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
 */
E
Eric Blake 已提交
567
#define PROGRAM_SENTINEL ((char *)0x1)
568 569 570 571
static void openvzSetProgramSentinal(const char **prog, const char *key)
{
    const char **tmp = prog;
    while (tmp && *tmp) {
E
Eric Blake 已提交
572
        if (*tmp == PROGRAM_SENTINEL) {
573 574 575 576 577 578
            *tmp = key;
            break;
        }
        tmp++;
    }
}
579

580 581 582
static int openvzDomainSuspend(virDomainPtr dom) {
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
583
    const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--suspend", NULL};
584 585 586
    int ret = -1;

    openvzDriverLock(driver);
587
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
588 589 590
    openvzDriverUnlock(driver);

    if (!vm) {
591 592
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
593 594 595 596
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
597 598
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not running"));
599 600 601
        goto cleanup;
    }

J
Jiri Denemark 已提交
602
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
603 604 605 606
        openvzSetProgramSentinal(prog, vm->def->name);
        if (virRun(prog, NULL) < 0) {
            goto cleanup;
        }
J
Jiri Denemark 已提交
607
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
608 609 610 611 612 613
    }

    ret = 0;

cleanup:
    if (vm)
614
        virObjectUnlock(vm);
615 616 617 618 619 620
    return ret;
}

static int openvzDomainResume(virDomainPtr dom) {
  struct openvz_driver *driver = dom->conn->privateData;
  virDomainObjPtr vm;
E
Eric Blake 已提交
621
  const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--resume", NULL};
622 623 624
  int ret = -1;

  openvzDriverLock(driver);
625
  vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
626 627 628
  openvzDriverUnlock(driver);

  if (!vm) {
629 630
      virReportError(VIR_ERR_NO_DOMAIN, "%s",
                     _("no domain with matching uuid"));
631 632 633 634
      goto cleanup;
  }

  if (!virDomainObjIsActive(vm)) {
635 636
      virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                     _("Domain is not running"));
637 638 639
      goto cleanup;
  }

J
Jiri Denemark 已提交
640
  if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
641 642 643 644
      openvzSetProgramSentinal(prog, vm->def->name);
      if (virRun(prog, NULL) < 0) {
          goto cleanup;
      }
J
Jiri Denemark 已提交
645
      virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
646 647 648 649 650 651
  }

  ret = 0;

cleanup:
  if (vm)
652
      virObjectUnlock(vm);
653 654 655
  return ret;
}

656 657 658
static int
openvzDomainShutdownFlags(virDomainPtr dom,
                          unsigned int flags) {
659 660
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
661
    const char *prog[] = {VZCTL, "--quiet", "stop", PROGRAM_SENTINEL, NULL};
662
    int ret = -1;
663
    int status;
664

665 666
    virCheckFlags(0, -1);

667
    openvzDriverLock(driver);
668
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
669 670
    openvzDriverUnlock(driver);

671
    if (!vm) {
672 673
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
674
        goto cleanup;
675
    }
676

677 678 679
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

680
    openvzSetProgramSentinal(prog, vm->def->name);
681
    if (status != VIR_DOMAIN_RUNNING) {
682 683
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
684
        goto cleanup;
685
    }
686

687
    if (virRun(prog, NULL) < 0)
688
        goto cleanup;
689

690
    vm->def->id = -1;
J
Jiri Denemark 已提交
691
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
692
    dom->id = -1;
693
    ret = 0;
694

695
cleanup:
696
    if (vm)
697
        virObjectUnlock(vm);
698
    return ret;
699 700
}

701 702 703 704 705 706
static int
openvzDomainShutdown(virDomainPtr dom)
{
    return openvzDomainShutdownFlags(dom, 0);
}

707 708 709 710 711 712 713 714 715 716 717 718
static int
openvzDomainDestroy(virDomainPtr dom)
{
    return openvzDomainShutdownFlags(dom, 0);
}

static int
openvzDomainDestroyFlags(virDomainPtr dom, unsigned int flags)
{
    return openvzDomainShutdownFlags(dom, flags);
}

719
static int openvzDomainReboot(virDomainPtr dom,
E
Eric Blake 已提交
720 721
                              unsigned int flags)
{
722 723
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
724
    const char *prog[] = {VZCTL, "--quiet", "restart", PROGRAM_SENTINEL, NULL};
725
    int ret = -1;
726
    int status;
727

E
Eric Blake 已提交
728 729
    virCheckFlags(0, -1);

730
    openvzDriverLock(driver);
731
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
732 733
    openvzDriverUnlock(driver);

734
    if (!vm) {
735 736
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
737
        goto cleanup;
738
    }
739

740 741 742
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

743
    openvzSetProgramSentinal(prog, vm->def->name);
744
    if (status != VIR_DOMAIN_RUNNING) {
745 746
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
747
        goto cleanup;
748
    }
749

750
    if (virRun(prog, NULL) < 0)
751 752
        goto cleanup;
    ret = 0;
753

J
Jiri Denemark 已提交
754 755
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);

756
cleanup:
757
    if (vm)
758
        virObjectUnlock(vm);
759
    return ret;
760 761
}

762 763 764 765
static char *
openvzGenerateVethName(int veid, char *dev_name_ve)
{
    int     ifNo = 0;
766
    char    *ret;
767 768 769

    if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
        return NULL;
770
    ignore_value(virAsprintf(&ret, "veth%d.%d.", veid, ifNo));
771
    return ret;
772 773 774 775 776
}

static char *
openvzGenerateContainerVethName(int veid)
{
777 778
    char *temp = NULL;
    char *name = NULL;
779 780

    /* try to get line "^NETIF=..." from config */
781
    if (openvzReadVPSConfigParam(veid, "NETIF", &temp) <= 0) {
782
        ignore_value(VIR_STRDUP(name, "eth0"));
783
    } else {
784
        char *saveptr = NULL;
785 786
        char *s;
        int max = 0;
787 788

        /* get maximum interface number (actually, it is the last one) */
789
        for (s=strtok_r(temp, ";", &saveptr); s; s=strtok_r(NULL, ";", &saveptr)) {
790 791 792 793 794 795 796
            int x;

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

        /* set new name */
797
        ignore_value(virAsprintf(&name, "eth%d", max + 1));
798
    }
799 800 801 802

    VIR_FREE(temp);

    return name;
803 804
}

D
Daniel Veillard 已提交
805 806
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
807 808
                       virDomainNetDefPtr net,
                       virBufferPtr configBuf)
D
Daniel Veillard 已提交
809
{
810
    int rc = -1;
811
    char macaddr[VIR_MAC_STRING_BUFLEN];
812
    virMacAddr host_mac;
813
    char host_macaddr[VIR_MAC_STRING_BUFLEN];
814
    struct openvz_driver *driver =  conn->privateData;
815
    virCommandPtr cmd = NULL;
816
    char *guest_ifname = NULL;
D
Daniel Veillard 已提交
817 818 819 820

    if (net == NULL)
       return 0;
    if (vpsid == NULL) {
821 822
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Container ID is not specified"));
D
Daniel Veillard 已提交
823 824 825
        return -1;
    }

826 827 828
    if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
        net->type != VIR_DOMAIN_NET_TYPE_ETHERNET)
        return 0;
D
Daniel Veillard 已提交
829

830
    cmd = virCommandNewArgList(VZCTL, "--quiet", "set", vpsid, NULL);
D
Daniel Veillard 已提交
831

832
    virMacAddrFormat(&net->mac, macaddr);
833
    virDomainNetGenerateMAC(driver->xmlopt, &host_mac);
834
    virMacAddrFormat(&host_mac, host_macaddr);
835

836 837 838
    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
         net->data.ethernet.ipaddr == NULL)) {
839
        virBuffer buf = VIR_BUFFER_INITIALIZER;
840
        int veid = openvzGetVEID(vpsid);
D
Daniel Veillard 已提交
841

842 843 844 845 846 847 848 849 850
        /* if net is ethernet and the user has specified guest interface name,
         * let's use it; otherwise generate a new one */
        if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
            net->data.ethernet.dev != NULL) {
            if (VIR_STRDUP(guest_ifname, net->data.ethernet.dev) == -1)
                goto cleanup;
        } else {
            guest_ifname = openvzGenerateContainerVethName(veid);
            if (guest_ifname == NULL) {
851 852
               virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                              _("Could not generate eth name for container"));
853
               goto cleanup;
854
            }
855 856 857 858 859
        }

        /* if user doesn't specified host interface name,
         * than we need to generate it */
        if (net->ifname == NULL) {
860
            net->ifname = openvzGenerateVethName(veid, guest_ifname);
861
            if (net->ifname == NULL) {
862 863
               virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                              _("Could not generate veth name"));
864
               goto cleanup;
865 866 867
            }
        }

868
        virBufferAdd(&buf, guest_ifname, -1); /* Guest dev */
869 870 871
        virBufferAsprintf(&buf, ",%s", macaddr); /* Guest dev mac */
        virBufferAsprintf(&buf, ",%s", net->ifname); /* Host dev */
        virBufferAsprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
872

873 874
        if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
875
                virBufferAsprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
876
            } else {
877
                virBufferAsprintf(configBuf, "ifname=%s", guest_ifname);
878 879 880 881
                virBufferAsprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
                virBufferAsprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
                virBufferAsprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
                virBufferAsprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
882
            }
D
Daniel Veillard 已提交
883
        }
884

885 886 887
        /* --netif_add ifname[,mac,host_ifname,host_mac] */
        virCommandAddArg(cmd, "--netif_add");
        virCommandAddArgBuffer(cmd, &buf);
888
    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
D
Daniel Veillard 已提交
889
              net->data.ethernet.ipaddr != NULL) {
890
        /* --ipadd ip */
891
        virCommandAddArgList(cmd, "--ipadd", net->data.ethernet.ipaddr, NULL);
D
Daniel Veillard 已提交
892 893
    }

894
    /* TODO: processing NAT and physical device */
D
Daniel Veillard 已提交
895

896 897
    virCommandAddArg(cmd, "--save");
    rc = virCommandRun(cmd, NULL);
D
Daniel Veillard 已提交
898

899 900
 cleanup:
    virCommandFree(cmd);
901
    VIR_FREE(guest_ifname);
D
Daniel Veillard 已提交
902 903 904
    return rc;
}

905 906 907 908 909

static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
                             virDomainDefPtr def)
{
910
    size_t i;
911 912 913
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *param;
    int first = 1;
914
    struct openvz_driver *driver =  conn->privateData;
915

916
    for (i = 0; i < def->nnets; i++) {
917 918 919 920 921 922 923 924 925
        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) {
926 927
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not configure network"));
928 929 930 931 932 933 934
            goto exit;
        }
    }

    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
        param = virBufferContentAndReset(&buf);
        if (param) {
935
            if (openvzWriteVPSConfigParam(strtoI(def->name), "NETIF", param) < 0) {
936
                VIR_FREE(param);
937 938
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot replace NETIF config"));
939 940 941 942 943 944 945 946 947
                return -1;
            }
            VIR_FREE(param);
        }
    }

    return 0;

exit:
948
    virBufferFreeAndReset(&buf);
949 950 951 952
    return -1;
}


953 954 955
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
956
    struct openvz_driver *driver =  conn->privateData;
957 958
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
959
    virDomainPtr dom = NULL;
960

961
    openvzDriverLock(driver);
962 963
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                         1 << VIR_DOMAIN_VIRT_OPENVZ,
964
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
965
        goto cleanup;
966

967
    vm = virDomainObjListFindByName(driver->domains, vmdef->name);
968
    if (vm) {
969 970 971
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Already an OPENVZ VM active with the id '%s'"),
                       vmdef->name);
972
        goto cleanup;
973
    }
974
    if (!(vm = virDomainObjListAdd(driver->domains, vmdef,
975
                                   driver->xmlopt,
976
                                   0, NULL)))
977 978
        goto cleanup;
    vmdef = NULL;
979
    vm->persistent = 1;
980

981
    if (openvzSetInitialConfig(vm->def) < 0) {
982
        VIR_ERROR(_("Error creating initial configuration"));
983
        goto cleanup;
984 985
    }

986
    if (vm->def->nfss == 1) {
987
        if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
988 989
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set disk quota"));
990 991 992
            goto cleanup;
        }
    }
D
Daniel Veillard 已提交
993

994
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
995 996
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set UUID"));
997
        goto cleanup;
998 999
    }

1000 1001
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1002

E
Eric Blake 已提交
1003
    if (vm->def->vcpus != vm->def->maxvcpus) {
1004 1005
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
1006 1007 1008 1009
        goto cleanup;
    }
    if (vm->def->maxvcpus > 0) {
        if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
1010
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1011
                           _("Could not set number of vCPUs"));
1012
             goto cleanup;
1013 1014 1015
        }
    }

1016 1017
    if (vm->def->mem.cur_balloon > 0) {
        if (openvzDomainSetMemoryInternal(vm, vm->def->mem.cur_balloon) < 0) {
1018 1019
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set memory size"));
1020 1021 1022 1023
             goto cleanup;
        }
    }

1024 1025 1026 1027 1028 1029
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

cleanup:
    virDomainDefFree(vmdef);
1030
    if (vm)
1031
        virObjectUnlock(vm);
1032
    openvzDriverUnlock(driver);
1033 1034 1035 1036
    return dom;
}

static virDomainPtr
1037
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
1038
                      unsigned int flags)
1039
{
1040
    struct openvz_driver *driver =  conn->privateData;
1041 1042
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
1043
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
1044
    const char *progstart[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL};
1045

1046 1047
    virCheckFlags(0, NULL);

1048
    openvzDriverLock(driver);
1049 1050
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                         1 << VIR_DOMAIN_VIRT_OPENVZ,
1051
                                         VIR_DOMAIN_XML_INACTIVE)) == NULL)
1052
        goto cleanup;
1053

1054
    vm = virDomainObjListFindByName(driver->domains, vmdef->name);
1055
    if (vm) {
1056 1057 1058
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Already an OPENVZ VM defined with the id '%s'"),
                       vmdef->name);
1059
        goto cleanup;
1060
    }
1061
    if (!(vm = virDomainObjListAdd(driver->domains,
1062
                                   vmdef,
1063
                                   driver->xmlopt,
1064 1065
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1066 1067
        goto cleanup;
    vmdef = NULL;
1068 1069 1070
    /* 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;
1071

1072
    if (openvzSetInitialConfig(vm->def) < 0) {
1073
        VIR_ERROR(_("Error creating initial configuration"));
1074
        goto cleanup;
1075
    }
1076

1077
    if (vm->def->nfss == 1) {
1078
        if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
1079 1080
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not set disk quota"));
1081 1082 1083 1084
            goto cleanup;
        }
    }

1085
    if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
1086 1087
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set UUID"));
1088
        goto cleanup;
1089 1090
    }

1091 1092
    if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1093

1094
    openvzSetProgramSentinal(progstart, vm->def->name);
1095

1096
    if (virRun(progstart, NULL) < 0) {
1097
        goto cleanup;
1098
    }
1099

1100
    vm->pid = strtoI(vm->def->name);
1101
    vm->def->id = vm->pid;
J
Jiri Denemark 已提交
1102
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1103

E
Eric Blake 已提交
1104 1105
    if (vm->def->maxvcpus > 0) {
        if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
1106
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1107
                           _("Could not set number of vCPUs"));
1108
            goto cleanup;
1109 1110 1111
        }
    }

1112 1113 1114 1115 1116 1117
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

cleanup:
    virDomainDefFree(vmdef);
1118
    if (vm)
1119
        virObjectUnlock(vm);
1120
    openvzDriverUnlock(driver);
1121 1122 1123 1124
    return dom;
}

static int
1125
openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
1126
{
1127 1128
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1129
    const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL };
1130
    int ret = -1;
1131
    int status;
1132

1133 1134
    virCheckFlags(0, -1);

1135
    openvzDriverLock(driver);
1136
    vm = virDomainObjListFindByName(driver->domains, dom->name);
1137 1138
    openvzDriverUnlock(driver);

1139
    if (!vm) {
1140 1141
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching id"));
1142
        goto cleanup;
1143
    }
1144

1145 1146 1147 1148
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

    if (status != VIR_DOMAIN_SHUTOFF) {
1149 1150
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("domain is not in shutoff state"));
1151
        goto cleanup;
1152 1153
    }

1154
    openvzSetProgramSentinal(prog, vm->def->name);
1155
    if (virRun(prog, NULL) < 0) {
1156
        goto cleanup;
1157
    }
1158

1159 1160
    vm->pid = strtoI(vm->def->name);
    vm->def->id = vm->pid;
1161
    dom->id = vm->pid;
J
Jiri Denemark 已提交
1162
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1163
    ret = 0;
1164

1165
cleanup:
1166
    if (vm)
1167
        virObjectUnlock(vm);
1168
    return ret;
1169 1170
}

1171 1172 1173 1174 1175 1176
static int
openvzDomainCreate(virDomainPtr dom)
{
    return openvzDomainCreateWithFlags(dom, 0);
}

1177
static int
1178 1179
openvzDomainUndefineFlags(virDomainPtr dom,
                          unsigned int flags)
1180
{
1181 1182
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1183
    const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINEL, NULL };
1184
    int ret = -1;
1185
    int status;
1186

1187 1188
    virCheckFlags(0, -1);

1189
    openvzDriverLock(driver);
1190
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1191
    if (!vm) {
1192 1193
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1194
        goto cleanup;
1195
    }
1196

1197 1198 1199
    if (openvzGetVEStatus(vm, &status, NULL) == -1)
        goto cleanup;

1200
    openvzSetProgramSentinal(prog, vm->def->name);
1201
    if (virRun(prog, NULL) < 0) {
1202
        goto cleanup;
1203
    }
1204

1205 1206 1207
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
1208
        virDomainObjListRemove(driver->domains, vm);
1209 1210 1211
        vm = NULL;
    }

1212
    ret = 0;
1213

1214
cleanup:
1215
    if (vm)
1216
        virObjectUnlock(vm);
1217
    openvzDriverUnlock(driver);
1218
    return ret;
1219 1220
}

1221 1222 1223 1224 1225
static int
openvzDomainUndefine(virDomainPtr dom)
{
    return openvzDomainUndefineFlags(dom, 0);
}
1226 1227 1228
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
1229 1230
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
E
Eric Blake 已提交
1231
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
D
Daniel Veillard 已提交
1232
                           "--onboot", autostart ? "yes" : "no",
1233
                           "--save", NULL };
1234
    int ret = -1;
1235

1236
    openvzDriverLock(driver);
1237
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1238 1239
    openvzDriverUnlock(driver);

1240
    if (!vm) {
1241 1242
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1243
        goto cleanup;
1244 1245
    }

1246
    openvzSetProgramSentinal(prog, vm->def->name);
1247
    if (virRun(prog, NULL) < 0) {
1248
        goto cleanup;
1249
    }
1250
    ret = 0;
1251

1252
cleanup:
1253
    if (vm)
1254
        virObjectUnlock(vm);
1255
    return ret;
1256 1257 1258 1259 1260
}

static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
1261 1262
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1263
    char *value = NULL;
1264
    int ret = -1;
1265

1266
    openvzDriverLock(driver);
1267
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1268 1269
    openvzDriverUnlock(driver);

1270
    if (!vm) {
1271 1272
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1273
        goto cleanup;
1274 1275
    }

1276
    if (openvzReadVPSConfigParam(strtoI(vm->def->name), "ONBOOT", &value) < 0) {
1277 1278
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not read container config"));
1279
        goto cleanup;
1280 1281 1282 1283
    }

    *autostart = 0;
    if (STREQ(value,"yes"))
D
Daniel Veillard 已提交
1284
        *autostart = 1;
1285
    ret = 0;
1286

1287
cleanup:
1288 1289
    VIR_FREE(value);

1290
    if (vm)
1291
        virObjectUnlock(vm);
1292
    return ret;
1293 1294
}

1295 1296
static int openvzConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
                                    const char *type)
1297 1298 1299
{
    if (type == NULL || STRCASEEQ(type, "openvz"))
        return 1028; /* OpenVZ has no limitation */
1300

1301 1302
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1303 1304 1305
    return -1;
}

1306 1307 1308 1309
static int
openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED,
                          unsigned int flags)
{
1310
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1311 1312
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported flags (0x%x)"), flags);
1313 1314
        return -1;
    }
1315

1316
    return openvzConnectGetMaxVcpus(NULL, "openvz");
1317 1318
}

1319 1320
static int openvzDomainGetMaxVcpus(virDomainPtr dom)
{
1321
    return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
1322 1323 1324
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}

1325 1326
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
                                        unsigned int nvcpus)
1327 1328
{
    char        str_vcpus[32];
E
Eric Blake 已提交
1329
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
1330
                           "--cpus", str_vcpus, "--save", NULL };
1331
    unsigned int pcpus;
1332 1333 1334 1335 1336 1337 1338 1339
    pcpus = openvzGetNodeCPUs();
    if (pcpus > 0 && pcpus < nvcpus)
        nvcpus = pcpus;

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

    openvzSetProgramSentinal(prog, vm->def->name);
1340
    if (virRun(prog, NULL) < 0) {
1341 1342 1343
        return -1;
    }

E
Eric Blake 已提交
1344
    vm->def->maxvcpus = vm->def->vcpus = nvcpus;
1345 1346 1347
    return 0;
}

1348 1349
static int openvzDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                                     unsigned int flags)
1350 1351 1352 1353
{
    virDomainObjPtr         vm;
    struct openvz_driver   *driver = dom->conn->privateData;
    int                     ret = -1;
1354

1355
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
1356 1357
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported flags (0x%x)"), flags);
1358 1359 1360
        return -1;
    }

1361
    openvzDriverLock(driver);
1362
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1363 1364
    openvzDriverUnlock(driver);

1365
    if (!vm) {
1366 1367
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1368
        goto cleanup;
1369 1370
    }

1371
    if (nvcpus <= 0) {
1372
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1373 1374 1375 1376 1377 1378 1379
                       _("Number of vCPUs should be >= 1"));
        goto cleanup;
    }

    if (openvzDomainSetVcpusInternal(vm, nvcpus) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not set number of vCPUs"));
1380
        goto cleanup;
1381 1382
    }

1383 1384 1385
    ret = 0;

cleanup:
1386
    if (vm)
1387
        virObjectUnlock(vm);
1388
    return ret;
1389 1390
}

1391 1392 1393
static int
openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
1394
    return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
1395 1396
}

1397 1398 1399
static virDrvOpenStatus openvzConnectOpen(virConnectPtr conn,
                                          virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                          unsigned int flags)
1400
{
1401
    struct openvz_driver *driver;
1402

E
Eric Blake 已提交
1403 1404
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1405
    if (conn->uri == NULL) {
1406 1407 1408 1409 1410 1411
        if (!virFileExists("/proc/vz"))
            return VIR_DRV_OPEN_DECLINED;

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

1412
        if (!(conn->uri = virURIParse("openvz:///system")))
1413 1414 1415 1416
            return VIR_DRV_OPEN_ERROR;
    } else {
        /* If scheme isn't 'openvz', then its for another driver */
        if (conn->uri->scheme == NULL ||
1417
            STRNEQ(conn->uri->scheme, "openvz"))
1418 1419 1420 1421 1422 1423 1424 1425
            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 ||
1426
            STRNEQ(conn->uri->path, "/system")) {
1427 1428 1429
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected OpenVZ URI path '%s', try openvz:///system"),
                           conn->uri->path);
1430 1431 1432 1433
            return VIR_DRV_OPEN_ERROR;
        }

        if (!virFileExists("/proc/vz")) {
1434 1435
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("OpenVZ control file /proc/vz does not exist"));
1436 1437 1438 1439
            return VIR_DRV_OPEN_ERROR;
        }

        if (access("/proc/vz", W_OK) < 0) {
1440 1441
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("OpenVZ control file /proc/vz is not accessible"));
1442 1443
            return VIR_DRV_OPEN_ERROR;
        }
1444 1445
    }

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

1449
    if (VIR_ALLOC(driver) < 0)
1450 1451
        return VIR_DRV_OPEN_ERROR;

1452
    if (!(driver->domains = virDomainObjListNew()))
1453 1454
        goto cleanup;

1455 1456
    if (!(driver->caps = openvzCapsInit()))
        goto cleanup;
1457

1458 1459
    if (!(driver->xmlopt = virDomainXMLOptionNew(&openvzDomainDefParserConfig,
                                                 NULL, NULL)))
1460 1461
        goto cleanup;

1462 1463
    if (openvzLoadDomains(driver) < 0)
        goto cleanup;
1464

1465
    if (openvzExtractVersion(driver) < 0)
1466 1467
        goto cleanup;

1468
    conn->privateData = driver;
1469

1470
    return VIR_DRV_OPEN_SUCCESS;
1471

1472 1473 1474
cleanup:
    openvzFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
1475
};
1476

1477
static int openvzConnectClose(virConnectPtr conn) {
1478
    struct openvz_driver *driver = conn->privateData;
1479

1480
    openvzFreeDriver(driver);
1481 1482 1483 1484 1485
    conn->privateData = NULL;

    return 0;
}

1486
static const char *openvzConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1487
    return "OpenVZ";
1488 1489
}

1490
static int openvzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) {
1491 1492 1493 1494
    /* Encryption is not relevant / applicable to way we talk to openvz */
    return 0;
}

1495
static int openvzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) {
1496 1497 1498 1499
    /* We run CLI tools directly so this is secure */
    return 1;
}

1500
static int
1501
openvzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1502 1503 1504 1505
{
    return 1;
}

1506
static char *openvzConnectGetCapabilities(virConnectPtr conn) {
1507 1508 1509
    struct openvz_driver *driver = conn->privateData;
    char *ret;

1510
    openvzDriverLock(driver);
1511
    ret = virCapabilitiesFormatXML(driver->caps);
1512
    openvzDriverUnlock(driver);
1513

1514
    return ret;
1515 1516
}

1517 1518
static int openvzConnectListDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
                                    int *ids, int nids) {
1519
    int got = 0;
1520
    int veid;
1521
    int outfd = -1;
1522
    int rc = -1;
1523 1524
    int ret;
    char buf[32];
1525
    char *endptr;
1526 1527 1528 1529 1530
    virCommandPtr cmd = virCommandNewArgList(VZLIST, "-ovpsid", "-H" , NULL);

    virCommandSetOutputFD(cmd, &outfd);
    if (virCommandRunAsync(cmd, NULL) < 0)
        goto cleanup;
1531

E
Eric Blake 已提交
1532
    while (got < nids) {
1533
        ret = openvz_readline(outfd, buf, 32);
E
Eric Blake 已提交
1534 1535
        if (!ret)
            break;
1536
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1537 1538
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse VPS ID %s"), buf);
1539 1540
            continue;
        }
1541 1542 1543
        ids[got] = veid;
        got ++;
    }
1544 1545 1546

    if (virCommandWait(cmd, NULL) < 0)
        goto cleanup;
1547

G
Guido Günther 已提交
1548 1549
    if (VIR_CLOSE(outfd) < 0) {
        virReportSystemError(errno, "%s", _("failed to close file"));
1550
        goto cleanup;
G
Guido Günther 已提交
1551
    }
1552 1553 1554 1555 1556 1557

    rc = got;
cleanup:
    VIR_FORCE_CLOSE(outfd);
    virCommandFree(cmd);
    return rc;
1558 1559
}

1560
static int openvzConnectNumOfDomains(virConnectPtr conn) {
1561
    struct openvz_driver *driver = conn->privateData;
1562
    int n;
1563

1564
    openvzDriverLock(driver);
1565
    n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
1566
    openvzDriverUnlock(driver);
1567

1568
    return n;
1569 1570
}

1571 1572
static int openvzConnectListDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           char **const names, int nnames) {
1573
    int got = 0;
G
Guido Günther 已提交
1574
    int veid, outfd = -1, ret;
1575
    int rc = -1;
1576
    char vpsname[32];
1577
    char buf[32];
1578
    char *endptr;
1579 1580
    virCommandPtr cmd = virCommandNewArgList(VZLIST,
                                             "-ovpsid", "-H", "-S", NULL);
1581 1582

    /* the -S options lists only stopped domains */
1583 1584
    virCommandSetOutputFD(cmd, &outfd);
    if (virCommandRunAsync(cmd, NULL) < 0)
G
Guido Günther 已提交
1585
        goto out;
1586

E
Eric Blake 已提交
1587
    while (got < nnames) {
1588
        ret = openvz_readline(outfd, buf, 32);
E
Eric Blake 已提交
1589 1590
        if (!ret)
            break;
1591
        if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
1592 1593
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse VPS ID %s"), buf);
1594 1595
            continue;
        }
1596
        snprintf(vpsname, sizeof(vpsname), "%d", veid);
1597
        if (VIR_STRDUP(names[got], vpsname) < 0)
G
Guido Günther 已提交
1598
            goto out;
1599 1600
        got ++;
    }
1601 1602 1603 1604

    if (virCommandWait(cmd, NULL) < 0)
        goto out;

G
Guido Günther 已提交
1605 1606 1607 1608
    if (VIR_CLOSE(outfd) < 0) {
        virReportSystemError(errno, "%s", _("failed to close file"));
        goto out;
    }
1609

1610
    rc = got;
G
Guido Günther 已提交
1611 1612
out:
    VIR_FORCE_CLOSE(outfd);
1613
    virCommandFree(cmd);
1614
    if (rc < 0) {
1615
        for (; got >= 0; got--)
1616 1617 1618
            VIR_FREE(names[got]);
    }
    return rc;
1619 1620
}

1621 1622 1623 1624 1625
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid)
{
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
D
Daniel Veillard 已提交
1626
    unsigned long long usertime, systime, nicetime;
1627
    int readvps = vpsid + 1;  /* ensure readvps is initially different */
1628
    ssize_t ret;
1629
    int err = 0;
D
Daniel Veillard 已提交
1630 1631 1632 1633

/* read statistic from /proc/vz/vestat.
sample:
Version: 2.2
1634 1635 1636
   VEID     user      nice     system     uptime                 idle   other..
     33       78         0       1330   59454597      142650441835148   other..
     55      178         0       5340   59424597      542650441835148   other..
D
Daniel Veillard 已提交
1637 1638
*/

1639
    if ((fp = fopen("/proc/vz/vestat", "r")) == NULL)
D
Daniel Veillard 已提交
1640 1641 1642
        return -1;

    /*search line with VEID=vpsid*/
E
Eric Blake 已提交
1643
    while (1) {
1644
        ret = getline(&line, &line_size, fp);
1645 1646
        if (ret < 0) {
            err = !feof(fp);
D
Daniel Veillard 已提交
1647
            break;
1648
        }
D
Daniel Veillard 已提交
1649

1650 1651
        if (sscanf(line, "%d %llu %llu %llu",
                   &readvps, &usertime, &nicetime, &systime) == 4
1652 1653 1654 1655 1656 1657 1658
            && 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 已提交
1659 1660
    }

1661 1662
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
1663
    if (err)
D
Daniel Veillard 已提交
1664 1665 1666 1667 1668 1669 1670 1671
        return -1;

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

    return 0;
}

1672
static int openvzConnectNumOfDefinedDomains(virConnectPtr conn) {
1673
    struct openvz_driver *driver =  conn->privateData;
1674
    int n;
1675

1676
    openvzDriverLock(driver);
1677
    n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
1678
    openvzDriverUnlock(driver);
1679

1680
    return n;
1681 1682
}

1683
static int
1684
openvzDomainSetMemoryInternal(virDomainObjPtr vm,
1685
                              unsigned long long mem)
1686 1687
{
    char str_mem[16];
E
Eric Blake 已提交
1688
    const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
1689 1690 1691 1692
        "--kmemsize", str_mem, "--save", NULL
    };

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

    openvzSetProgramSentinal(prog, vm->def->name);
1696
    if (virRun(prog, NULL) < 0) {
1697 1698 1699 1700 1701 1702 1703 1704 1705
        goto cleanup;
    }

    return 0;

cleanup:
    return -1;
}

1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720

static int
openvzDomainGetBarrierLimit(virDomainPtr domain,
                            const char *param,
                            unsigned long long *barrier,
                            unsigned long long *limit)
{
    int status, ret = -1;
    char *endp, *output = NULL;
    const char *tmp;
    virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL);

    virCommandSetOutputBuffer(cmd, &output);
    virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param);
    virCommandAddArg(cmd, domain->name);
1721
    if (virCommandRun(cmd, &status) < 0 || status != 0) {
1722 1723 1724
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Failed to get %s for %s: %d"), param, domain->name,
                       status);
1725 1726 1727 1728 1729 1730
        goto cleanup;
    }

    tmp = output;
    virSkipSpaces(&tmp);
    if (virStrToLong_ull(tmp, &endp, 10, barrier) < 0) {
1731 1732
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Can't parse limit from "VZLIST" output '%s'"), output);
1733 1734 1735 1736 1737
        goto cleanup;
    }
    tmp = endp;
    virSkipSpaces(&tmp);
    if (virStrToLong_ull(tmp, &endp, 10, limit) < 0) {
1738 1739
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Can't parse barrier from "VZLIST" output '%s'"), output);
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
        goto cleanup;
    }

    ret = 0;
cleanup:
    VIR_FREE(output);
    virCommandFree(cmd);
    return ret;
}


static int
openvzDomainSetBarrierLimit(virDomainPtr domain,
                            const  char *param,
                            unsigned long long barrier,
                            unsigned long long limit)
{
    int status, ret = -1;
    virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL);

    /* LONG_MAX indicates unlimited so reject larger values */
    if (barrier > LONG_MAX || limit > LONG_MAX) {
1762 1763 1764
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Failed to set %s for %s: value too large"), param,
                       domain->name);
1765 1766 1767 1768 1769 1770 1771
        goto cleanup;
    }

    virCommandAddArg(cmd, domain->name);
    virCommandAddArgFormat(cmd, "--%s", param);
    virCommandAddArgFormat(cmd, "%llu:%llu", barrier, limit);
    virCommandAddArg(cmd, "--save");
1772
    if (virCommandRun(cmd, &status) < 0 || status != 0) {
1773 1774 1775
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Failed to set %s for %s: %d"), param, domain->name,
                       status);
1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
        goto cleanup;
    }

    ret = 0;
cleanup:
    virCommandFree(cmd);
    return ret;
}


static int
openvzDomainGetMemoryParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
{
1792 1793
    size_t i;
    int result = -1;
1794 1795 1796 1797 1798 1799
    const char *name;
    long kb_per_pages;
    unsigned long long barrier, limit, val;

    virCheckFlags(0, -1);

1800 1801
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
        goto cleanup;

    if (*nparams == 0) {
        *nparams = OPENVZ_NB_MEM_PARAM;
        return 0;
    }

    for (i = 0; i <= *nparams; i++) {
        virMemoryParameterPtr param = &params[i];

        switch (i) {
        case 0:
            name = "privvmpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

            val = (limit == LONG_MAX) ? 0ull : limit * kb_per_pages;
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;

        case 1:
            name = "privvmpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

            val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;

        case 2:
            name = "vmguarpages";
            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
                goto cleanup;

            val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
                goto cleanup;
            break;
        }
    }

    if (*nparams > OPENVZ_NB_MEM_PARAM)
        *nparams = OPENVZ_NB_MEM_PARAM;
    result = 0;

cleanup:
    return result;
}


static int
openvzDomainSetMemoryParameters(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
{
1863 1864
    size_t i;
    int result = -1;
1865 1866
    long kb_per_pages;

1867 1868
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
1869 1870 1871
        goto cleanup;

    virCheckFlags(0, -1);
1872 1873 1874 1875 1876 1877 1878 1879
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_MEMORY_HARD_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
        return -1;

    for (i = 0; i < nparams; i++) {
        virTypedParameterPtr param = &params[i];
        unsigned long long barrier, limit;

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
                                            &barrier, &limit) < 0)
                goto cleanup;
            limit = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
                                            barrier, limit) < 0)
                goto cleanup;
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
                                            &barrier, &limit) < 0)
                goto cleanup;
            barrier = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
                                            barrier, limit) < 0)
                goto cleanup;
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
            barrier = params[i].value.ul / kb_per_pages;
            if (openvzDomainSetBarrierLimit(domain, "vmguarpages",
                                            barrier, LONG_MAX) < 0)
                goto cleanup;
        }
    }
    result = 0;
cleanup:
    return result;
}


1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
static int
openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason)
{
    virCommandPtr cmd;
    char *outbuf;
    char *line;
    int state;
    int ret = -1;

    cmd = virCommandNewArgList(VZLIST, vm->def->name, "-ostatus", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    if ((line = strchr(outbuf, '\n')) == NULL) {
1930 1931
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to parse vzlist output"));
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
        goto cleanup;
    }
    *line++ = '\0';

    state = virDomainObjGetState(vm, reason);

    if (STREQ(outbuf, "running")) {
        /* There is no way to detect whether a domain is paused or not
         * with vzlist */
        if (state == VIR_DOMAIN_PAUSED)
            *status = state;
        else
            *status = VIR_DOMAIN_RUNNING;
    } else {
        *status = VIR_DOMAIN_SHUTOFF;
    }

    ret = 0;

cleanup:
    virCommandFree(cmd);
    VIR_FREE(outbuf);
    return ret;
}

1957
static int
1958 1959 1960
openvzDomainInterfaceStats(virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
1961 1962 1963
{
    struct openvz_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1964
    size_t i;
1965 1966 1967
    int ret = -1;

    openvzDriverLock(driver);
1968
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1969 1970 1971 1972 1973
    openvzDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1974 1975
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1976 1977 1978 1979
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
1980 1981
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1982 1983 1984 1985
        goto cleanup;
    }

    /* Check the path is one of the domain's network interfaces. */
1986
    for (i = 0; i < vm->def->nnets; i++) {
1987
        if (vm->def->nets[i]->ifname &&
1988
            STREQ(vm->def->nets[i]->ifname, path)) {
1989 1990 1991 1992 1993 1994 1995 1996
            ret = 0;
            break;
        }
    }

    if (ret == 0)
        ret = linuxDomainInterfaceStats(path, stats);
    else
1997 1998
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
1999 2000 2001

cleanup:
    if (vm)
2002
        virObjectUnlock(vm);
2003 2004 2005 2006
    return ret;
}


2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
static int
openvzUpdateDevice(virDomainDefPtr vmdef,
                   virDomainDeviceDefPtr dev,
                   bool persist)
{
    virDomainFSDefPtr fs, cur;
    int pos;

    if (dev->type == VIR_DOMAIN_DEVICE_FS) {
        fs = dev->data.fs;
        pos = virDomainFSIndexByName(vmdef, fs->dst);

        if (pos < 0) {
2020 2021
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), fs->dst);
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031
            return -1;
        }
        cur = vmdef->fss[pos];

        /* We only allow updating the quota */
        if (!STREQ(cur->src, fs->src)
            || cur->type != fs->type
            || cur->accessmode != fs->accessmode
            || cur->wrpolicy != fs->wrpolicy
            || cur->readonly != fs->readonly) {
2032
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2033
                           _("Can only modify disk quota"));
2034 2035 2036 2037 2038 2039 2040 2041 2042
            return -1;
        }

        if (openvzSetDiskQuota(vmdef, fs, persist) < 0) {
            return -1;
        }
        cur->space_hard_limit = fs->space_hard_limit;
        cur->space_soft_limit = fs->space_soft_limit;
    } else {
2043 2044 2045
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can't modify device type '%s'"),
                       virDomainDeviceTypeToString(dev->type));
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068
        return -1;
    }

    return 0;
}


static int
openvzDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
{
    int ret = -1;
    int veid;
    struct  openvz_driver *driver = dom->conn->privateData;
    virDomainDeviceDefPtr dev = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    bool persist = false;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

    openvzDriverLock(driver);
2069
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2070 2071

    if (!vm) {
2072 2073
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2074 2075
        goto cleanup;
    }
2076
    vmdef = vm->def;
2077 2078

    if (virStrToLong_i(vmdef->name, NULL, 10, &veid) < 0) {
2079 2080
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not convert domain name to VEID"));
2081 2082 2083 2084
        goto cleanup;
    }

    if (virDomainLiveConfigHelperMethod(driver->caps,
2085
                                        driver->xmlopt,
2086 2087 2088 2089 2090
                                        vm,
                                        &flags,
                                        &vmdef) < 0)
        goto cleanup;

2091 2092
    dev = virDomainDeviceDefParse(xml, vmdef, driver->caps, driver->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
    if (!dev)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG)
        persist = true;

    if (openvzUpdateDevice(vmdef, dev, persist) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    openvzDriverUnlock(driver);
    virDomainDeviceDefFree(dev);
    if (vm)
2108
        virObjectUnlock(vm);
2109 2110 2111
    return ret;
}

2112
static int
2113 2114 2115
openvzConnectListAllDomains(virConnectPtr conn,
                            virDomainPtr **domains,
                            unsigned int flags)
2116 2117 2118 2119
{
    struct openvz_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2120
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2121 2122

    openvzDriverLock(driver);
2123 2124
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 NULL, flags);
2125 2126 2127 2128 2129
    openvzDriverUnlock(driver);

    return ret;
}

2130

2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188

static int
openvzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                  virNodeInfoPtr nodeinfo)
{
    return nodeGetInfo(nodeinfo);
}


static int
openvzNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                      int cpuNum,
                      virNodeCPUStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
openvzNodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
                         int cellNum,
                         virNodeMemoryStatsPtr params,
                         int *nparams,
                         unsigned int flags)
{
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
openvzNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                             unsigned long long *freeMems,
                             int startCell,
                             int maxCells)
{
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
openvzNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return nodeGetFreeMemory();
}


static int
openvzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
                    unsigned char **cpumap,
                    unsigned int *online,
                    unsigned int flags)
{
    return nodeGetCPUMap(cpumap, online, flags);
}


2189
static virDriver openvzDriver = {
2190 2191
    .no = VIR_DRV_OPENVZ,
    .name = "OPENVZ",
2192 2193 2194 2195
    .connectOpen = openvzConnectOpen, /* 0.3.1 */
    .connectClose = openvzConnectClose, /* 0.3.1 */
    .connectGetType = openvzConnectGetType, /* 0.3.1 */
    .connectGetVersion = openvzConnectGetVersion, /* 0.5.0 */
2196
    .connectGetHostname = openvzConnectGetHostname, /* 0.9.12 */
2197
    .connectGetMaxVcpus = openvzConnectGetMaxVcpus, /* 0.4.6 */
2198 2199 2200 2201 2202 2203
    .nodeGetInfo = openvzNodeGetInfo, /* 0.3.2 */
    .nodeGetCPUStats = openvzNodeGetCPUStats, /* 0.9.12 */
    .nodeGetMemoryStats = openvzNodeGetMemoryStats, /* 0.9.12 */
    .nodeGetCellsFreeMemory = openvzNodeGetCellsFreeMemory, /* 0.9.12 */
    .nodeGetFreeMemory = openvzNodeGetFreeMemory, /* 0.9.12 */
    .nodeGetCPUMap = openvzNodeGetCPUMap, /* 1.0.0 */
2204 2205 2206 2207
    .connectGetCapabilities = openvzConnectGetCapabilities, /* 0.4.6 */
    .connectListDomains = openvzConnectListDomains, /* 0.3.1 */
    .connectNumOfDomains = openvzConnectNumOfDomains, /* 0.3.1 */
    .connectListAllDomains = openvzConnectListAllDomains, /* 0.9.13 */
2208 2209 2210 2211 2212 2213 2214
    .domainCreateXML = openvzDomainCreateXML, /* 0.3.3 */
    .domainLookupByID = openvzDomainLookupByID, /* 0.3.1 */
    .domainLookupByUUID = openvzDomainLookupByUUID, /* 0.3.1 */
    .domainLookupByName = openvzDomainLookupByName, /* 0.3.1 */
    .domainSuspend = openvzDomainSuspend, /* 0.8.3 */
    .domainResume = openvzDomainResume, /* 0.8.3 */
    .domainShutdown = openvzDomainShutdown, /* 0.3.1 */
2215
    .domainShutdownFlags = openvzDomainShutdownFlags, /* 0.9.10 */
2216
    .domainReboot = openvzDomainReboot, /* 0.3.1 */
2217 2218 2219
    .domainDestroy = openvzDomainDestroy, /* 0.3.1 */
    .domainDestroyFlags = openvzDomainDestroyFlags, /* 0.9.4 */
    .domainGetOSType = openvzDomainGetOSType, /* 0.3.1 */
2220 2221
    .domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */
    .domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */
2222 2223 2224 2225 2226 2227 2228
    .domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */
    .domainGetState = openvzDomainGetState, /* 0.9.2 */
    .domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */
    .domainSetVcpusFlags = openvzDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = openvzDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = openvzDomainGetMaxVcpus, /* 0.4.6 */
    .domainGetXMLDesc = openvzDomainGetXMLDesc, /* 0.4.6 */
2229 2230
    .connectListDefinedDomains = openvzConnectListDefinedDomains, /* 0.3.1 */
    .connectNumOfDefinedDomains = openvzConnectNumOfDefinedDomains, /* 0.3.1 */
2231 2232 2233 2234
    .domainCreate = openvzDomainCreate, /* 0.3.1 */
    .domainCreateWithFlags = openvzDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = openvzDomainDefineXML, /* 0.3.3 */
    .domainUndefine = openvzDomainUndefine, /* 0.3.3 */
2235
    .domainUndefineFlags = openvzDomainUndefineFlags, /* 0.9.4 */
2236 2237
    .domainGetAutostart = openvzDomainGetAutostart, /* 0.4.6 */
    .domainSetAutostart = openvzDomainSetAutostart, /* 0.4.6 */
2238
    .domainInterfaceStats = openvzDomainInterfaceStats, /* 0.9.12 */
2239 2240
    .connectIsEncrypted = openvzConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = openvzConnectIsSecure, /* 0.7.3 */
2241 2242 2243
    .domainIsActive = openvzDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = openvzDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = openvzDomainIsUpdated, /* 0.8.6 */
2244
    .connectIsAlive = openvzConnectIsAlive, /* 0.9.8 */
2245
    .domainUpdateDeviceFlags = openvzDomainUpdateDeviceFlags, /* 0.9.13 */
2246
    .domainGetHostname = openvzDomainGetHostname, /* 0.10.0 */
2247 2248 2249 2250 2251 2252
};

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