vmware_driver.c 33.3 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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
static void
vmwareDriverLock(struct vmware_driver *driver)
{
    virMutexLock(&driver->lock);
}

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

static void *
vmwareDataAllocFunc(void)
{
    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);
}

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
static int
vmwareDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
                         virCapsPtr caps ATTRIBUTE_UNUSED,
                         void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}

static int
vmwareDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                               const virDomainDef *def ATTRIBUTE_UNUSED,
                               virCapsPtr caps ATTRIBUTE_UNUSED,
                               void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}

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

107
static virDomainXMLOptionPtr
108 109 110 111 112
vmwareDomainXMLConfigInit(void)
{
    virDomainXMLPrivateDataCallbacks priv = { .alloc = vmwareDataAllocFunc,
                                              .free = vmwareDataFreeFunc };

113
    return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv, NULL);
114 115
}

116
static virDrvOpenStatus
117 118 119
vmwareConnectOpen(virConnectPtr conn,
                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                  unsigned int flags)
120 121
{
    struct vmware_driver *driver;
122
    size_t i;
123
    char *tmp;
124

E
Eric Blake 已提交
125 126
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

127 128 129 130 131 132
    if (conn->uri == NULL) {
        /* @TODO accept */
        return VIR_DRV_OPEN_DECLINED;
    } else {
        if (conn->uri->scheme == NULL ||
            (STRNEQ(conn->uri->scheme, "vmwareplayer") &&
133 134
             STRNEQ(conn->uri->scheme, "vmwarews") &&
             STRNEQ(conn->uri->scheme, "vmwarefusion")))
135 136 137 138 139 140 141 142
            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 /session, then they typoed, so tell them correct path */
        if (conn->uri->path == NULL || STRNEQ(conn->uri->path, "/session")) {
143
            virReportError(VIR_ERR_INTERNAL_ERROR,
144
                           _("unexpected VMware URI path '%s', try vmwareplayer:///session, vmwarews:///session or vmwarefusion:///session"),
145
                           NULLSTR(conn->uri->path));
146 147 148 149 150 151 152
            return VIR_DRV_OPEN_ERROR;
        }
    }

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

153
    if (VIR_ALLOC(driver) < 0)
154
        return VIR_DRV_OPEN_ERROR;
155 156 157 158 159 160 161 162 163 164

    /* 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++) {
        driver->vmrun = virFindFileInPath(vmrun_candidates[i]);
        /* If we found one, we can stop looking */
        if (driver->vmrun)
            break;
165 166
    }

167 168 169 170 171
    if (driver->vmrun == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmrun utility is missing"));
        goto cleanup;
    }
172 173 174 175

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

176 177 178 179 180 181
    if ((tmp = STRSKIP(conn->uri->scheme, "vmware")) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to parse URI "
                       "scheme '%s'"), conn->uri->scheme);
        goto cleanup;
    }

182 183
    /* Match the non-'vmware' part of the scheme as the driver backend */
    driver->type = vmwareDriverTypeFromString(tmp);
184 185 186 187 188 189

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

191 192 193
    if (vmwareExtractVersion(driver) < 0)
        goto cleanup;

194
    if (!(driver->domains = virDomainObjListNew()))
195 196 197 198 199
        goto cleanup;

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

200
    if (!(driver->xmlopt = vmwareDomainXMLConfigInit()))
201
        goto cleanup;
202 203 204 205 206 207 208 209

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

    conn->privateData = driver;

    return VIR_DRV_OPEN_SUCCESS;

210
 cleanup:
211 212 213 214 215
    vmwareFreeDriver(driver);
    return VIR_DRV_OPEN_ERROR;
};

static int
216
vmwareConnectClose(virConnectPtr conn)
217 218 219 220 221 222 223 224 225 226 227
{
    struct vmware_driver *driver = conn->privateData;

    vmwareFreeDriver(driver);

    conn->privateData = NULL;

    return 0;
}

static const char *
228
vmwareConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
229 230 231 232 233
{
    return "VMware";
}

