vmware_driver.c 32.0 KB
Newer Older
1
/*---------------------------------------------------------------------------*/
E
Eric Blake 已提交
2
/*
3
 * Copyright (C) 2011-2015 Red Hat, Inc.
E
Eric Blake 已提交
4
 * Copyright 2010, diateam (www.diateam.net)
5
 * Copyright (C) 2013. Doug Goldstein <cardoe@cardoe.com>
6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26
 */
/*---------------------------------------------------------------------------*/

#include <config.h>

#include <fcntl.h>

27
#include "internal.h"
28
#include "virerror.h"
29
#include "datatypes.h"
E
Eric Blake 已提交
30
#include "virfile.h"
31
#include "viralloc.h"
32
#include "viruuid.h"
33
#include "vircommand.h"
34
#include "vmx.h"
35 36
#include "vmware_conf.h"
#include "vmware_driver.h"
37
#include "virstring.h"
38

39 40 41 42 43
/* Various places we may find the "vmrun" binary,
 * without a leading / it will be searched in PATH
 */
static const char * const vmrun_candidates[] = {
    "vmrun",
44 45 46 47
#ifdef __APPLE__
    "/Applications/VMware Fusion.app/Contents/Library/vmrun",
    "/Library/Application Support/VMware Fusion/vmrun",
#endif /* __APPLE__ */
48 49
};

50 51 52 53 54 55 56 57 58 59 60 61
static void
vmwareDriverLock(struct vmware_driver *driver)
{
    virMutexLock(&driver->lock);
}

static void
vmwareDriverUnlock(struct vmware_driver *driver)
{
    virMutexUnlock(&driver->lock);
}

62 63 64 65 66 67 68 69

static virDomainObjPtr
vmwareDomObjFromDomainLocked(struct vmware_driver *driver,
                             const unsigned char *uuid)
{
    virDomainObjPtr vm;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

70
    if (!(vm = virDomainObjListFindByUUID(driver->domains, uuid))) {
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
        virUUIDFormat(uuid, uuidstr);

        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        return NULL;
    }

    return vm;
}


static virDomainObjPtr
vmwareDomObjFromDomain(struct vmware_driver *driver,
                       const unsigned char *uuid)
{
    virDomainObjPtr vm;

    vmwareDriverLock(driver);
    vm = vmwareDomObjFromDomainLocked(driver, uuid);
    vmwareDriverUnlock(driver);
    return vm;
}


95
static void *
96
vmwareDataAllocFunc(void *opaque ATTRIBUTE_UNUSED)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
{
    vmwareDomainPtr dom;

    if (VIR_ALLOC(dom) < 0)
        return NULL;

    dom->vmxPath = NULL;
    dom->gui = true;

    return dom;
}

static void
vmwareDataFreeFunc(void *data)
{
    vmwareDomainPtr dom = data;

    VIR_FREE(dom->vmxPath);
    VIR_FREE(dom);
}

118
static int
119
vmwareDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
120
                         virCapsPtr caps ATTRIBUTE_UNUSED,
121
                         unsigned int parseFlags ATTRIBUTE_UNUSED,
122 123
                         void *opaque ATTRIBUTE_UNUSED,
                         void *parseOpaque ATTRIBUTE_UNUSED)
124 125 126 127 128 129 130 131
{
    return 0;
}

static int
vmwareDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                               const virDomainDef *def ATTRIBUTE_UNUSED,
                               virCapsPtr caps ATTRIBUTE_UNUSED,
132
                               unsigned int parseFlags ATTRIBUTE_UNUSED,
133 134
                               void *opaque ATTRIBUTE_UNUSED,
                               void *parseOpaque ATTRIBUTE_UNUSED)
135 136 137 138 139 140 141 142 143
{
    return 0;
}

virDomainDefParserConfig vmwareDomainDefParserConfig = {
    .devicesPostParseCallback = vmwareDomainDeviceDefPostParse,
    .domainPostParseCallback = vmwareDomainDefPostParse,
};

