vmware_driver.c 32.2 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 *
J
Ján Tomko 已提交
96
vmwareDataAllocFunc(void *opaque G_GNUC_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,
J
Ján Tomko 已提交
120 121 122
                         unsigned int parseFlags G_GNUC_UNUSED,
                         void *opaque G_GNUC_UNUSED,
                         void *parseOpaque G_GNUC_UNUSED)
123
{
124 125
    struct vmware_driver *driver = opaque;
    if (!virCapabilitiesDomainSupported(driver->caps, def->os.type,
126 127 128 129
                                        def->os.arch,
                                        def->virtType))
        return -1;

130 131 132 133
    return 0;
}

static int
J
Ján Tomko 已提交
134 135 136 137 138
vmwareDomainDeviceDefPostParse(virDomainDeviceDefPtr dev G_GNUC_UNUSED,
                               const virDomainDef *def G_GNUC_UNUSED,
                               unsigned int parseFlags G_GNUC_UNUSED,
                               void *opaque G_GNUC_UNUSED,
                               void *parseOpaque G_GNUC_UNUSED)
139
{
140 141 142 143
    if (dev->type == VIR_DOMAIN_DEVICE_VIDEO &&
        dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT)
        dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VMVGA;

144 145 146 147 148 149
    return 0;
}

virDomainDefParserConfig vmwareDomainDefParserConfig = {
    .devicesPostParseCallback = vmwareDomainDeviceDefPostParse,
    .domainPostParseCallback = vmwareDomainDefPostParse,
150
    .defArch = VIR_ARCH_I686,
151 152
};

153
static virDomainXMLOptionPtr
154
vmwareDomainXMLConfigInit(struct vmware_driver *driver)
155 156 157
{
    virDomainXMLPrivateDataCallbacks priv = { .alloc = vmwareDataAllocFunc,
                                              .free = vmwareDataFreeFunc };
158
    vmwareDomainDefParserConfig.priv = driver;
159 160
    return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv,
                                 NULL, NULL, NULL);
161 162
}

163
static virDrvOpenStatus
164
vmwareConnectOpen(virConnectPtr conn,
J
Ján Tomko 已提交
165 166
                  virConnectAuthPtr auth G_GNUC_UNUSED,
                  virConfPtr conf G_GNUC_UNUSED,
167
                  unsigned int flags)
168 169
{
    struct vmware_driver *driver;
170
    size_t i;
171
    char *tmp;
172
    char *vmrun = NULL;
173

E
Eric Blake 已提交
174 175
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

176
    /* If path isn't /session, then they typoed, so tell them correct path */
177
    if (STRNEQ(conn->uri->path, "/session")) {
178 179 180 181
        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;
182 183 184 185 186
    }

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

187
    if (VIR_ALLOC(driver) < 0)
188
        return VIR_DRV_OPEN_ERROR;
189 190 191 192 193

    /* 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
     */
194
    for (i = 0; i < G_N_ELEMENTS(vmrun_candidates); i++) {
195 196 197 198 199 200 201 202
        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);
203 204 205
        /* If we found one, we can stop looking */
        if (driver->vmrun)
            break;
206 207
    }

208 209 210 211 212
    if (driver->vmrun == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmrun utility is missing"));
        goto cleanup;
    }
213 214 215 216

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

217 218 219 220 221 222
    if ((tmp = STRSKIP(conn->uri->scheme, "vmware")) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to parse URI "
                       "scheme '%s'"), conn->uri->scheme);
        goto cleanup;
    }

223 224
    /* Match the non-'vmware' part of the scheme as the driver backend */
    driver->type = vmwareDriverTypeFromString(tmp);
225 226 227 228 229 230

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

232 233 234
    if (vmwareExtractVersion(driver) < 0)
        goto cleanup;

235
    if (!(driver->domains = virDomainObjListNew()))
236 237 238 239 240
        goto cleanup;

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

241
    if (!(driver->xmlopt = vmwareDomainXMLConfigInit(driver)))
242
        goto cleanup;
243 244 245 246 247 248 249 250

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

    conn->privateData = driver;

    return VIR_DRV_OPEN_SUCCESS;

251
 cleanup:
252
    vmwareFreeDriver(driver);
253
    VIR_FREE(vmrun);
254 255 256 257
    return VIR_DRV_OPEN_ERROR;
};

static int
258
vmwareConnectClose(virConnectPtr conn)
259 260 261 262 263 264 265 266 267 268 269
{
    struct vmware_driver *driver = conn->privateData;

    vmwareFreeDriver(driver);

    conn->privateData = NULL;

    return 0;
}