static int
234
vmwareConnectGetVersion(virConnectPtr conn, unsigned long *version)
235 236 237 238 239 240 241 242 243
{
    struct vmware_driver *driver = conn->privateData;

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

244 245 246 247 248 249 250 251 252 253 254 255 256 257
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;

258
    cmd = virCommandNewArgList(driver->vmrun, "-T",
259
                               vmwareDriverTypeToString(driver->type),
260 261 262 263 264 265 266 267 268
                               "list", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

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

269
    for (str = outbuf; (parsedVmxPath = strtok_r(str, "\n", &saveptr)) != NULL;
270
         str = NULL) {
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

        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;

296
 cleanup:
297 298 299 300 301 302
    virCommandFree(cmd);
    VIR_FREE(outbuf);
    VIR_FREE(vmxAbsolutePath);
    return ret;
}

303
static int
J
Jiri Denemark 已提交
304 305 306
vmwareStopVM(struct vmware_driver *driver,
             virDomainObjPtr vm,
             virDomainShutoffReason reason)
307 308
{
    const char *cmd[] = {
309
        driver->vmrun, "-T", PROGRAM_SENTINEL, "stop",
E
Eric Blake 已提交
310
        PROGRAM_SENTINEL, "soft", NULL
311 312
    };

313
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
314 315
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);

316
    if (virRun(cmd, NULL) < 0)
317 318 319
        return -1;

    vm->def->id = -1;
J
Jiri Denemark 已提交
320
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
321 322 323 324 325 326 327 328

    return 0;
}

static int
vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
{
    const char *cmd[] = {
329
        driver->vmrun, "-T", PROGRAM_SENTINEL, "start",
E
Eric Blake 已提交
330
        PROGRAM_SENTINEL, PROGRAM_SENTINEL, NULL
331 332 333
    };
    const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;

J
Jiri Denemark 已提交
334
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
335 336
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not in shutoff state"));
337 338 339
        return -1;
    }

340
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
341 342 343 344 345 346
    vmwareSetSentinal(cmd, vmxPath);
    if (!((vmwareDomainPtr) vm->privateData)->gui)
        vmwareSetSentinal(cmd, NOGUI);
    else
        vmwareSetSentinal(cmd, NULL);

347
    if (virRun(cmd, NULL) < 0)
348 349 350
        return -1;

    if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) {
J
Jiri Denemark 已提交
351
        vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
352 353 354
        return -1;
    }

J
Jiri Denemark 已提交
355
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
356 357 358 359 360

    return 0;
}

static virDomainPtr
361
vmwareDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
362 363 364 365 366 367 368 369 370 371
{
    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;
372
    virVMXContext ctx;
373
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
374

375 376 377 378
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
379

380
    ctx.formatFileName = vmwareCopyVMXFileName;
381 382

    vmwareDriverLock(driver);
383 384
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                         1 << VIR_DOMAIN_VIRT_VMWARE,
385
                                         parse_flags)) == NULL)
386 387 388
        goto cleanup;

    /* generate vmx file */
389
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
390 391 392 393 394 395 396 397
    if (vmx == NULL)
        goto cleanup;

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

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
398 399
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
400 401 402 403
        goto cleanup;
    }

    /* assign def */
404
    if (!(vm = virDomainObjListAdd(driver->domains,
405
                                   vmdef,
406
                                   driver->xmlopt,
407 408
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
409 410 411
        goto cleanup;

    pDomain = vm->privateData;
412
    if (VIR_STRDUP(pDomain->vmxPath, vmxPath) < 0)
413 414 415 416 417 418 419 420 421 422 423
        goto cleanup;

    vmwareDomainConfigDisplay(pDomain, vmdef);

    vmdef = NULL;
    vm->persistent = 1;

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = -1;

424
 cleanup:
425 426 427 428 429 430
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(directoryName);
    VIR_FREE(fileName);
    VIR_FREE(vmxPath);
    if (vm)
431
        virObjectUnlock(vm);
432 433 434 435
    vmwareDriverUnlock(driver);
    return dom;
}

436 437 438 439 440 441
static virDomainPtr
vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return vmwareDomainDefineXMLFlags(conn, xml, 0);
}

442
static int
443 444
vmwareDomainShutdownFlags(virDomainPtr dom,
                          unsigned int flags)
445 446 447 448 449
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

450 451
    virCheckFlags(0, -1);

452 453
    vmwareDriverLock(driver);

454
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
455 456

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

462 463 464
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
465
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
466 467
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
468 469 470
        goto cleanup;
    }