144
static virDomainXMLOptionPtr
145 146 147 148 149
vmwareDomainXMLConfigInit(void)
{
    virDomainXMLPrivateDataCallbacks priv = { .alloc = vmwareDataAllocFunc,
                                              .free = vmwareDataFreeFunc };

150 151
    return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv,
                                 NULL, NULL, NULL);
152 153
}

154
static virDrvOpenStatus
155 156
vmwareConnectOpen(virConnectPtr conn,
                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
157
                  virConfPtr conf ATTRIBUTE_UNUSED,
158
                  unsigned int flags)
159 160
{
    struct vmware_driver *driver;
161
    size_t i;
162
    char *tmp;
163
    char *vmrun = NULL;
164

E
Eric Blake 已提交
165 166
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

167
    /* If path isn't /session, then they typoed, so tell them correct path */
168
    if (STRNEQ(conn->uri->path, "/session")) {
169 170 171 172
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected VMware URI path '%s', try vmwareplayer:///session, vmwarews:///session or vmwarefusion:///session"),
                       NULLSTR(conn->uri->path));
        return VIR_DRV_OPEN_ERROR;
173 174 175 176 177
    }

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

178
    if (VIR_ALLOC(driver) < 0)
179
        return VIR_DRV_OPEN_ERROR;
180 181 182 183 184 185

    /* Find vmrun, which is what this driver uses to communicate to
     * the VMware hypervisor. We look this up first since we use it
     * for auto detection of the backend
     */
    for (i = 0; i < ARRAY_CARDINALITY(vmrun_candidates); i++) {
186 187 188 189 190 191 192 193
        vmrun = virFindFileInPath(vmrun_candidates[i]);
        if (vmrun == NULL)
            continue;
        if (virFileResolveLink(vmrun, &driver->vmrun) < 0) {
            virReportSystemError(errno, _("unable to resolve symlink '%s'"), vmrun);
            goto cleanup;
        }
        VIR_FREE(vmrun);
194 195 196
        /* If we found one, we can stop looking */
        if (driver->vmrun)
            break;
197 198
    }

199 200 201 202 203
    if (driver->vmrun == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmrun utility is missing"));
        goto cleanup;
    }
204 205 206 207

    if (virMutexInit(&driver->lock) < 0)
        goto cleanup;

208 209 210 211 212 213
    if ((tmp = STRSKIP(conn->uri->scheme, "vmware")) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to parse URI "
                       "scheme '%s'"), conn->uri->scheme);
        goto cleanup;
    }

214 215
    /* Match the non-'vmware' part of the scheme as the driver backend */
    driver->type = vmwareDriverTypeFromString(tmp);
216 217 218 219 220 221

    if (driver->type == -1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to find valid "
                       "requested VMware backend '%s'"), tmp);
        goto cleanup;
    }
222

223 224 225
    if (vmwareExtractVersion(driver) < 0)
        goto cleanup;

226
    if (!(driver->domains = virDomainObjListNew()))
227 228 229 230 231
        goto cleanup;

    if (!(driver->caps = vmwareCapsInit()))
        goto cleanup;

232
    if (!(driver->xmlopt = vmwareDomainXMLConfigInit()))
233
        goto cleanup;
234 235 236 237 238 239 240 241

    if (vmwareLoadDomains(driver) < 0)
        goto cleanup;

    conn->privateData = driver;

    return VIR_DRV_OPEN_SUCCESS;

242
 cleanup:
243
    vmwareFreeDriver(driver);
244
    VIR_FREE(vmrun);
245 246 247 248
    return VIR_DRV_OPEN_ERROR;
};

static int
249
vmwareConnectClose(virConnectPtr conn)
250 251 252 253 254 255 256 257 258 259 260
{
    struct vmware_driver *driver = conn->privateData;

    vmwareFreeDriver(driver);

    conn->privateData = NULL;

    return 0;
}

static const char *
261
vmwareConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
262 263 264 265 266
{
    return "VMware";
}