static const char *
J
Ján Tomko 已提交
270
vmwareConnectGetType(virConnectPtr conn G_GNUC_UNUSED)
271 272 273 274 275
{
    return "VMware";
}

static int
276
vmwareConnectGetVersion(virConnectPtr conn, unsigned long *version)
277 278 279 280 281 282 283 284 285
{
    struct vmware_driver *driver = conn->privateData;

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

286 287 288 289 290 291 292 293 294 295 296 297 298 299
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;

300
    cmd = virCommandNewArgList(driver->vmrun, "-T",
301
                               vmwareDriverTypeToString(driver->type),
302 303 304 305 306 307 308 309 310
                               "list", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

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

311
    for (str = outbuf; (parsedVmxPath = strtok_r(str, "\n", &saveptr)) != NULL;
312
         str = NULL) {
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337

        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;

338
 cleanup:
339 340 341 342 343 344
    virCommandFree(cmd);
    VIR_FREE(outbuf);
    VIR_FREE(vmxAbsolutePath);
    return ret;
}

345
static int
J
Jiri Denemark 已提交
346 347 348
vmwareStopVM(struct vmware_driver *driver,
             virDomainObjPtr vm,
             virDomainShutoffReason reason)
349 350
{
    const char *cmd[] = {
351
        driver->vmrun, "-T", PROGRAM_SENTINEL, "stop",
E
Eric Blake 已提交
352
        PROGRAM_SENTINEL, "soft", NULL
353 354
    };

355
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
356 357
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);

358
    if (virRun(cmd, NULL) < 0)
359 360 361
        return -1;

    vm->def->id = -1;
J
Jiri Denemark 已提交
362
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
363 364 365 366 367 368 369 370

    return 0;
}

static int
vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm)
{
    const char *cmd[] = {
371
        driver->vmrun, "-T", PROGRAM_SENTINEL, "start",
E
Eric Blake 已提交
372
        PROGRAM_SENTINEL, PROGRAM_SENTINEL, NULL
373 374 375
    };
    const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;

J
Jiri Denemark 已提交
376
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
377 378
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not in shutoff state"));
379 380 381
        return -1;
    }

382
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
383 384 385 386 387 388
    vmwareSetSentinal(cmd, vmxPath);
    if (!((vmwareDomainPtr) vm->privateData)->gui)
        vmwareSetSentinal(cmd, NOGUI);
    else
        vmwareSetSentinal(cmd, NULL);

389
    if (virRun(cmd, NULL) < 0)
390 391 392
        return -1;

    if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) {
J
Jiri Denemark 已提交
393
        vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
394 395 396
        return -1;
    }

J
Jiri Denemark 已提交
397
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
398 399 400 401 402

    return 0;
}

static virDomainPtr
403
vmwareDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
404 405 406 407 408 409 410 411 412 413
{
    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;
414
    virVMXContext ctx;
415
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
416

417 418 419
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
420
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
421

422
    ctx.parseFileName = NULL;
423
    ctx.formatFileName = vmwareCopyVMXFileName;
424 425
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
426 427

    vmwareDriverLock(driver);
428
    if ((vmdef = virDomainDefParseString(xml, driver->xmlopt,
429
                                         NULL, parse_flags)) == NULL)
430
        goto cleanup;
431 432 433

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

    /* generate vmx file */
436
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
437 438 439 440 441 442 443 444
    if (vmx == NULL)
        goto cleanup;

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

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
445 446
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
447 448 449 450
        goto cleanup;
    }

    /* assign def */
451
    if (!(vm = virDomainObjListAdd(driver->domains,
452
                                   vmdef,
453
                                   driver->xmlopt,
454 455
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
456 457 458
        goto cleanup;

    pDomain = vm->privateData;
459
    pDomain->vmxPath = g_strdup(vmxPath);
460 461 462 463 464 465

    vmwareDomainConfigDisplay(pDomain, vmdef);

    vmdef = NULL;
    vm->persistent = 1;

466
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, -1);
467

468
 cleanup:
469 470 471 472 473 474
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(directoryName);
    VIR_FREE(fileName);
    VIR_FREE(vmxPath);
    if (vm)
475
        virObjectUnlock(vm);
476 477 478 479
    vmwareDriverUnlock(driver);
    return dom;
}

480 481 482 483 484 485
static virDomainPtr
vmwareDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return vmwareDomainDefineXMLFlags(conn, xml, 0);
}