J
Jiri Denemark 已提交
471
    if (vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0)
472 473 474
        goto cleanup;

    if (!vm->persistent) {
475
        virDomainObjListRemove(driver->domains, vm);
476 477 478 479
        vm = NULL;
    }

    ret = 0;
480
 cleanup:
481
    if (vm)
482
        virObjectUnlock(vm);
483 484 485 486
    vmwareDriverUnlock(driver);
    return ret;
}

487 488 489 490 491 492
static int
vmwareDomainShutdown(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

493 494 495 496 497 498 499 500 501 502 503 504 505
static int
vmwareDomainDestroy(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

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

506 507 508 509 510 511 512
static int
vmwareDomainSuspend(virDomainPtr dom)
{
    struct vmware_driver *driver = dom->conn->privateData;

    virDomainObjPtr vm;
    const char *cmd[] = {
513
      driver->vmrun, "-T", PROGRAM_SENTINEL, "pause",
E
Eric Blake 已提交
514
      PROGRAM_SENTINEL, NULL
515 516 517
    };
    int ret = -1;

518
    if (driver->type == VMWARE_DRIVER_PLAYER) {
519 520 521
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmplayer does not support libvirt suspend/resume"
                         " (vmware pause/unpause) operation "));
522 523 524 525
        return ret;
    }

    vmwareDriverLock(driver);
526
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
527 528 529
    vmwareDriverUnlock(driver);

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

535
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
536
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
537
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
538 539
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
540 541 542 543 544 545
        goto cleanup;
    }

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

J
Jiri Denemark 已提交
546
    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
547 548
    ret = 0;

549
 cleanup:
550
    if (vm)
551
        virObjectUnlock(vm);
552 553 554 555 556 557 558 559 560 561
    return ret;
}

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

    virDomainObjPtr vm;
    const char *cmd[] = {
562
        driver->vmrun, "-T", PROGRAM_SENTINEL, "unpause", PROGRAM_SENTINEL,
563 564 565 566
        NULL
    };
    int ret = -1;

567
    if (driver->type == VMWARE_DRIVER_PLAYER) {
568
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
569
                       _("vmplayer does not support libvirt suspend/resume "
570
                         "(vmware pause/unpause) operation "));
571 572 573 574
        return ret;
    }

    vmwareDriverLock(driver);
575
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
576 577 578
    vmwareDriverUnlock(driver);

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

584
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
585
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
586
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
587 588
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in suspend state"));
589 590 591 592 593 594
        goto cleanup;
    }

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

J
Jiri Denemark 已提交
595
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
596 597
    ret = 0;

598
 cleanup:
599
    if (vm)
600
        virObjectUnlock(vm);
601 602 603 604
    return ret;
}

static int
E
Eric Blake 已提交
605
vmwareDomainReboot(virDomainPtr dom, unsigned int flags)
606 607 608 609 610
{
    struct vmware_driver *driver = dom->conn->privateData;
    const char * vmxPath = NULL;
    virDomainObjPtr vm;
    const char *cmd[] = {
611
        driver->vmrun, "-T", PROGRAM_SENTINEL,
E
Eric Blake 已提交
612
        "reset", PROGRAM_SENTINEL, "soft", NULL
613 614 615
    };
    int ret = -1;

E
Eric Blake 已提交
616 617
    virCheckFlags(0, -1);

618
    vmwareDriverLock(driver);
619
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
620 621 622
    vmwareDriverUnlock(driver);

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

628
    vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
629
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
C
Christophe Fergeau 已提交
630
    vmwareSetSentinal(cmd, vmxPath);
631

632 633
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;
634

J
Jiri Denemark 已提交
635
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
636 637
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
638 639 640 641 642 643 644 645
        goto cleanup;
    }

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

    ret = 0;

646
 cleanup:
647
    if (vm)
648
        virObjectUnlock(vm);
649 650 651 652 653
    return ret;
}

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

    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
667

668 669
    if (flags & VIR_DOMAIN_START_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
E
Eric Blake 已提交
670

671
    ctx.formatFileName = vmwareCopyVMXFileName;
672 673 674

    vmwareDriverLock(driver);

675 676
    if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                         1 << VIR_DOMAIN_VIRT_VMWARE,
677
                                         parse_flags)) == NULL)