static int
267
vmwareConnectGetVersion(virConnectPtr conn, unsigned long *version)
268 269 270 271 272 273 274 275 276
{
    struct vmware_driver *driver = conn->privateData;

    vmwareDriverLock(driver);
    *version = driver->version;
    vmwareDriverUnlock(driver);
    return 0;
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290
static int
vmwareUpdateVMStatus(struct vmware_driver *driver, virDomainObjPtr vm)
{
    virCommandPtr cmd;
    char *outbuf = NULL;
    char *vmxAbsolutePath = NULL;
    char *parsedVmxPath = NULL;
    char *str;
    char *saveptr = NULL;
    bool found = false;
    int oldState = virDomainObjGetState(vm, NULL);
    int newState;
    int ret = -1;

291
    cmd = virCommandNewArgList(driver->vmrun, "-T",
292
                               vmwareDriverTypeToString(driver->type),
293 294 295 296 297 298 299 300 301
                               "list", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    if (virFileResolveAllLinks(((vmwareDomainPtr) vm->privateData)->vmxPath,
                               &vmxAbsolutePath) < 0)
        goto cleanup;

302
    for (str = outbuf; (parsedVmxPath = strtok_r(str, "\n", &saveptr)) != NULL;
303
         str = NULL) {
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

        if (parsedVmxPath[0] != '/')
            continue;

        if (STREQ(parsedVmxPath, vmxAbsolutePath)) {
            found = true;
            /* If the vmx path is in the output, the domain is running or
             * is paused but we have no way to detect if it is paused or not. */
            if (oldState == VIR_DOMAIN_PAUSED)
                newState = oldState;
            else
                newState = VIR_DOMAIN_RUNNING;
            break;
        }
    }

    if (!found) {
        vm->def->id = -1;
        newState = VIR_DOMAIN_SHUTOFF;
    }

    virDomainObjSetState(vm, newState, 0);

    ret = 0;

329
 cleanup:
330 331 332 333 334 335
    virCommandFree(cmd);
    VIR_FREE(outbuf);
    VIR_FREE(vmxAbsolutePath);
    return ret;
}

336
static int
J
Jiri Denemark 已提交
337 338 339
vmwareStopVM(struct vmware_driver *driver,
             virDomainObjPtr vm,
             virDomainShutoffReason reason)
340 341
{
    const char *cmd[] = {
342
        driver->vmrun, "-T", PROGRAM_SENTINEL, "stop",
E
Eric Blake 已提交
343
        PROGRAM_SENTINEL, "soft", NULL
344 345
    };

346
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
347 348
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);

349
    if (virRun(cmd, NULL) < 0)
350 351 352
        return -1;

    vm->def->id = -1;
J
Jiri Denemark 已提交
353
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
354 355 356 357 358 359 360 361

    return 0;
}

static int
vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
{
    const char *cmd[] = {
362
        driver->vmrun, "-T", PROGRAM_SENTINEL, "start",
E
Eric Blake 已提交
363
        PROGRAM_SENTINEL, PROGRAM_SENTINEL, NULL
364 365 366
    };
    const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;

J
Jiri Denemark 已提交
367
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
368 369
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not in shutoff state"));
370 371 372
        return -1;
    }

373
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
374 375 376 377 378 379
    vmwareSetSentinal(cmd, vmxPath);
    if (!((vmwareDomainPtr) vm->privateData)->gui)
        vmwareSetSentinal(cmd, NOGUI);
    else
        vmwareSetSentinal(cmd, NULL);

380
    if (virRun(cmd, NULL) < 0)
381 382 383
        return -1;

    if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) {
J
Jiri Denemark 已提交
384
        vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
385 386 387
        return -1;
    }

J
Jiri Denemark 已提交
388
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
389 390 391 392 393

    return 0;
}

static virDomainPtr
394
vmwareDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
395 396 397 398 399 400 401 402 403 404
{
    struct vmware_driver *driver = conn->privateData;
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
    char *vmx = NULL;
    char *directoryName = NULL;
    char *fileName = NULL;
    char *vmxPath = NULL;
    vmwareDomainPtr pDomain = NULL;
405
    virVMXContext ctx;
406
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
407

408 409 410
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
411
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
412

413
    ctx.parseFileName = NULL;
414
    ctx.formatFileName = vmwareCopyVMXFileName;
415 416
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
417 418

    vmwareDriverLock(driver);
419
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
420
                                         NULL, parse_flags)) == NULL)