486
static int
487 488
vmwareDomainShutdownFlags(virDomainPtr dom,
                          unsigned int flags)
489 490 491 492 493
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

494 495
    virCheckFlags(0, -1);

496 497
    vmwareDriverLock(driver);

498
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
499 500
        goto cleanup;

501 502 503
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
504
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
505 506
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
507 508 509
        goto cleanup;
    }

J
Jiri Denemark 已提交
510
    if (vmwareStopVM(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0)
511 512
        goto cleanup;

513
    if (!vm->persistent)
514
        virDomainObjListRemove(driver->domains, vm);
515 516

    ret = 0;
517
 cleanup:
518
    virDomainObjEndAPI(&vm);
519 520 521 522
    vmwareDriverUnlock(driver);
    return ret;
}

523 524 525 526 527 528
static int
vmwareDomainShutdown(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

529 530 531 532 533 534 535 536 537 538 539 540 541
static int
vmwareDomainDestroy(virDomainPtr dom)
{
    return vmwareDomainShutdownFlags(dom, 0);
}

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

542 543 544 545 546 547 548
static int
vmwareDomainSuspend(virDomainPtr dom)
{
    struct vmware_driver *driver = dom->conn->privateData;

    virDomainObjPtr vm;
    const char *cmd[] = {
549
      driver->vmrun, "-T", PROGRAM_SENTINEL, "pause",
E
Eric Blake 已提交
550
      PROGRAM_SENTINEL, NULL
551 552 553
    };
    int ret = -1;

554
    if (driver->type == VMWARE_DRIVER_PLAYER) {
555 556 557
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("vmplayer does not support libvirt suspend/resume"
                         " (vmware pause/unpause) operation "));
558 559 560
        return ret;
    }

561 562
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
563

564
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
565
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
566
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
567 568
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
569 570 571 572 573 574
        goto cleanup;
    }

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

J
Jiri Denemark 已提交
575
    virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
576 577
    ret = 0;

578
 cleanup:
579
    virDomainObjEndAPI(&vm);
580 581 582 583 584 585 586 587 588 589
    return ret;
}

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

    virDomainObjPtr vm;
    const char *cmd[] = {
590
        driver->vmrun, "-T", PROGRAM_SENTINEL, "unpause", PROGRAM_SENTINEL,
591 592 593 594
        NULL
    };
    int ret = -1;

595
    if (driver->type == VMWARE_DRIVER_PLAYER) {
596
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
597
                       _("vmplayer does not support libvirt suspend/resume "
598
                         "(vmware pause/unpause) operation "));
599 600 601
        return ret;
    }

602 603
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
604

605
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
606
    vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath);
J
Jiri Denemark 已提交
607
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
608 609
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in suspend state"));
610 611 612 613 614 615
        goto cleanup;
    }

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

J
Jiri Denemark 已提交
616
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
617 618
    ret = 0;

619
 cleanup:
620
    virDomainObjEndAPI(&vm);
621 622 623 624
    return ret;
}

static int
E
Eric Blake 已提交
625
vmwareDomainReboot(virDomainPtr dom, unsigned int flags)
626 627 628 629 630
{
    struct vmware_driver *driver = dom->conn->privateData;
    const char * vmxPath = NULL;
    virDomainObjPtr vm;
    const char *cmd[] = {
631
        driver->vmrun, "-T", PROGRAM_SENTINEL,
E
Eric Blake 已提交
632
        "reset", PROGRAM_SENTINEL, "soft", NULL
633 634 635
    };
    int ret = -1;

E
Eric Blake 已提交
636 637
    virCheckFlags(0, -1);

638 639
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
640

641
    vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath;
642
    vmwareSetSentinal(cmd, vmwareDriverTypeToString(driver->type));
C
Christophe Fergeau 已提交
643
    vmwareSetSentinal(cmd, vmxPath);
644

645 646
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;
647

J
Jiri Denemark 已提交
648
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
649 650
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domain is not in running state"));
651 652 653 654 655 656 657 658
        goto cleanup;
    }

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

    ret = 0;

659
 cleanup:
660
    virDomainObjEndAPI(&vm);
661 662 663 664 665
    return ret;
}

static virDomainPtr
vmwareDomainCreateXML(virConnectPtr conn, const char *xml,
E
Eric Blake 已提交
666
                      unsigned int flags)