678 679 680
        goto cleanup;

    /* generate vmx file */
681
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
682 683 684 685 686 687 688 689
    if (vmx == NULL)
        goto cleanup;

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

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
690 691
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
692 693 694 695
        goto cleanup;
    }

    /* assign def */
696
    if (!(vm = virDomainObjListAdd(driver->domains,
697
                                   vmdef,
698
                                   driver->xmlopt,
699 700
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
701 702 703
        goto cleanup;

    pDomain = vm->privateData;
704 705
    if (VIR_STRDUP(pDomain->vmxPath, vmxPath) < 0)
        goto cleanup;
706 707 708 709 710

    vmwareDomainConfigDisplay(pDomain, vmdef);
    vmdef = NULL;

    if (vmwareStartVM(driver, vm) < 0) {
711
        virDomainObjListRemove(driver->domains, vm);
712 713 714 715 716 717 718 719
        vm = NULL;
        goto cleanup;
    }

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

720
 cleanup:
721 722 723
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(vmxPath);
724
    if (vm)
725
        virObjectUnlock(vm);
726 727 728 729 730 731
    vmwareDriverUnlock(driver);
    return dom;
}

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

E
Eric Blake 已提交
738 739
    virCheckFlags(0, -1);

740
    vmwareDriverLock(driver);
741
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
742 743 744
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
745 746
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
747 748 749
        goto cleanup;
    }

750 751 752
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

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

    ret = vmwareStartVM(driver, vm);

761
 cleanup:
762
    if (vm)
763
        virObjectUnlock(vm);
764 765 766 767 768 769 770 771 772 773 774
    vmwareDriverUnlock(driver);
    return ret;
}

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

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

782 783
    virCheckFlags(0, -1);

784
    vmwareDriverLock(driver);
785
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
786 787 788 789 790

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
791 792
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
793 794 795 796
        goto cleanup;
    }

    if (!vm->persistent) {
797 798
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
799 800 801
        goto cleanup;
    }

802 803 804
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

805 806 807
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
808
        virDomainObjListRemove(driver->domains, vm);
809 810 811
        vm = NULL;
    }

812 813
    ret = 0;

814
 cleanup:
815
    if (vm)
816
        virObjectUnlock(vm);
817 818 819 820
    vmwareDriverUnlock(driver);
    return ret;
}

821 822 823 824 825 826
static int
vmwareDomainUndefine(virDomainPtr dom)
{
    return vmwareDomainUndefineFlags(dom, 0);
}

827 828 829 830 831 832 833 834
static virDomainPtr
vmwareDomainLookupByID(virConnectPtr conn, int id)
{
    struct vmware_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

    vmwareDriverLock(driver);
835
    vm = virDomainObjListFindByID(driver->domains, id);
836 837 838
    vmwareDriverUnlock(driver);

    if (!vm) {
839
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
840 841 842 843 844 845 846
        goto cleanup;
    }

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

847
 cleanup:
848
    if (vm)
849
        virObjectUnlock(vm);
850 851 852 853
    return dom;
}

static char *
854
vmwareDomainGetOSType(virDomainPtr dom)
855 856 857 858 859 860
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

    vmwareDriverLock(driver);
861
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
862 863 864
    vmwareDriverUnlock(driver);

    if (!vm) {
865
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
866 867 868
        goto cleanup;
    }

869
    ignore_value(VIR_STRDUP(ret, vm->def->os.type));
870

871
 cleanup:
872
    if (vm)
873
        virObjectUnlock(vm);
874 875 876 877 878 879 880 881 882 883 884 885
    return ret;
}


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

    vmwareDriverLock(driver);
886
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
887 888 889
    vmwareDriverUnlock(driver);

    if (!vm) {
890
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
891 892 893 894 895 896 897
        goto cleanup;
    }

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

898
 cleanup:
899
    if (vm)
900
        virObjectUnlock(vm);
901 902 903 904 905 906 907 908 909 910 911
    return dom;
}

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

    vmwareDriverLock(driver);
912
    vm = virDomainObjListFindByName(driver->domains, name);
913 914 915
    vmwareDriverUnlock(driver);

    if (!vm) {
916
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
917 918 919 920 921 922 923
        goto cleanup;
    }

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