421
        goto cleanup;
422 423 424

    if (virXMLCheckIllegalChars("name", vmdef->name, "\n") < 0)
        goto cleanup;
425 426

    /* generate vmx file */
427
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
428 429 430 431 432 433 434 435
    if (vmx == NULL)
        goto cleanup;

    if (vmwareVmxPath(vmdef, &vmxPath) < 0)
        goto cleanup;

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
436 437
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
438 439 440 441
        goto cleanup;
    }

    /* assign def */
442
    if (!(vm = virDomainObjListAdd(driver->domains,
443
                                   vmdef,
444
                                   driver->xmlopt,
445 446
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
447 448 449
        goto cleanup;

    pDomain = vm->privateData;
450
    if (VIR_STRDUP(pDomain->vmxPath, vmxPath) < 0)
451 452 453 454 455 456 457
        goto cleanup;

    vmwareDomainConfigDisplay(pDomain, vmdef);

    vmdef = NULL;
    vm->persistent = 1;

458
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, -1);
459

460
 cleanup:
461 462 463 464 465 466
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(directoryName);
    VIR_FREE(fileName);
    VIR_FREE(vmxPath);
    if (vm)
467
        virObjectUnlock(vm);
468 469 470 471
    vmwareDriverUnlock(driver);
    return dom;
}

472 473 474 475 476 477
static virDomainPtr
vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return vmwareDomainDefineXMLFlags(conn, xml, 0);
}

478
static int
479 480
vmwareDomainShutdownFlags(virDomainPtr dom,
                          unsigned int flags)
481 482 483 484 485
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

486 487
    virCheckFlags(0, -1);

488 489
    vmwareDriverLock(driver);

490
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
491 492
        goto cleanup;

493 494 495
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
496
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
497 498
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
499 500 501
        goto cleanup;
    }

J
Jiri Denemark 已提交
502
    if (vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0)
503 504
        goto cleanup;

505
    if (!vm->persistent)
506
        virDomainObjListRemove(driver->domains, vm);
507 508

    ret = 0;
509
 cleanup:
510
    virDomainObjEndAPI(&vm);
511 512 513 514
    vmwareDriverUnlock(driver);
    return ret;
}

515 516 517 518 519 520
static int
vmwareDomainShutdown(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

521 522 523 524 525 526 527 528 529 530 531 532 533
static int
vmwareDomainDestroy(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

static int
vmwareDomainDestroyFlags(virDomainPtr dom,
                         unsigned int flags)
{
    return vmwareDomainShutdownFlags(dom, flags);
}

534 535 536 537 538 539 540
static int
vmwareDomainSuspend(virDomainPtr dom)
{
    struct vmware_driver *driver = dom->conn->privateData;

    virDomainObjPtr vm;
    const char *cmd[] = {
541
      driver->vmrun, "-T", PROGRAM_SENTINEL, "pause",
E
Eric Blake 已提交
542
      PROGRAM_SENTINEL, NULL
543 544 545
    };
    int ret = -1;

546
    if (driver->type == VMWARE_DRIVER_PLAYER) {
547 548 549
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmplayer does not support libvirt suspend/resume"
                         " (vmware pause/unpause) operation "));
550 551 552
        return ret;
    }

553 554
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
555

556
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
557
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
558
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
559 560
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
561 562 563 564 565 566
        goto cleanup;
    }

    if (virRun(cmd, NULL) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
567
    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
568 569
    ret = 0;

570
 cleanup:
571
    virDomainObjEndAPI(&vm);
572 573 574 575 576 577 578 579 580 581
    return ret;
}