667 668 669 670 671 672 673 674
{
    struct vmware_driver *driver = conn->privateData;
    virDomainDefPtr vmdef = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
    char *vmx = NULL;
    char *vmxPath = NULL;
    vmwareDomainPtr pDomain = NULL;
675
    virVMXContext ctx;
676 677 678
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
679

680
    if (flags & VIR_DOMAIN_START_VALIDATE)
681
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
E
Eric Blake 已提交
682

683
    ctx.parseFileName = NULL;
684
    ctx.formatFileName = vmwareCopyVMXFileName;
685 686
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
687 688 689

    vmwareDriverLock(driver);

690
    if ((vmdef = virDomainDefParseString(xml, driver->xmlopt,
691
                                         NULL, parse_flags)) == NULL)
692 693 694
        goto cleanup;

    /* generate vmx file */
695
    vmx = virVMXFormatConfig(&ctx, driver->xmlopt, vmdef, 7);
696 697 698 699 700 701 702 703
    if (vmx == NULL)
        goto cleanup;

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

    /* create vmx file */
    if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) {
704 705
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to write vmx file '%s'"), vmxPath);
706 707 708 709
        goto cleanup;
    }

    /* assign def */
710
    if (!(vm = virDomainObjListAdd(driver->domains,
711
                                   vmdef,
712
                                   driver->xmlopt,
713
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
714 715
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
716 717 718
        goto cleanup;

    pDomain = vm->privateData;
719
    pDomain->vmxPath = g_strdup(vmxPath);
720 721 722 723 724

    vmwareDomainConfigDisplay(pDomain, vmdef);
    vmdef = NULL;

    if (vmwareStartVM(driver, vm) < 0) {
725
        if (!vm->persistent)
726
            virDomainObjListRemove(driver->domains, vm);
727 728 729
        goto cleanup;
    }

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

732
 cleanup:
733 734 735
    virDomainDefFree(vmdef);
    VIR_FREE(vmx);
    VIR_FREE(vmxPath);
736
    virDomainObjEndAPI(&vm);
737 738 739 740 741 742
    vmwareDriverUnlock(driver);
    return dom;
}

static int
vmwareDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
743
                            unsigned int flags)
744 745 746 747 748
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

E
Eric Blake 已提交
749 750
    virCheckFlags(0, -1);

751
    vmwareDriverLock(driver);
752
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
753 754
        goto cleanup;

755 756 757
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

758
    if (virDomainObjIsActive(vm)) {
759 760
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
761 762 763 764 765
        goto cleanup;
    }

    ret = vmwareStartVM(driver, vm);

766
 cleanup:
767
    virDomainObjEndAPI(&vm);
768 769 770 771 772 773 774 775 776 777 778
    vmwareDriverUnlock(driver);
    return ret;
}

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

static int
779 780
vmwareDomainUndefineFlags(virDomainPtr dom,
                          unsigned int flags)
781 782 783 784 785
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

786 787
    virCheckFlags(0, -1);

788
    vmwareDriverLock(driver);
789
    if (!(vm = vmwareDomObjFromDomainLocked(driver, dom->uuid)))
790 791 792
        goto cleanup;

    if (!vm->persistent) {
793 794
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
795 796 797
        goto cleanup;
    }

798 799 800
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

801
    if (virDomainObjIsActive(vm))
802
        vm->persistent = 0;
803
    else
804
        virDomainObjListRemove(driver->domains, vm);
805

806 807
    ret = 0;

808
 cleanup:
809
    virDomainObjEndAPI(&vm);
810 811 812 813
    vmwareDriverUnlock(driver);
    return ret;
}

814 815 816 817 818 819
static int
vmwareDomainUndefine(virDomainPtr dom)
{
    return vmwareDomainUndefineFlags(dom, 0);
}

820 821 822 823 824 825 826 827
static virDomainPtr
vmwareDomainLookupByID(virConnectPtr conn, int id)
{
    struct vmware_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

    vmwareDriverLock(driver);
828
    vm = virDomainObjListFindByID(driver->domains, id);
829 830 831
    vmwareDriverUnlock(driver);

    if (!vm) {
832 833
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id '%d'"), id);
834 835 836
        goto cleanup;
    }

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

839
 cleanup:
840
    virDomainObjEndAPI(&vm);
841 842 843 844
    return dom;
}

static char *
845
vmwareDomainGetOSType(virDomainPtr dom)
846 847 848 849 850
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

851 852
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return NULL;
853

854
    ret = g_strdup(virDomainOSTypeToString(vm->def->os.type));
855