924
 cleanup:
925
    if (vm)
926
        virObjectUnlock(vm);
927 928 929 930 931 932 933 934 935 936 937
    return dom;
}

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

    vmwareDriverLock(driver);
938
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
939 940
    vmwareDriverUnlock(driver);
    if (!obj) {
941
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
942 943 944 945
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

946
 cleanup:
947
    if (obj)
948
        virObjectUnlock(obj);
949 950 951 952 953 954 955 956 957 958 959 960
    return ret;
}


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

    vmwareDriverLock(driver);
961
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
962 963
    vmwareDriverUnlock(driver);
    if (!obj) {
964
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
965 966 967 968
        goto cleanup;
    }
    ret = obj->persistent;

969
 cleanup:
970
    if (obj)
971
        virObjectUnlock(obj);
972 973 974 975 976
    return ret;
}


static char *
977
vmwareDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
978 979 980 981 982
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

983 984
    /* Flags checked by virDomainDefFormat */

985
    vmwareDriverLock(driver);
986
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
987 988 989
    vmwareDriverUnlock(driver);

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

995 996
    ret = virDomainDefFormat(vm->def,
                             virDomainDefFormatConvertXMLFlags(flags));
997

998
 cleanup:
999
    if (vm)
1000
        virObjectUnlock(vm);
1001 1002 1003
    return ret;
}

1004
static char *
1005 1006 1007
vmwareConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                                 const char *nativeConfig,
                                 unsigned int flags)
1008 1009 1010 1011 1012 1013 1014 1015 1016
{
    struct vmware_driver *driver = conn->privateData;
    virVMXContext ctx;
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    virCheckFlags(0, NULL);

    if (STRNEQ(nativeFormat, "vmware-vmx")) {
1017 1018
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
1019 1020 1021 1022 1023
        return NULL;
    }

    ctx.parseFileName = vmwareCopyVMXFileName;

1024
    def = virVMXParseConfig(&ctx, driver->xmlopt, nativeConfig);
1025 1026

    if (def != NULL)
1027
        xml = virDomainDefFormat(def, VIR_DOMAIN_DEF_FORMAT_INACTIVE);
1028 1029 1030 1031 1032 1033

    virDomainDefFree(def);

    return xml;
}

1034
static int vmwareDomainObjListUpdateDomain(virDomainObjPtr dom, void *data)
1035 1036
{
    struct vmware_driver *driver = data;
1037 1038 1039 1040
    virObjectLock(dom);
    ignore_value(vmwareUpdateVMStatus(driver, dom));
    virObjectUnlock(dom);
    return 0;
1041 1042 1043 1044 1045
}

static void
vmwareDomainObjListUpdateAll(virDomainObjListPtr doms, struct vmware_driver *driver)
{
1046
    virDomainObjListForEach(doms, vmwareDomainObjListUpdateDomain, driver);
1047 1048
}

1049
static int
1050
vmwareConnectNumOfDefinedDomains(virConnectPtr conn)
1051 1052 1053 1054 1055
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1056
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1057
    n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
1058 1059 1060 1061 1062 1063
    vmwareDriverUnlock(driver);

    return n;
}

static int
1064
vmwareConnectNumOfDomains(virConnectPtr conn)
1065 1066 1067 1068 1069
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1070
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1071
    n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
1072 1073 1074 1075 1076 1077 1078
    vmwareDriverUnlock(driver);

    return n;
}


static int
1079
vmwareConnectListDomains(virConnectPtr conn, int *ids, int nids)
1080 1081 1082 1083 1084
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1085
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1086
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids, NULL, NULL);
1087 1088 1089 1090 1091 1092
    vmwareDriverUnlock(driver);

    return n;
}

static int
1093 1094
vmwareConnectListDefinedDomains(virConnectPtr conn,
                                char **const names, int nnames)
1095 1096 1097 1098 1099
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1100
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1101 1102
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         NULL, NULL);
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
    vmwareDriverUnlock(driver);
    return n;
}

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

    vmwareDriverLock(driver);
1115
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1116 1117 1118
    vmwareDriverUnlock(driver);

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

1124 1125 1126
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1127
    info->state = virDomainObjGetState(vm, NULL);