static int
vmwareDomainResume(virDomainPtr dom)
{
    struct vmware_driver *driver = dom->conn->privateData;

    virDomainObjPtr vm;
    const char *cmd[] = {
582
        driver->vmrun, "-T", PROGRAM_SENTINEL, "unpause", PROGRAM_SENTINEL,
583 584 585 586
        NULL
    };
    int ret = -1;

587
    if (driver->type == VMWARE_DRIVER_PLAYER) {
588
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
589
                       _("vmplayer does not support libvirt suspend/resume "
590
                         "(vmware pause/unpause) operation "));
591 592 593
        return ret;
    }

594 595
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
596

597
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
598
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
599
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
600 601
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in suspend state"));
602 603 604 605 606 607
        goto cleanup;
    }

    if (virRun(cmd, NULL) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
608
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
609 610
    ret = 0;

611
 cleanup:
612
    virDomainObjEndAPI(&vm);
613 614 615 616
    return ret;
}

static int
E
Eric Blake 已提交
617
vmwareDomainReboot(virDomainPtr dom, unsigned int flags)
618 619 620 621 622
{
    struct vmware_driver *driver = dom->conn->privateData;
    const char * vmxPath = NULL;
    virDomainObjPtr vm;
    const char *cmd[] = {
623
        driver->vmrun, "-T", PROGRAM_SENTINEL,
E
Eric Blake 已提交
624
        "reset", PROGRAM_SENTINEL, "soft", NULL
625 626 627
    };
    int ret = -1;

E
Eric Blake 已提交
628 629
    virCheckFlags(0, -1);

630 631
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
632

633
    vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
634
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
C
Christophe Fergeau 已提交
635
    vmwareSetSentinal(cmd, vmxPath);
636

637 638
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;
639

J
Jiri Denemark 已提交
640
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
641 642
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
643 644 645 646 647 648 649 650
        goto cleanup;
    }

    if (virRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;

651
 cleanup:
652
    virDomainObjEndAPI(&vm);
653 654 655 656 657
    return ret;
}

static virDomainPtr
vmwareDomainCreateXML(virConnectPtr conn, const char *xml,
E
Eric Blake 已提交
658
                      unsigned int flags)
659 660 661 662 663 664 665 666
{
    struct vmware_driver *driver = conn->privateData;
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
    char *vmx = NULL;
    char *vmxPath = NULL;
    vmwareDomainPtr pDomain = NULL;
667
    virVMXContext ctx;
668 669 670
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
671

672
    if (flags & VIR_DOMAIN_START_VALIDATE)
673
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
E
Eric Blake 已提交
674

675
    ctx.parseFileName = NULL;
676
    ctx.formatFileName = vmwareCopyVMXFileName;
677 678
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
679 680 681

    vmwareDriverLock(driver);

682
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
683
                                         NULL, parse_flags)) == NULL)
684 685 686
        goto cleanup;

    /* generate vmx file */
687
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
688 689 690 691 692 693 694 695
    if (vmx == NULL)
        goto cleanup;

    if (vmwareVmxPath(vmdef, &vmxPath) < 0)
        goto cleanup;

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
696 697
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
698 699 700 701
        goto cleanup;
    }

    /* assign def */
702
    if (!(vm = virDomainObjListAdd(driver->domains,
703
                                   vmdef,
704
                                   driver->xmlopt,
705
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
706 707
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
708 709 710
        goto cleanup;

    pDomain = vm->privateData;
711 712
    if (VIR_STRDUP(pDomain->vmxPath, vmxPath) < 0)
        goto cleanup;
713 714 715 716 717

    vmwareDomainConfigDisplay(pDomain, vmdef);
    vmdef = NULL;

    if (vmwareStartVM(driver, vm) < 0) {
718
        if (!vm->persistent)
719
            virDomainObjListRemove(driver->domains, vm);
720 721 722
        goto cleanup;
    }

723
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
724

725
 cleanup:
726 727 728
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(vmxPath);
729
    virDomainObjEndAPI(&vm);
730 731 732 733 734 735
    vmwareDriverUnlock(driver);
    return dom;
}

static int
vmwareDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
736
                            unsigned int flags)
737 738 739 740 741
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

E
Eric Blake 已提交
742 743
    virCheckFlags(0, -1);

744
    vmwareDriverLock(driver);
745
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
746 747
        goto cleanup;

748 749 750
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

751
    if (virDomainObjIsActive(vm)) {
752 753
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
754 755 756 757 758
        goto cleanup;
    }

    ret = vmwareStartVM(driver, vm);

759
 cleanup:
760
    virDomainObjEndAPI(&vm);
761 762 763 764 765 766 767 768 769 770 771
    vmwareDriverUnlock(driver);
    return ret;
}