856
    virDomainObjEndAPI(&vm);
857 858 859 860 861 862 863 864 865 866 867
    return ret;
}


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

868 869
    if (!(vm = vmwareDomObjFromDomain(driver, uuid)))
        return NULL;
870

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

873
    virDomainObjEndAPI(&vm);
874 875 876 877 878 879 880 881 882 883 884
    return dom;
}

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

    vmwareDriverLock(driver);
885
    vm = virDomainObjListFindByName(driver->domains, name);
886 887 888
    vmwareDriverUnlock(driver);

    if (!vm) {
889 890
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
891 892 893
        goto cleanup;
    }

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

896
 cleanup:
897
    virDomainObjEndAPI(&vm);
898 899 900 901 902 903 904 905 906 907
    return dom;
}

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

908 909 910
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

911 912
    ret = virDomainObjIsActive(obj);

913
    virDomainObjEndAPI(&obj);
914 915 916 917 918 919 920 921 922 923 924
    return ret;
}


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

925 926 927
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

928 929
    ret = obj->persistent;

930
    virDomainObjEndAPI(&obj);
931 932 933 934 935
    return ret;
}


static char *
936
vmwareDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
937 938 939 940 941
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

942
    virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
943

944 945
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return NULL;
946

947
    ret = virDomainDefFormat(vm->def, driver->xmlopt,
948
                             virDomainDefFormatConvertXMLFlags(flags));
949

950
    virDomainObjEndAPI(&vm);
951 952 953
    return ret;
}

954
static char *
955 956 957
vmwareConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                                 const char *nativeConfig,
                                 unsigned int flags)
958 959 960 961 962 963 964 965
{
    struct vmware_driver *driver = conn->privateData;
    virVMXContext ctx;
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    virCheckFlags(0, NULL);

H
Han Han 已提交
966
    if (STRNEQ(nativeFormat, VMX_CONFIG_FORMAT_ARGV)) {
967 968
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
969 970 971 972
        return NULL;
    }

    ctx.parseFileName = vmwareCopyVMXFileName;
973 974 975
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;
    ctx.datacenterPath = NULL;
976

977
    def = virVMXParseConfig(&ctx, driver->xmlopt, driver->caps, nativeConfig);
978 979

    if (def != NULL)
980
        xml = virDomainDefFormat(def, driver->xmlopt,
981
                                 VIR_DOMAIN_DEF_FORMAT_INACTIVE);
982 983 984 985 986 987

    virDomainDefFree(def);

    return xml;
}

988
static int vmwareDomainObjListUpdateDomain(virDomainObjPtr dom, void *data)
989 990
{
    struct vmware_driver *driver = data;
991 992 993 994
    virObjectLock(dom);
    ignore_value(vmwareUpdateVMStatus(driver, dom));
    virObjectUnlock(dom);
    return 0;
995 996 997 998 999
}

static void
vmwareDomainObjListUpdateAll(virDomainObjListPtr doms, struct vmware_driver *driver)
{
1000
    virDomainObjListForEach(doms, false, vmwareDomainObjListUpdateDomain, driver);
1001 1002
}

1003
static int
1004
vmwareConnectNumOfDefinedDomains(virConnectPtr conn)
1005 1006 1007 1008 1009
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1010
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1011
    n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
1012 1013 1014 1015 1016 1017
    vmwareDriverUnlock(driver);

    return n;
}

static int
1018
vmwareConnectNumOfDomains(virConnectPtr conn)
1019 1020 1021 1022 1023
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1024
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1025
    n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
1026 1027 1028 1029 1030 1031 1032
    vmwareDriverUnlock(driver);

    return n;
}


static int
1033
vmwareConnectListDomains(virConnectPtr conn, int *ids, int nids)
1034 1035 1036 1037 1038
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1039
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1040
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids, NULL, NULL);
1041 1042 1043 1044 1045 1046
    vmwareDriverUnlock(driver);

    return n;
}

static int
1047 1048
vmwareConnectListDefinedDomains(virConnectPtr conn,
                                char **const names, int nnames)
1049 1050 1051 1052 1053
{
    struct vmware_driver *driver = conn->privateData;
    int n;

    vmwareDriverLock(driver);
1054
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1055 1056
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         NULL, NULL);
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    vmwareDriverUnlock(driver);
    return n;
}

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

1068 1069
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
1070

1071 1072 1073
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1074
    info->state = virDomainObjGetState(vm, NULL);
1075
    info->cpuTime = 0;