1128
    info->cpuTime = 0;
1129
    info->maxMem = virDomainDefGetMemoryActual(vm->def);
1130 1131 1132 1133
    info->memory = vm->def->mem.cur_balloon;
    info->nrVirtCpu = vm->def->vcpus;
    ret = 0;

1134
 cleanup:
1135
    if (vm)
1136
        virObjectUnlock(vm);
1137 1138 1139
    return ret;
}

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
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);

    vmwareDriverLock(driver);
1153
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1154 1155 1156
    vmwareDriverUnlock(driver);

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

1162 1163 1164
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1165
    *state = virDomainObjGetState(vm, reason);
1166 1167
    ret = 0;

1168
 cleanup:
1169
    if (vm)
1170
        virObjectUnlock(vm);
1171 1172 1173
    return ret;
}

1174
static int
1175
vmwareConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1176 1177 1178 1179
{
    return 1;
}

1180
static int
1181 1182 1183
vmwareConnectListAllDomains(virConnectPtr conn,
                            virDomainPtr **domains,
                            unsigned int flags)
1184 1185 1186 1187
{
    struct vmware_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
1188
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
1189 1190

    vmwareDriverLock(driver);
1191
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1192 1193
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 NULL, flags);
1194 1195 1196 1197
    vmwareDriverUnlock(driver);
    return ret;
}

1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
static int
vmwareDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    virCheckFlags(0, -1);

    vmwareDriverLock(driver);
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
    vmwareDriverUnlock(driver);
    if (!obj) {
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = 0;

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

1222 1223


1224
static virHypervisorDriver vmwareHypervisorDriver = {
1225
    .name = "VMWARE",
1226 1227 1228 1229 1230 1231 1232
    .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 */
1233 1234 1235 1236 1237 1238 1239
    .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 */
1240
    .domainShutdownFlags = vmwareDomainShutdownFlags, /* 0.9.10 */
1241
    .domainReboot = vmwareDomainReboot, /* 0.8.7 */
1242 1243 1244
    .domainDestroy = vmwareDomainDestroy, /* 0.8.7 */
    .domainDestroyFlags = vmwareDomainDestroyFlags, /* 0.9.4 */
    .domainGetOSType = vmwareDomainGetOSType, /* 0.8.7 */
1245 1246 1247
    .domainGetInfo = vmwareDomainGetInfo, /* 0.8.7 */
    .domainGetState = vmwareDomainGetState, /* 0.9.2 */
    .domainGetXMLDesc = vmwareDomainGetXMLDesc, /* 0.8.7 */
1248 1249 1250
    .connectDomainXMLFromNative = vmwareConnectDomainXMLFromNative, /* 0.9.11 */
    .connectListDefinedDomains = vmwareConnectListDefinedDomains, /* 0.8.7 */
    .connectNumOfDefinedDomains = vmwareConnectNumOfDefinedDomains, /* 0.8.7 */
1251 1252 1253
    .domainCreate = vmwareDomainCreate, /* 0.8.7 */
    .domainCreateWithFlags = vmwareDomainCreateWithFlags, /* 0.8.7 */
    .domainDefineXML = vmwareDomainDefineXML, /* 0.8.7 */
1254
    .domainDefineXMLFlags = vmwareDomainDefineXMLFlags, /* 1.2.12 */
1255
    .domainUndefine = vmwareDomainUndefine, /* 0.8.7 */
1256
    .domainUndefineFlags = vmwareDomainUndefineFlags, /* 0.9.4 */
1257 1258
    .domainIsActive = vmwareDomainIsActive, /* 0.8.7 */
    .domainIsPersistent = vmwareDomainIsPersistent, /* 0.8.7 */
1259
    .connectIsAlive = vmwareConnectIsAlive, /* 0.9.8 */
1260
    .domainHasManagedSaveImage = vmwareDomainHasManagedSaveImage, /* 1.2.13 */
1261 1262
};

1263 1264 1265 1266
static virConnectDriver vmwareConnectDriver = {
    .hypervisorDriver = &vmwareHypervisorDriver,
};

1267 1268 1269
int
vmwareRegister(void)
{
1270 1271
    return virRegisterConnectDriver(&vmwareConnectDriver,
                                    false);
1272
}