static int
vmwareDomainCreate(virDomainPtr dom)
{
    return vmwareDomainCreateWithFlags(dom, 0);
}

static int
772 773
vmwareDomainUndefineFlags(virDomainPtr dom,
                          unsigned int flags)
774 775 776 777 778
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

779 780
    virCheckFlags(0, -1);

781
    vmwareDriverLock(driver);
782
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
783 784 785
        goto cleanup;

    if (!vm->persistent) {
786 787
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
788 789 790
        goto cleanup;
    }

791 792 793
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

794
    if (virDomainObjIsActive(vm))
795
        vm->persistent = 0;
796
    else
797
        virDomainObjListRemove(driver->domains, vm);
798

799 800
    ret = 0;

801
 cleanup:
802
    virDomainObjEndAPI(&vm);
803 804 805 806
    vmwareDriverUnlock(driver);
    return ret;
}

807 808 809 810 811 812
static int
vmwareDomainUndefine(virDomainPtr dom)
{
    return vmwareDomainUndefineFlags(dom, 0);
}

813 814 815 816 817 818 819 820
static virDomainPtr
vmwareDomainLookupByID(virConnectPtr conn, int id)
{
    struct vmware_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

    vmwareDriverLock(driver);
821
    vm = virDomainObjListFindByID(driver->domains, id);
822 823 824
    vmwareDriverUnlock(driver);

    if (!vm) {
825 826
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id '%d'"), id);
827 828 829
        goto cleanup;
    }

830
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
831

832
 cleanup:
833
    virDomainObjEndAPI(&vm);
834 835 836 837
    return dom;
}

static char *
838
vmwareDomainGetOSType(virDomainPtr dom)
839 840 841 842 843
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

844 845
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return NULL;
846

847
    ignore_value(VIR_STRDUP(ret, virDomainOSTypeToString(vm->def->os.type)));
848

849
    virDomainObjEndAPI(&vm);
850 851 852 853 854 855 856 857 858 859 860
    return ret;
}


static virDomainPtr
vmwareDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    struct vmware_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

861 862
    if (!(vm = vmwareDomObjFromDomain(driver, uuid)))
        return NULL;
863

864
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
865

866
    virDomainObjEndAPI(&vm);
867 868 869 870 871 872 873 874 875 876 877
    return dom;
}

static virDomainPtr
vmwareDomainLookupByName(virConnectPtr conn, const char *name)
{
    struct vmware_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

    vmwareDriverLock(driver);
878
    vm = virDomainObjListFindByName(driver->domains, name);
879 880 881
    vmwareDriverUnlock(driver);

    if (!vm) {
882 883
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
884 885 886
        goto cleanup;
    }

887
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
888

889
 cleanup:
890
    virDomainObjEndAPI(&vm);
891 892 893 894 895 896 897 898 899 900
    return dom;
}

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

901 902 903
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

904 905
    ret = virDomainObjIsActive(obj);

906
    virDomainObjEndAPI(&obj);
907 908 909 910 911 912 913 914 915 916 917
    return ret;
}


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

918 919 920
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

921 922
    ret = obj->persistent;

923
    virDomainObjEndAPI(&obj);
924 925 926 927 928
    return ret;
}


static char *
929
vmwareDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
930 931 932 933 934
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

935
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
936

937 938
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return NULL;
939

940
    ret = virDomainDefFormat(vm->def, driver->caps,
941
                             virDomainDefFormatConvertXMLFlags(flags));
942

943
    virDomainObjEndAPI(&vm);
944 945 946
    return ret;
}

947
static char *
948 949 950
vmwareConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                                 const char *nativeConfig,
                                 unsigned int flags)