1076
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1077
    info->memory = vm->def->mem.cur_balloon;
1078
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
1079 1080
    ret = 0;

1081
 cleanup:
1082
    virDomainObjEndAPI(&vm);
1083 1084 1085
    return ret;
}

1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
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);

1098 1099
    if (!(vm = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;
1100

1101 1102 1103
    if (vmwareUpdateVMStatus(driver, vm) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1104
    *state = virDomainObjGetState(vm, reason);
1105 1106
    ret = 0;

1107
 cleanup:
1108
    virDomainObjEndAPI(&vm);
1109 1110 1111
    return ret;
}

1112
static int
J
Ján Tomko 已提交
1113
vmwareConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
1114 1115 1116 1117
{
    return 1;
}

1118
static int
1119 1120 1121
vmwareConnectListAllDomains(virConnectPtr conn,
                            virDomainPtr **domains,
                            unsigned int flags)
1122 1123 1124 1125
{
    struct vmware_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
1126
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
1127 1128

    vmwareDriverLock(driver);
1129
    vmwareDomainObjListUpdateAll(driver->domains, driver);
1130 1131
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 NULL, flags);
1132 1133 1134 1135
    vmwareDriverUnlock(driver);
    return ret;
}

1136 1137 1138 1139 1140 1141 1142 1143 1144
static int
vmwareDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct vmware_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    virCheckFlags(0, -1);

1145 1146 1147
    if (!(obj = vmwareDomObjFromDomain(driver, dom->uuid)))
        return -1;

1148 1149
    ret = 0;

1150
    virDomainObjEndAPI(&obj);
1151 1152 1153
    return ret;
}

1154 1155


1156
static virHypervisorDriver vmwareHypervisorDriver = {
1157
    .name = "VMWARE",
1158 1159 1160 1161 1162 1163 1164
    .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 */
1165 1166 1167 1168 1169 1170 1171
    .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 */
1172
    .domainShutdownFlags = vmwareDomainShutdownFlags, /* 0.9.10 */
1173
    .domainReboot = vmwareDomainReboot, /* 0.8.7 */
1174 1175 1176
    .domainDestroy = vmwareDomainDestroy, /* 0.8.7 */
    .domainDestroyFlags = vmwareDomainDestroyFlags, /* 0.9.4 */
    .domainGetOSType = vmwareDomainGetOSType, /* 0.8.7 */
1177 1178 1179
    .domainGetInfo = vmwareDomainGetInfo, /* 0.8.7 */
    .domainGetState = vmwareDomainGetState, /* 0.9.2 */
    .domainGetXMLDesc = vmwareDomainGetXMLDesc, /* 0.8.7 */
1180 1181 1182
    .connectDomainXMLFromNative = vmwareConnectDomainXMLFromNative, /* 0.9.11 */
    .connectListDefinedDomains = vmwareConnectListDefinedDomains, /* 0.8.7 */
    .connectNumOfDefinedDomains = vmwareConnectNumOfDefinedDomains, /* 0.8.7 */
1183 1184 1185
    .domainCreate = vmwareDomainCreate, /* 0.8.7 */
    .domainCreateWithFlags = vmwareDomainCreateWithFlags, /* 0.8.7 */
    .domainDefineXML = vmwareDomainDefineXML, /* 0.8.7 */
1186
    .domainDefineXMLFlags = vmwareDomainDefineXMLFlags, /* 1.2.12 */
1187
    .domainUndefine = vmwareDomainUndefine, /* 0.8.7 */
1188
    .domainUndefineFlags = vmwareDomainUndefineFlags, /* 0.9.4 */
1189 1190
    .domainIsActive = vmwareDomainIsActive, /* 0.8.7 */
    .domainIsPersistent = vmwareDomainIsPersistent, /* 0.8.7 */
1191
    .connectIsAlive = vmwareConnectIsAlive, /* 0.9.8 */
1192
    .domainHasManagedSaveImage = vmwareDomainHasManagedSaveImage, /* 1.2.13 */
1193 1194
};

1195
static virConnectDriver vmwareConnectDriver = {
1196
    .localOnly = true,
1197
    .uriSchemes = (const char *[]){ "vmwareplayer", "vmwarews", "vmwarefusion", NULL },
1198 1199 1200
    .hypervisorDriver = &vmwareHypervisorDriver,
};

1201 1202 1203
int
vmwareRegister(void)
{
1204 1205
    return virRegisterConnectDriver(&vmwareConnectDriver,
                                    false);
1206
}