951 952 953 954 955 956 957 958 959
{
    struct vmware_driver *driver = conn->privateData;
    virVMXContext ctx;
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    virCheckFlags(0, NULL);

    if (STRNEQ(nativeFormat, "vmware-vmx")) {
960 961
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
962 963 964 965
        return NULL;
    }

    ctx.parseFileName = vmwareCopyVMXFileName;
966 967 968
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
969

970
    def = virVMXParseConfig(&ctx, driver->xmlopt, driver->caps, nativeConfig);
971 972

    if (def != NULL)
973 974
        xml = virDomainDefFormat(def, driver->caps,
                                 VIR_DOMAIN_DEF_FORMAT_INACTIVE);
975 976 977 978 979 980

    virDomainDefFree(def);

    return xml;
}

981
static int vmwareDomainObjListUpdateDomain(virDomainObjPtr dom, void *data)
982 983
{
    struct vmware_driver *driver = data;
984 985 986 987
    virObjectLock(dom);
    ignore_value(vmwareUpdateVMStatus(driver, dom));
    virObjectUnlock(dom);
    return 0;
988 989 990 991 992
}

static void
vmwareDomainObjListUpdateAll(virDomainObjListPtr doms, struct vmware_driver *driver)
{
993
    virDomainObjListForEach(doms, vmwareDomainObjListUpdateDomain, driver);
994 995
}

996
static int
997
vmwareConnectNumOfDefinedDomains(virConnectPtr conn)
998 999 1000 1001 1002
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1003
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1004
    n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
1005 1006 1007 1008 1009 1010
    vmwareDriverUnlock(driver);

    return n;
}

static int
1011
vmwareConnectNumOfDomains(virConnectPtr conn)
1012 1013 1014 1015 1016
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1017
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1018
    n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
1019 1020 1021 1022 1023 1024 1025
    vmwareDriverUnlock(driver);

    return n;
}


static int
1026
vmwareConnectListDomains(virConnectPtr conn, int *ids, int nids)
1027 1028 1029 1030 1031
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1032
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1033
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids, NULL, NULL);
1034 1035 1036 1037 1038 1039
    vmwareDriverUnlock(driver);

    return n;
}

static int
1040 1041
vmwareConnectListDefinedDomains(virConnectPtr conn,
                                char **const names, int nnames)
1042 1043 1044 1045 1046
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1047
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1048 1049
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         NULL, NULL);
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    vmwareDriverUnlock(driver);
    return n;
}

static int
vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1061 1062
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
1063

1064 1065 1066
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1067
    info->state = virDomainObjGetState(vm, NULL);
1068
    info->cpuTime = 0;
1069
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1070
    info->memory = vm->def->mem.cur_balloon;
1071
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
1072 1073
    ret = 0;

1074
 cleanup:
1075
    virDomainObjEndAPI(&vm);
1076 1077 1078
    return ret;
}

1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
static int
vmwareDomainGetState(virDomainPtr dom,
                     int *state,
                     int *reason,
                     unsigned int flags)
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

1091 1092
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
1093

1094 1095 1096
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1097
    *state = virDomainObjGetState(vm, reason);
1098 1099
    ret = 0;

1100
 cleanup:
1101
    virDomainObjEndAPI(&vm);
1102 1103 1104
    return ret;
}

1105
static int
1106
vmwareConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1107 1108 1109 1110
{
    return 1;
}

1111
static int
1112 1113 1114
vmwareConnectListAllDomains(virConnectPtr conn,
                            virDomainPtr **domains,
                            unsigned int flags)
1115 1116 1117 1118
{
    struct vmware_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
1119
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
1120 1121

    vmwareDriverLock(driver);
1122
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1123 1124
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 NULL, flags);
1125 1126 1127 1128
    vmwareDriverUnlock(driver);
    return ret;
}

1129 1130 1131 1132 1133 1134 1135 1136 1137
static int
vmwareDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    virCheckFlags(0, -1);

1138 1139 1140
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

1141 1142
    ret = 0;

1143
    virDomainObjEndAPI(&obj);
1144 1145 1146
    return ret;
}

1147 1148


1149
static virHypervisorDriver vmwareHypervisorDriver = {
1150
    .name = "VMWARE",
1151 1152 1153 1154 1155 1156 1157
    .connectOpen = vmwareConnectOpen, /* 0.8.7 */
    .connectClose = vmwareConnectClose, /* 0.8.7 */
    .connectGetType = vmwareConnectGetType, /* 0.8.7 */
    .connectGetVersion = vmwareConnectGetVersion, /* 0.8.7 */
    .connectListDomains = vmwareConnectListDomains, /* 0.8.7 */
    .connectNumOfDomains = vmwareConnectNumOfDomains, /* 0.8.7 */
    .connectListAllDomains = vmwareConnectListAllDomains, /* 0.9.13 */
1158 1159 1160 1161 1162 1163 1164
    .domainCreateXML = vmwareDomainCreateXML, /* 0.8.7 */
    .domainLookupByID = vmwareDomainLookupByID, /* 0.8.7 */
    .domainLookupByUUID = vmwareDomainLookupByUUID, /* 0.8.7 */
    .domainLookupByName = vmwareDomainLookupByName, /* 0.8.7 */
    .domainSuspend = vmwareDomainSuspend, /* 0.8.7 */
    .domainResume = vmwareDomainResume, /* 0.8.7 */
    .domainShutdown = vmwareDomainShutdown, /* 0.8.7 */
1165
    .domainShutdownFlags = vmwareDomainShutdownFlags, /* 0.9.10 */
1166
    .domainReboot = vmwareDomainReboot, /* 0.8.7 */
1167 1168 1169
    .domainDestroy = vmwareDomainDestroy, /* 0.8.7 */
    .domainDestroyFlags = vmwareDomainDestroyFlags, /* 0.9.4 */
    .domainGetOSType = vmwareDomainGetOSType, /* 0.8.7 */
1170 1171 1172
    .domainGetInfo = vmwareDomainGetInfo, /* 0.8.7 */
    .domainGetState = vmwareDomainGetState, /* 0.9.2 */
    .domainGetXMLDesc = vmwareDomainGetXMLDesc, /* 0.8.7 */
1173 1174 1175
    .connectDomainXMLFromNative = vmwareConnectDomainXMLFromNative, /* 0.9.11 */
    .connectListDefinedDomains = vmwareConnectListDefinedDomains, /* 0.8.7 */
    .connectNumOfDefinedDomains = vmwareConnectNumOfDefinedDomains, /* 0.8.7 */
1176 1177 1178
    .domainCreate = vmwareDomainCreate, /* 0.8.7 */
    .domainCreateWithFlags = vmwareDomainCreateWithFlags, /* 0.8.7 */
    .domainDefineXML = vmwareDomainDefineXML, /* 0.8.7 */
1179
    .domainDefineXMLFlags = vmwareDomainDefineXMLFlags, /* 1.2.12 */
1180
    .domainUndefine = vmwareDomainUndefine, /* 0.8.7 */
1181
    .domainUndefineFlags = vmwareDomainUndefineFlags, /* 0.9.4 */
1182 1183
    .domainIsActive = vmwareDomainIsActive, /* 0.8.7 */
    .domainIsPersistent = vmwareDomainIsPersistent, /* 0.8.7 */
1184
    .connectIsAlive = vmwareConnectIsAlive, /* 0.9.8 */
1185
    .domainHasManagedSaveImage = vmwareDomainHasManagedSaveImage, /* 1.2.13 */
1186 1187
};

1188
static virConnectDriver vmwareConnectDriver = {
1189
    .localOnly = true,
1190
    .uriSchemes = (const char *[]){ "vmwareplayer", "vmwarews", "vmwarefusion", NULL },
1191 1192 1193
    .hypervisorDriver = &vmwareHypervisorDriver,
};

1194 1195 1196
int
vmwareRegister(void)
{
1197 1198
    return virRegisterConnectDriver(&vmwareConnectDriver,
                                    false);
1199
}