esx_driver.c 169.4 KB
Newer Older
1 2

/*
3
 * esx_driver.c: core driver functions for managing VMware ESX hosts
4
 *
5
 * Copyright (C) 2010-2013 Red Hat, Inc.
6
 * Copyright (C) 2009-2013 Matthias Bolte <matthias.bolte@googlemail.com>
7 8 9 10 11 12 13 14 15 16 17 18 19
 * Copyright (C) 2009 Maximilian Wilhelm <max@rfc2324.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library.  If not, see
O
Osier Yang 已提交
21
 * <http://www.gnu.org/licenses/>.
22 23 24 25 26 27 28
 *
 */

#include <config.h>

#include "internal.h"
#include "domain_conf.h"
29
#include "snapshot_conf.h"
30
#include "virauth.h"
31
#include "viralloc.h"
32
#include "virfile.h"
33
#include "virlog.h"
34
#include "viruuid.h"
35
#include "vmx.h"
36
#include "virtypedparam.h"
37
#include "esx_driver.h"
38 39 40 41 42
#include "esx_interface_driver.h"
#include "esx_network_driver.h"
#include "esx_storage_driver.h"
#include "esx_device_monitor.h"
#include "esx_secret_driver.h"
M
Matthias Bolte 已提交
43
#include "esx_nwfilter_driver.h"
44
#include "esx_private.h"
45 46 47
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
48
#include "virstring.h"
49
#include "viruri.h"
50 51 52 53 54

#define VIR_FROM_THIS VIR_FROM_ESX

static int esxDomainGetMaxVcpus(virDomainPtr domain);

55 56 57 58
typedef struct _esxVMX_Data esxVMX_Data;

struct _esxVMX_Data {
    esxVI_Context *ctx;
59
    char *datastorePathWithoutFileName;
60 61 62 63
};



64 65 66 67 68 69 70 71 72 73
static void
esxFreePrivate(esxPrivate **priv)
{
    if (priv == NULL || *priv == NULL) {
        return;
    }

    esxVI_Context_Free(&(*priv)->host);
    esxVI_Context_Free(&(*priv)->vCenter);
    esxUtil_FreeParsedUri(&(*priv)->parsedUri);
74
    virObjectUnref((*priv)->caps);
75
    virObjectUnref((*priv)->xmlopt);
76 77 78 79 80
    VIR_FREE(*priv);
}



81
/*
82 83
 * Parse a file name from a .vmx file and convert it to datastore path format
 * if possbile. A .vmx file can contain file names in various formats:
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
 *
 * - A single name referencing a file in the same directory as the .vmx file:
 *
 *     test1.vmdk
 *
 * - An absolute file name referencing a file in a datastore that is mounted at
 *   /vmfs/volumes/<datastore>:
 *
 *     /vmfs/volumes/b24b7a78-9d82b4f5/test1/test1.vmdk
 *     /vmfs/volumes/datastore1/test1/test1.vmdk
 *
 *   The actual mount directory is /vmfs/volumes/b24b7a78-9d82b4f5, the second
 *   form is a symlink to it using the datastore name. This is the typical
 *   setup on an ESX(i) server.
 *
 * - With GSX installed on Windows there are also Windows style file names
 *   including UNC file names:
 *
 *     C:\Virtual Machines\test1\test1.vmdk
 *     \\nas1\storage1\test1\test1.vmdk
 *
105 106 107 108 109 110 111 112
 * - There might also be absolute file names referencing files outside of a
 *   datastore:
 *
 *     /usr/lib/vmware/isoimages/linux.iso
 *
 *   Such file names are left as is and are not converted to datastore path
 *   format because this is not possible.
 *
113 114 115 116 117 118 119
 * The datastore path format typically looks like this:
 *
 *  [datastore1] test1/test1.vmdk
 *
 * Firstly this functions checks if the given file name contains a separator.
 * If it doesn't then the referenced file is in the same directory as the .vmx
 * file. The datastore name and directory of the .vmx file are passed to this
120
 * function via the opaque parameter by the caller of virVMXParseConfig.
121 122 123 124 125 126 127 128 129
 *
 * Otherwise query for all known datastores and their mount directories. Then
 * try to find a datastore with a mount directory that is a prefix to the given
 * file name. This mechanism covers the Windows style file names too.
 *
 * The symlinks using the datastore name (/vmfs/volumes/datastore1) are an
 * exception and need special handling. Parse the datastore name and use it
 * to lookup the datastore by name to verify that it exists.
 */
130
static char *
131
esxParseVMXFileName(const char *fileName, void *opaque)
132
{
133
    char *result = NULL;
134
    esxVMX_Data *data = opaque;
135
    esxVI_String *propertyNameList = NULL;
136
    esxVI_ObjectContent *datastoreList = NULL;
137
    esxVI_ObjectContent *datastore = NULL;
138 139 140 141 142 143 144 145 146 147
    esxVI_DatastoreHostMount *hostMount = NULL;
    char *datastoreName;
    char *tmp;
    char *saveptr;
    char *strippedFileName = NULL;
    char *copyOfFileName = NULL;
    char *directoryAndFileName;

    if (strchr(fileName, '/') == NULL && strchr(fileName, '\\') == NULL) {
        /* Plain file name, use same directory as for the .vmx file */
148
        if (virAsprintf(&result, "%s/%s",
149
                        data->datastorePathWithoutFileName, fileName) < 0)
150 151 152 153 154 155 156 157
            goto cleanup;
    } else {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "summary.name") < 0 ||
            esxVI_LookupDatastoreList(data->ctx, propertyNameList,
                                      &datastoreList) < 0) {
            return NULL;
        }
158

159 160 161 162 163
        /* Search for datastore by mount path */
        for (datastore = datastoreList; datastore != NULL;
             datastore = datastore->_next) {
            esxVI_DatastoreHostMount_Free(&hostMount);
            datastoreName = NULL;
164

165
            if (esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
166 167
                                               &hostMount,
                                               esxVI_Occurrence_RequiredItem) < 0 ||
168 169 170 171
                esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
                                     esxVI_Occurrence_RequiredItem) < 0) {
                goto cleanup;
            }
172

173
            tmp = (char *)STRSKIP(fileName, hostMount->mountInfo->path);
174

175 176 177
            if (tmp == NULL) {
                continue;
            }
178

179 180 181 182
            /* Found a match. Strip leading separators */
            while (*tmp == '/' || *tmp == '\\') {
                ++tmp;
            }
183

184
            if (VIR_STRDUP(strippedFileName, tmp) < 0) {
185 186
                goto cleanup;
            }
187

188
            tmp = strippedFileName;
189

190 191 192 193 194
            /* Convert \ to / */
            while (*tmp != '\0') {
                if (*tmp == '\\') {
                    *tmp = '/';
                }
195

196 197
                ++tmp;
            }
198

199
            if (virAsprintf(&result, "[%s] %s", datastoreName,
200
                            strippedFileName) < 0)
201
                goto cleanup;
202

203 204
            break;
        }
205

206
        /* Fallback to direct datastore name match */
207
        if (result == NULL && STRPREFIX(fileName, "/vmfs/volumes/")) {
208
            if (VIR_STRDUP(copyOfFileName, fileName) < 0) {
209 210
                goto cleanup;
            }
211

212 213 214 215
            /* Expected format: '/vmfs/volumes/<datastore>/<path>' */
            if ((tmp = STRSKIP(copyOfFileName, "/vmfs/volumes/")) == NULL ||
                (datastoreName = strtok_r(tmp, "/", &saveptr)) == NULL ||
                (directoryAndFileName = strtok_r(NULL, "", &saveptr)) == NULL) {
216 217 218
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("File name '%s' doesn't have expected format "
                                 "'/vmfs/volumes/<datastore>/<path>'"), fileName);
219 220
                goto cleanup;
            }
221

222
            esxVI_ObjectContent_Free(&datastoreList);
223

224 225 226 227 228
            if (esxVI_LookupDatastoreByName(data->ctx, datastoreName,
                                            NULL, &datastoreList,
                                            esxVI_Occurrence_OptionalItem) < 0) {
                goto cleanup;
            }
229

230
            if (datastoreList == NULL) {
231 232 233
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("File name '%s' refers to non-existing datastore '%s'"),
                               fileName, datastoreName);
234 235
                goto cleanup;
            }
236

237
            if (virAsprintf(&result, "[%s] %s", datastoreName,
238
                            directoryAndFileName) < 0)
239
                goto cleanup;
240 241
        }

242 243 244
        /* If it's an absolute path outside of a datastore just use it as is */
        if (result == NULL && *fileName == '/') {
            /* FIXME: need to deal with Windows paths here too */
245
            if (VIR_STRDUP(result, fileName) < 0) {
246 247 248 249 250
                goto cleanup;
            }
        }

        if (result == NULL) {
251 252
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not handle file name '%s'"), fileName);
253
            goto cleanup;
254
        }
255
    }
256

257 258 259 260 261 262
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&datastoreList);
    esxVI_DatastoreHostMount_Free(&hostMount);
    VIR_FREE(strippedFileName);
    VIR_FREE(copyOfFileName);
263

264
    return result;
265 266 267 268
}



269
/*
E
Eric Blake 已提交
270
 * This function does the inverse of esxParseVMXFileName. It takes a file name
271 272
 * in datastore path format or in absolute format and converts it to a file
 * name that can be used in a .vmx file.
273 274 275 276 277 278
 *
 * The datastore path format and the formats found in a .vmx file are described
 * in the documentation of esxParseVMXFileName.
 *
 * Firstly parse the datastore path. Then use the datastore name to lookup the
 * datastore and it's mount path. Finally concatenate the mount path, directory
E
Eric Blake 已提交
279
 * and file name to an absolute path and return it. Detect the separator type
280 281
 * based on the mount path.
 */
282
static char *
283
esxFormatVMXFileName(const char *fileName, void *opaque)
284 285
{
    bool success = false;
286
    char *result = NULL;
287
    esxVMX_Data *data = opaque;
288
    char *datastoreName = NULL;
289
    char *directoryAndFileName = NULL;
290 291 292 293 294
    esxVI_ObjectContent *datastore = NULL;
    esxVI_DatastoreHostMount *hostMount = NULL;
    char separator = '/';
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *tmp;
295
    size_t length;
296

297 298 299 300 301 302
    if (*fileName == '[') {
        /* Parse datastore path and lookup datastore */
        if (esxUtil_ParseDatastorePath(fileName, &datastoreName, NULL,
                                       &directoryAndFileName) < 0) {
            goto cleanup;
        }
303

304 305 306
        if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
                                        esxVI_Occurrence_RequiredItem) < 0 ||
            esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
307 308
                                           &hostMount,
                                           esxVI_Occurrence_RequiredItem) < 0) {
309 310
            goto cleanup;
        }
311

312 313 314 315
        /* Detect separator type */
        if (strchr(hostMount->mountInfo->path, '\\') != NULL) {
            separator = '\\';
        }
316

317 318
        /* Strip trailing separators */
        length = strlen(hostMount->mountInfo->path);
319

320 321 322
        while (length > 0 && hostMount->mountInfo->path[length - 1] == separator) {
            --length;
        }
323

324 325
        /* Format as <mount>[/<directory>]/<file>, convert / to \ when necessary */
        virBufferAdd(&buffer, hostMount->mountInfo->path, length);
326

327 328
        if (separator != '/') {
            tmp = directoryAndFileName;
329

330 331 332 333
            while (*tmp != '\0') {
                if (*tmp == '/') {
                    *tmp = separator;
                }
334

335 336
                ++tmp;
            }
337
        }
338

339 340
        virBufferAddChar(&buffer, separator);
        virBufferAdd(&buffer, directoryAndFileName, -1);
341

342 343 344 345 346 347 348 349
        if (virBufferError(&buffer)) {
            virReportOOMError();
            goto cleanup;
        }

        result = virBufferContentAndReset(&buffer);
    } else if (*fileName == '/') {
        /* FIXME: need to deal with Windows paths here too */
350
        if (VIR_STRDUP(result, fileName) < 0) {
351 352 353
            goto cleanup;
        }
    } else {
354 355
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not handle file name '%s'"), fileName);
356 357 358 359 360 361 362 363 364
        goto cleanup;
    }

    /* FIXME: Check if referenced path/file really exists */

    success = true;

  cleanup:
    if (! success) {
365
        virBufferFreeAndReset(&buffer);
366
        VIR_FREE(result);
367 368 369
    }

    VIR_FREE(datastoreName);
370
    VIR_FREE(directoryAndFileName);
371 372
    esxVI_ObjectContent_Free(&datastore);
    esxVI_DatastoreHostMount_Free(&hostMount);
373

374
    return result;
375 376 377 378 379 380 381 382 383 384
}



static int
esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model,
                                 void *opaque)
{
    int result = -1;
    esxVMX_Data *data = opaque;
385
    esxVI_FileInfo *fileInfo = NULL;
386 387 388 389 390 391 392 393 394 395 396 397 398 399
    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;

    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK ||
        def->bus != VIR_DOMAIN_DISK_BUS_SCSI ||
        def->type != VIR_DOMAIN_DISK_TYPE_FILE ||
        def->src == NULL ||
        ! STRPREFIX(def->src, "[")) {
        /*
         * This isn't a file-based SCSI disk device with a datastore related
         * source path => do nothing.
         */
        return 0;
    }

400 401
    if (esxVI_LookupFileInfoByDatastorePath(data->ctx, def->src,
                                            false, &fileInfo,
402
                                            esxVI_Occurrence_RequiredItem) < 0) {
403 404 405
        goto cleanup;
    }

406
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
407 408

    if (vmDiskFileInfo == NULL || vmDiskFileInfo->controllerType == NULL) {
409 410
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not lookup controller model for '%s'"), def->src);
411 412 413 414 415
        goto cleanup;
    }

    if (STRCASEEQ(vmDiskFileInfo->controllerType,
                  "VirtualBusLogicController")) {
416
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
417 418
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicController")) {
419
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
420 421
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicSASController")) {
422
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068;
423 424
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "ParaVirtualSCSIController")) {
425
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI;
426
    } else {
427 428 429
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Found unexpected controller model '%s' for disk '%s'"),
                       vmDiskFileInfo->controllerType, def->src);
430 431 432 433 434 435
        goto cleanup;
    }

    result = 0;

  cleanup:
436
    esxVI_FileInfo_Free(&fileInfo);
437 438 439 440

    return result;
}

441 442


443
static esxVI_Boolean
444
esxSupportsLongMode(esxPrivate *priv)
445 446 447 448 449 450
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL;
    esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL;
451
    esxVI_ParsedHostCpuIdInfo parsedHostCpuIdInfo;
452 453 454 455 456 457
    char edxLongModeBit = '?';

    if (priv->supportsLongMode != esxVI_Boolean_Undefined) {
        return priv->supportsLongMode;
    }

458
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
459
        return esxVI_Boolean_Undefined;
460 461
    }

462
    if (esxVI_String_AppendValueToList(&propertyNameList,
463
                                       "hardware.cpuFeature") < 0 ||
464 465
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
466
        goto cleanup;
467 468 469 470 471 472
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuFeature")) {
            if (esxVI_HostCpuIdInfo_CastListFromAnyType
473
                  (dynamicProperty->val, &hostCpuIdInfoList) < 0) {
M
Matthias Bolte 已提交
474
                goto cleanup;
475 476 477 478 479
            }

            for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo != NULL;
                 hostCpuIdInfo = hostCpuIdInfo->_next) {
                if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */
480 481
                    if (esxVI_ParseHostCpuIdInfo(&parsedHostCpuIdInfo,
                                                 hostCpuIdInfo) < 0) {
M
Matthias Bolte 已提交
482
                        goto cleanup;
483 484
                    }

485
                    edxLongModeBit = parsedHostCpuIdInfo.edx[29];
486 487 488 489 490 491

                    if (edxLongModeBit == '1') {
                        priv->supportsLongMode = esxVI_Boolean_True;
                    } else if (edxLongModeBit == '0') {
                        priv->supportsLongMode = esxVI_Boolean_False;
                    } else {
492 493 494 495 496
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Bit 29 (Long Mode) of HostSystem property "
                                         "'hardware.cpuFeature[].edx' with value '%s' "
                                         "has unexpected value '%c', expecting '0' "
                                         "or '1'"), hostCpuIdInfo->edx, edxLongModeBit);
M
Matthias Bolte 已提交
497
                        goto cleanup;
498 499 500 501 502 503 504 505 506 507 508 509 510
                    }

                    break;
                }
            }

            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

  cleanup:
M
Matthias Bolte 已提交
511 512 513 514
    /*
     * If we goto cleanup in case of an error then priv->supportsLongMode
     * is still esxVI_Boolean_Undefined, therefore we don't need to set it.
     */
515 516 517 518 519 520 521 522 523
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);
    esxVI_HostCpuIdInfo_Free(&hostCpuIdInfoList);

    return priv->supportsLongMode;
}



524 525 526 527 528 529
static int
esxLookupHostSystemBiosUuid(esxPrivate *priv, unsigned char *uuid)
{
    int result = -1;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
530
    char *uuid_string = NULL;
531

532
    if (esxVI_EnsureSession(priv->primary) < 0) {
533 534 535 536 537
        return -1;
    }

    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "hardware.systemInfo.uuid") < 0 ||
538
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
539 540 541
                                         &hostSystem) < 0 ||
        esxVI_GetStringValue(hostSystem, "hardware.systemInfo.uuid",
                             &uuid_string, esxVI_Occurrence_RequiredItem) < 0) {
542 543 544
        goto cleanup;
    }

545 546 547
    if (strlen(uuid_string) > 0) {
        if (virUUIDParse(uuid_string, uuid) < 0) {
            VIR_WARN("Could not parse host UUID from string '%s'", uuid_string);
548

549 550
            /* HostSystem has an invalid UUID, ignore it */
            memset(uuid, 0, VIR_UUID_BUFLEN);
551
        }
552 553 554
    } else {
        /* HostSystem has an empty UUID */
        memset(uuid, 0, VIR_UUID_BUFLEN);
555 556 557 558 559 560 561 562 563 564 565 566
    }

    result = 0;

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}


567
static virCapsPtr
568
esxCapsInit(esxPrivate *priv)
569
{
570
    esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
571 572 573
    virCapsPtr caps = NULL;
    virCapsGuestPtr guest = NULL;

574 575 576 577 578
    if (supportsLongMode == esxVI_Boolean_Undefined) {
        return NULL;
    }

    if (supportsLongMode == esxVI_Boolean_True) {
579
        caps = virCapabilitiesNew(VIR_ARCH_X86_64, 1, 1);
580
    } else {
581
        caps = virCapabilitiesNew(VIR_ARCH_I686, 1, 1);
582
    }
583

584
    if (caps == NULL)
585 586
        return NULL;

587
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
588

589

590 591 592 593
    if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0) {
        goto failure;
    }

594
    /* i686 */
595 596 597
    guest = virCapabilitiesAddGuest(caps, "hvm",
                                    VIR_ARCH_I686,
                                    NULL, NULL, 0,
598
                                    NULL);
599 600 601 602 603 604 605 606 607 608

    if (guest == NULL) {
        goto failure;
    }

    if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0,
                                      NULL) == NULL) {
        goto failure;
    }

609 610
    /* x86_64 */
    if (supportsLongMode == esxVI_Boolean_True) {
611 612 613
        guest = virCapabilitiesAddGuest(caps, "hvm",
                                        VIR_ARCH_X86_64,
                                        NULL, NULL,
614 615 616 617 618 619 620 621 622 623 624 625
                                        0, NULL);

        if (guest == NULL) {
            goto failure;
        }

        if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0,
                                          NULL) == NULL) {
            goto failure;
        }
    }

626 627 628
    return caps;

  failure:
629
    virObjectUnref(caps);
630 631 632 633 634 635

    return NULL;
}



636
static int
637 638
esxConnectToHost(esxPrivate *priv,
                 virConnectPtr conn,
639
                 virConnectAuthPtr auth,
640 641 642 643 644
                 char **vCenterIpAddress)
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
645
    char *unescapedPassword = NULL;
646 647 648 649 650
    char *password = NULL;
    char *url = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;
651 652 653
    esxVI_ProductVersion expectedProductVersion = STRCASEEQ(conn->uri->scheme, "esx")
        ? esxVI_ProductVersion_ESX
        : esxVI_ProductVersion_GSX;
654 655

    if (vCenterIpAddress == NULL || *vCenterIpAddress != NULL) {
656
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
657 658 659
        return -1;
    }

660
    if (esxUtil_ResolveHostname(conn->uri->server, ipAddress, NI_MAXHOST) < 0) {
661 662 663
        return -1;
    }

664
    if (conn->uri->user != NULL) {
665
        if (VIR_STRDUP(username, conn->uri->user) < 0)
666 667
            goto cleanup;
    } else {
668
        username = virAuthGetUsername(conn, auth, "esx", "root", conn->uri->server);
669 670

        if (username == NULL) {
671
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
672 673 674 675
            goto cleanup;
        }
    }

676
    unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, conn->uri->server);
677

M
Matthias Bolte 已提交
678
    if (unescapedPassword == NULL) {
679
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
680 681 682
        goto cleanup;
    }

M
Matthias Bolte 已提交
683 684 685 686 687 688
    password = esxUtil_EscapeForXml(unescapedPassword);

    if (password == NULL) {
        goto cleanup;
    }

689
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
690
                    conn->uri->server, conn->uri->port) < 0)
691 692 693 694
        goto cleanup;

    if (esxVI_Context_Alloc(&priv->host) < 0 ||
        esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
695
                              priv->parsedUri) < 0 ||
696
        esxVI_Context_LookupManagedObjects(priv->host) < 0) {
697 698 699 700 701
        goto cleanup;
    }

    if (expectedProductVersion == esxVI_ProductVersion_ESX) {
        if (priv->host->productVersion != esxVI_ProductVersion_ESX35 &&
M
Matthias Bolte 已提交
702 703
            priv->host->productVersion != esxVI_ProductVersion_ESX40 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX41 &&
P
Patrice LACHANCE 已提交
704 705
            priv->host->productVersion != esxVI_ProductVersion_ESX4x &&
            priv->host->productVersion != esxVI_ProductVersion_ESX50 &&
M
Martin Kletzander 已提交
706
            priv->host->productVersion != esxVI_ProductVersion_ESX51 &&
P
Patrice LACHANCE 已提交
707
            priv->host->productVersion != esxVI_ProductVersion_ESX5x) {
708 709 710
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s is neither an ESX 3.5, 4.x nor 5.x host"),
                           conn->uri->server);
711 712 713 714
            goto cleanup;
        }
    } else { /* GSX */
        if (priv->host->productVersion != esxVI_ProductVersion_GSX20) {
715 716
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s isn't a GSX 2.0 host"), conn->uri->server);
717 718 719 720 721 722 723 724
            goto cleanup;
        }
    }

    /* Query the host for maintenance mode and vCenter IP address */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "runtime.inMaintenanceMode\0"
                                           "summary.managementServerIp\0") < 0 ||
725 726
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
727 728 729 730 731 732 733 734 735 736 737
        esxVI_GetBoolean(hostSystem, "runtime.inMaintenanceMode",
                         &inMaintenanceMode,
                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetStringValue(hostSystem, "summary.managementServerIp",
                             vCenterIpAddress,
                             esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

    /* Warn if host is in maintenance mode */
    if (inMaintenanceMode == esxVI_Boolean_True) {
738
        VIR_WARN("The server is in maintenance mode");
739 740
    }

741 742
    if (VIR_STRDUP(*vCenterIpAddress, *vCenterIpAddress) < 0)
        goto cleanup;
743 744 745 746 747

    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
748 749
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
750 751 752 753 754 755 756 757 758 759
    VIR_FREE(url);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



static int
760 761
esxConnectToVCenter(esxPrivate *priv,
                    virConnectPtr conn,
762 763
                    virConnectAuthPtr auth,
                    const char *hostname,
764
                    const char *hostSystemIpAddress)
765 766 767 768
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
769
    char *unescapedPassword = NULL;
770 771 772
    char *password = NULL;
    char *url = NULL;

773
    if (hostSystemIpAddress == NULL &&
774
        (priv->parsedUri->path == NULL || STREQ(priv->parsedUri->path, "/"))) {
775 776
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Path has to specify the datacenter and compute resource"));
777 778 779
        return -1;
    }

780 781 782 783
    if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST) < 0) {
        return -1;
    }

784
    if (conn->uri->user != NULL) {
785
        if (VIR_STRDUP(username, conn->uri->user) < 0) {
786 787 788
            goto cleanup;
        }
    } else {
789
        username = virAuthGetUsername(conn, auth, "esx", "administrator", hostname);
790 791

        if (username == NULL) {
792
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
793 794 795 796
            goto cleanup;
        }
    }

797
    unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, hostname);
798

M
Matthias Bolte 已提交
799
    if (unescapedPassword == NULL) {
800
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
801 802 803
        goto cleanup;
    }

M
Matthias Bolte 已提交
804 805 806 807 808 809
    password = esxUtil_EscapeForXml(unescapedPassword);

    if (password == NULL) {
        goto cleanup;
    }

810
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
811
                    hostname, conn->uri->port) < 0)
812 813 814 815
        goto cleanup;

    if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
        esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
816
                              password, priv->parsedUri) < 0) {
817 818 819 820
        goto cleanup;
    }

    if (priv->vCenter->productVersion != esxVI_ProductVersion_VPX25 &&
M
Matthias Bolte 已提交
821 822
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX40 &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX41 &&
P
Patrice LACHANCE 已提交
823 824
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX4x &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX50 &&
M
Martin Kletzander 已提交
825
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX51 &&
P
Patrice LACHANCE 已提交
826
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX5x) {
827 828 829
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s is neither a vCenter 2.5, 4.x nor 5.x server"),
                       hostname);
830 831 832
        goto cleanup;
    }

833
    if (hostSystemIpAddress != NULL) {
834 835
        if (esxVI_Context_LookupManagedObjectsByHostSystemIp
              (priv->vCenter, hostSystemIpAddress) < 0) {
836 837 838
            goto cleanup;
        }
    } else {
839 840
        if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter,
                                                     priv->parsedUri->path) < 0) {
841 842 843 844
            goto cleanup;
        }
    }

845 846 847 848
    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
849 850
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
851 852 853 854 855 856 857
    VIR_FREE(url);

    return result;
}



858
/*
859 860
 * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
 *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
861
 *
862 863
 * If no port is specified the default port is set dependent on the scheme and
 * transport parameter:
864 865
 * - vpx+http  80
 * - vpx+https 443
866
 * - esx+http  80
867
 * - esx+https 443
868 869 870
 * - gsx+http  8222
 * - gsx+https 8333
 *
871 872 873
 * For a vpx:// connection <path> references a host managed by the vCenter.
 * In case the host is part of a cluster then <computeresource> is the cluster
 * name. Otherwise <computeresource> and <hostsystem> are equal and the later
874 875
 * can be omitted. As datacenters and computeresources can be organized in
 * folders those have to be included in <path>.
876
 *
877 878
 * Optional query parameters:
 * - transport={http|https}
879
 * - vcenter={<vcenter>|*}             only useful for an esx:// connection
880 881
 * - no_verify={0|1}
 * - auto_answer={0|1}
M
Matthias Bolte 已提交
882
 * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
883
 *
884 885 886
 * If no transport parameter is specified https is used.
 *
 * The vcenter parameter is only necessary for migration, because the vCenter
887
 * server is in charge to initiate a migration between two ESX hosts. The
888
 * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
889 890
 * the driver will check if the ESX host is managed by a vCenter and connect to
 * it. If the ESX host is not managed by a vCenter an error is reported.
891 892
 *
 * If the no_verify parameter is set to 1, this disables libcurl client checks
893
 * of the server's certificate. The default value it 0.
894 895 896 897
 *
 * If the auto_answer parameter is set to 1, the driver will respond to all
 * virtual machine questions with the default answer, otherwise virtual machine
 * questions will be reported as errors. The default value it 0.
M
Matthias Bolte 已提交
898 899 900 901
 *
 * The proxy parameter allows to specify a proxy for to be used by libcurl.
 * The default for the optional <type> part is http and socks is synonymous for
 * socks5. The optional <port> part allows to override the default port 1080.
902 903
 */
static virDrvOpenStatus
904 905
esxConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
               unsigned int flags)
906
{
M
Matthias Bolte 已提交
907
    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
908
    char *plus;
909
    esxPrivate *priv = NULL;
910
    char *potentialVCenterIpAddress = NULL;
M
Matthias Bolte 已提交
911
    char vCenterIpAddress[NI_MAXHOST] = "";
912

E
Eric Blake 已提交
913 914
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

915 916
    /* Decline if the URI is NULL or the scheme is NULL */
    if (conn->uri == NULL || conn->uri->scheme == NULL) {
917 918 919
        return VIR_DRV_OPEN_DECLINED;
    }

920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
    /* Decline if the scheme is not one of {vpx|esx|gsx} */
    plus = strchr(conn->uri->scheme, '+');

    if (plus == NULL) {
        if (STRCASENEQ(conn->uri->scheme, "vpx") &&
            STRCASENEQ(conn->uri->scheme, "esx") &&
            STRCASENEQ(conn->uri->scheme, "gsx")) {
            return VIR_DRV_OPEN_DECLINED;
        }
    } else {
        if (plus - conn->uri->scheme != 3 ||
            (STRCASENEQLEN(conn->uri->scheme, "vpx", 3) &&
             STRCASENEQLEN(conn->uri->scheme, "esx", 3) &&
             STRCASENEQLEN(conn->uri->scheme, "gsx", 3))) {
            return VIR_DRV_OPEN_DECLINED;
        }

937 938 939
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Transport '%s' in URI scheme is not supported, try again "
                         "without the transport part"), plus + 1);
940 941 942
        return VIR_DRV_OPEN_ERROR;
    }

943 944 945 946 947 948
    if (STRCASENEQ(conn->uri->scheme, "vpx") &&
        conn->uri->path != NULL && STRNEQ(conn->uri->path, "/")) {
        VIR_WARN("Ignoring unexpected path '%s' for non-vpx scheme '%s'",
                 conn->uri->path, conn->uri->scheme);
    }

949 950
    /* Require server part */
    if (conn->uri->server == NULL) {
951 952
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("URI is missing the server part"));
953 954 955 956 957
        return VIR_DRV_OPEN_ERROR;
    }

    /* Require auth */
    if (auth == NULL || auth->cb == NULL) {
958 959
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Missing or invalid auth pointer"));
960
        return VIR_DRV_OPEN_ERROR;
961 962 963
    }

    /* Allocate per-connection private data */
964
    if (VIR_ALLOC(priv) < 0)
M
Matthias Bolte 已提交
965
        goto cleanup;
966

967
    if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0) {
968 969 970
        goto cleanup;
    }

M
Matthias Bolte 已提交
971 972
    priv->maxVcpus = -1;
    priv->supportsVMotion = esxVI_Boolean_Undefined;
973
    priv->supportsLongMode = esxVI_Boolean_Undefined;
974 975
    priv->usedCpuTimeCounterId = -1;

M
Matthias Bolte 已提交
976 977 978 979 980 981 982
    /*
     * Set the port dependent on the transport protocol if no port is
     * specified. This allows us to rely on the port parameter being
     * correctly set when building URIs later on, without the need to
     * distinguish between the situations port == 0 and port != 0
     */
    if (conn->uri->port == 0) {
983 984
        if (STRCASEEQ(conn->uri->scheme, "vpx") ||
            STRCASEEQ(conn->uri->scheme, "esx")) {
985
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
986 987 988 989 990
                conn->uri->port = 443;
            } else {
                conn->uri->port = 80;
            }
        } else { /* GSX */
991
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
992 993 994 995
                conn->uri->port = 8333;
            } else {
                conn->uri->port = 8222;
            }
996
        }
M
Matthias Bolte 已提交
997
    }
998

999 1000 1001
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
1002
        if (esxConnectToHost(priv, conn, auth,
1003
                             &potentialVCenterIpAddress) < 0) {
M
Matthias Bolte 已提交
1004
            goto cleanup;
1005
        }
1006

1007
        /* Connect to vCenter */
1008 1009
        if (priv->parsedUri->vCenter != NULL) {
            if (STREQ(priv->parsedUri->vCenter, "*")) {
1010
                if (potentialVCenterIpAddress == NULL) {
1011 1012
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("This host is not managed by a vCenter"));
M
Matthias Bolte 已提交
1013
                    goto cleanup;
1014 1015
                }

1016 1017
                if (virStrcpyStatic(vCenterIpAddress,
                                    potentialVCenterIpAddress) == NULL) {
1018 1019 1020
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("vCenter IP address %s too big for destination"),
                                   potentialVCenterIpAddress);
1021 1022 1023
                    goto cleanup;
                }
            } else {
1024
                if (esxUtil_ResolveHostname(priv->parsedUri->vCenter,
1025 1026 1027
                                            vCenterIpAddress, NI_MAXHOST) < 0) {
                    goto cleanup;
                }
1028

1029 1030
                if (potentialVCenterIpAddress != NULL &&
                    STRNEQ(vCenterIpAddress, potentialVCenterIpAddress)) {
1031 1032 1033 1034 1035 1036
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("This host is managed by a vCenter with IP "
                                     "address %s, but a mismachting vCenter '%s' "
                                     "(%s) has been specified"),
                                   potentialVCenterIpAddress, priv->parsedUri->vCenter,
                                   vCenterIpAddress);
M
Matthias Bolte 已提交
1037
                    goto cleanup;
1038 1039
                }
            }
1040

1041
            if (esxConnectToVCenter(priv, conn, auth,
1042
                                    vCenterIpAddress,
1043
                                    priv->host->ipAddress) < 0) {
1044 1045
                goto cleanup;
            }
1046 1047
        }

1048 1049 1050
        priv->primary = priv->host;
    } else { /* VPX */
        /* Connect to vCenter */
1051
        if (esxConnectToVCenter(priv, conn, auth,
1052 1053
                                conn->uri->server,
                                NULL) < 0) {
M
Matthias Bolte 已提交
1054
            goto cleanup;
1055 1056
        }

1057
        priv->primary = priv->vCenter;
1058 1059
    }

M
Matthias Bolte 已提交
1060
    /* Setup capabilities */
1061
    priv->caps = esxCapsInit(priv);
1062

M
Matthias Bolte 已提交
1063
    if (priv->caps == NULL) {
M
Matthias Bolte 已提交
1064
        goto cleanup;
1065 1066
    }

1067
    if (!(priv->xmlopt = virVMXDomainXMLConfInit()))
1068 1069
        goto cleanup;

1070 1071
    conn->privateData = priv;
    priv = NULL;
M
Matthias Bolte 已提交
1072
    result = VIR_DRV_OPEN_SUCCESS;
1073

M
Matthias Bolte 已提交
1074
  cleanup:
1075
    esxFreePrivate(&priv);
1076
    VIR_FREE(potentialVCenterIpAddress);
1077

M
Matthias Bolte 已提交
1078
    return result;
1079 1080 1081 1082 1083
}



static int
1084
esxConnectClose(virConnectPtr conn)
1085
{
M
Matthias Bolte 已提交
1086
    esxPrivate *priv = conn->privateData;
E
Eric Blake 已提交
1087
    int result = 0;
1088

1089 1090 1091 1092 1093 1094
    if (priv->host != NULL) {
        if (esxVI_EnsureSession(priv->host) < 0 ||
            esxVI_Logout(priv->host) < 0) {
            result = -1;
        }
    }
1095

M
Matthias Bolte 已提交
1096
    if (priv->vCenter != NULL) {
E
Eric Blake 已提交
1097 1098 1099 1100
        if (esxVI_EnsureSession(priv->vCenter) < 0 ||
            esxVI_Logout(priv->vCenter) < 0) {
            result = -1;
        }
1101 1102
    }

1103
    esxFreePrivate(&priv);
1104 1105 1106

    conn->privateData = NULL;

E
Eric Blake 已提交
1107
    return result;
1108 1109 1110 1111 1112
}



static esxVI_Boolean
1113
esxSupportsVMotion(esxPrivate *priv)
1114 1115 1116 1117
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

M
Matthias Bolte 已提交
1118 1119
    if (priv->supportsVMotion != esxVI_Boolean_Undefined) {
        return priv->supportsVMotion;
1120 1121
    }

1122
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1123
        return esxVI_Boolean_Undefined;
1124 1125
    }

1126
    if (esxVI_String_AppendValueToList(&propertyNameList,
1127
                                       "capability.vmotionSupported") < 0 ||
1128
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1129 1130
                                         &hostSystem) < 0 ||
        esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
1131 1132 1133
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1134 1135 1136
    }

  cleanup:
M
Matthias Bolte 已提交
1137 1138 1139 1140
    /*
     * If we goto cleanup in case of an error then priv->supportsVMotion is
     * still esxVI_Boolean_Undefined, therefore we don't need to set it.
     */
1141 1142 1143
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
1144
    return priv->supportsVMotion;
1145 1146 1147 1148 1149
}



static int
1150
esxConnectSupportsFeature(virConnectPtr conn, int feature)
1151
{
M
Matthias Bolte 已提交
1152
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1153
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1154 1155 1156

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1157
        supportsVMotion = esxSupportsVMotion(priv);
1158

M
Matthias Bolte 已提交
1159
        if (supportsVMotion == esxVI_Boolean_Undefined) {
1160 1161 1162
            return -1;
        }

M
Matthias Bolte 已提交
1163 1164 1165
        /* Migration is only possible via a vCenter and if VMotion is enabled */
        return priv->vCenter != NULL &&
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1166 1167 1168 1169 1170 1171 1172 1173 1174

      default:
        return 0;
    }
}



static const char *
1175
esxConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
1176 1177 1178 1179 1180 1181 1182
{
    return "ESX";
}



static int
1183
esxConnectGetVersion(virConnectPtr conn, unsigned long *version)
1184
{
M
Matthias Bolte 已提交
1185
    esxPrivate *priv = conn->privateData;
1186

1187
    if (virParseVersionString(priv->primary->service->about->version,
1188
                              version, false) < 0) {
1189 1190 1191
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse version number from '%s'"),
                       priv->primary->service->about->version);
1192

1193
        return -1;
1194 1195 1196 1197 1198 1199 1200 1201
    }

    return 0;
}



static char *
1202
esxConnectGetHostname(virConnectPtr conn)
1203
{
M
Matthias Bolte 已提交
1204
    esxPrivate *priv = conn->privateData;
1205 1206 1207 1208 1209 1210 1211
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1212
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1213
        return NULL;
1214 1215 1216
    }

    if (esxVI_String_AppendValueListToList
1217
          (&propertyNameList,
1218 1219
           "config.network.dnsConfig.hostName\0"
           "config.network.dnsConfig.domainName\0") < 0 ||
1220 1221
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1222
        goto cleanup;
1223 1224 1225 1226 1227 1228
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1229
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1230
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1231
                goto cleanup;
1232 1233 1234 1235 1236
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1237
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1238
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1239
                goto cleanup;
1240 1241 1242 1243 1244 1245 1246 1247
            }

            domainName = dynamicProperty->val->string;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

M
Matthias Bolte 已提交
1248
    if (hostName == NULL || strlen(hostName) < 1) {
1249 1250
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1251
        goto cleanup;
1252 1253
    }

M
Matthias Bolte 已提交
1254
    if (domainName == NULL || strlen(domainName) < 1) {
1255
        if (VIR_STRDUP(complete, hostName) < 0)
M
Matthias Bolte 已提交
1256
            goto cleanup;
1257
    } else {
1258
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0)
M
Matthias Bolte 已提交
1259
            goto cleanup;
1260 1261 1262
    }

  cleanup:
M
Matthias Bolte 已提交
1263 1264
    /*
     * If we goto cleanup in case of an error then complete is still NULL,
1265
     * either VIR_STRDUP returned -1 or virAsprintf failed. When virAsprintf
M
Matthias Bolte 已提交
1266 1267
     * fails it guarantees setting complete to NULL
     */
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1279
    int result = -1;
M
Matthias Bolte 已提交
1280
    esxPrivate *priv = conn->privateData;
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    int64_t cpuInfo_hz = 0;
    int16_t cpuInfo_numCpuCores = 0;
    int16_t cpuInfo_numCpuPackages = 0;
    int16_t cpuInfo_numCpuThreads = 0;
    int64_t memorySize = 0;
    int32_t numaInfo_numNodes = 0;
    char *ptr = NULL;

1292
    memset(nodeinfo, 0, sizeof(*nodeinfo));
1293

1294
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1295
        return -1;
1296 1297
    }

1298
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1299 1300 1301 1302 1303 1304 1305
                                           "hardware.cpuInfo.hz\0"
                                           "hardware.cpuInfo.numCpuCores\0"
                                           "hardware.cpuInfo.numCpuPackages\0"
                                           "hardware.cpuInfo.numCpuThreads\0"
                                           "hardware.memorySize\0"
                                           "hardware.numaInfo.numNodes\0"
                                           "summary.hardware.cpuModel\0") < 0 ||
1306 1307
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1308
        goto cleanup;
1309 1310 1311 1312 1313
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1314
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1315
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1316
                goto cleanup;
1317 1318 1319 1320 1321
            }

            cpuInfo_hz = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuCores")) {
1322
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1323
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1324
                goto cleanup;
1325 1326 1327 1328 1329
            }

            cpuInfo_numCpuCores = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuPackages")) {
1330
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1331
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1332
                goto cleanup;
1333 1334 1335 1336 1337
            }

            cpuInfo_numCpuPackages = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuThreads")) {
1338
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1339
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1340
                goto cleanup;
1341 1342 1343 1344
            }

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1345
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1346
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1347
                goto cleanup;
1348 1349 1350 1351 1352
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1353
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1354
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1355
                goto cleanup;
1356 1357 1358 1359 1360
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1361
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1362
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1363
                goto cleanup;
1364 1365 1366 1367 1368 1369
            }

            ptr = dynamicProperty->val->string;

            /* Strip the string to fit more relevant information in 32 chars */
            while (*ptr != '\0') {
M
Matthias Bolte 已提交
1370 1371
                if (STRPREFIX(ptr, "  ")) {
                    memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1372
                    continue;
1373
                } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
M
Matthias Bolte 已提交
1374
                    memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1375
                    continue;
1376 1377 1378
                } else if (STRPREFIX(ptr, "(TM)")) {
                    memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
                    continue;
1379 1380 1381 1382 1383
                }

                ++ptr;
            }

C
Chris Lalancette 已提交
1384 1385 1386
            if (virStrncpy(nodeinfo->model, dynamicProperty->val->string,
                           sizeof(nodeinfo->model) - 1,
                           sizeof(nodeinfo->model)) == NULL) {
1387 1388 1389
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("CPU Model %s too long for destination"),
                               dynamicProperty->val->string);
M
Matthias Bolte 已提交
1390
                goto cleanup;
C
Chris Lalancette 已提交
1391
            }
1392 1393 1394 1395 1396 1397 1398
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1399
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1400 1401 1402 1403 1404 1405 1406 1407 1408
    nodeinfo->nodes = numaInfo_numNodes;
    nodeinfo->sockets = cpuInfo_numCpuPackages;
    nodeinfo->cores = cpuInfo_numCpuPackages > 0
                        ? cpuInfo_numCpuCores / cpuInfo_numCpuPackages
                        : 0;
    nodeinfo->threads = cpuInfo_numCpuCores > 0
                          ? cpuInfo_numCpuThreads / cpuInfo_numCpuCores
                          : 0;

M
Matthias Bolte 已提交
1409 1410
    result = 0;

1411 1412 1413 1414 1415 1416 1417 1418 1419
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1420
static char *
1421
esxConnectGetCapabilities(virConnectPtr conn)
1422
{
M
Matthias Bolte 已提交
1423
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1424
    char *xml = virCapabilitiesFormatXML(priv->caps);
1425 1426

    if (xml == NULL) {
1427
        virReportOOMError();
1428 1429 1430 1431 1432 1433 1434 1435
        return NULL;
    }

    return xml;
}



1436
static int
1437
esxConnectListDomains(virConnectPtr conn, int *ids, int maxids)
1438
{
M
Matthias Bolte 已提交
1439
    bool success = false;
M
Matthias Bolte 已提交
1440
    esxPrivate *priv = conn->privateData;
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

    if (maxids == 0) {
        return 0;
    }

1451
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1452
        return -1;
1453 1454
    }

1455
    if (esxVI_String_AppendValueToList(&propertyNameList,
1456
                                       "runtime.powerState") < 0 ||
1457 1458
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1459
        goto cleanup;
1460 1461 1462 1463
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1464
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1465
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1466
            goto cleanup;
1467 1468 1469 1470 1471 1472 1473 1474 1475
        }

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1476 1477 1478
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to parse positive integer from '%s'"),
                           virtualMachine->obj->value);
M
Matthias Bolte 已提交
1479
            goto cleanup;
1480 1481 1482 1483 1484 1485 1486 1487 1488
        }

        count++;

        if (count >= maxids) {
            break;
        }
    }

M
Matthias Bolte 已提交
1489 1490
    success = true;

1491 1492 1493 1494
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1495
    return success ? count : -1;
1496 1497 1498 1499 1500
}



static int
1501
esxConnectNumOfDomains(virConnectPtr conn)
1502
{
M
Matthias Bolte 已提交
1503
    esxPrivate *priv = conn->privateData;
1504

1505
    if (esxVI_EnsureSession(priv->primary) < 0) {
1506 1507 1508
        return -1;
    }

1509
    return esxVI_LookupNumberOfDomainsByPowerState
1510
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1511 1512 1513 1514 1515 1516 1517
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1518
    esxPrivate *priv = conn->privateData;
1519 1520 1521 1522
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1523 1524 1525
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1526 1527
    virDomainPtr domain = NULL;

1528
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1529
        return NULL;
1530 1531
    }

1532
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1533
                                           "configStatus\0"
1534 1535
                                           "name\0"
                                           "runtime.powerState\0"
1536
                                           "config.uuid\0") < 0 ||
1537 1538
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1539
        goto cleanup;
1540 1541 1542 1543
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1544
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1545
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1546
            goto cleanup;
1547 1548 1549 1550 1551 1552 1553
        }

        /* Only running/suspended domains have an ID != -1 */
        if (powerState == esxVI_VirtualMachinePowerState_PoweredOff) {
            continue;
        }

M
Matthias Bolte 已提交
1554
        VIR_FREE(name_candidate);
1555

1556
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1557 1558
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1559
            goto cleanup;
1560 1561
        }

M
Matthias Bolte 已提交
1562
        if (id != id_candidate) {
1563 1564 1565
            continue;
        }

M
Matthias Bolte 已提交
1566
        domain = virGetDomain(conn, name_candidate, uuid_candidate);
1567 1568

        if (domain == NULL) {
M
Matthias Bolte 已提交
1569
            goto cleanup;
1570 1571 1572 1573 1574 1575 1576 1577
        }

        domain->id = id;

        break;
    }

    if (domain == NULL) {
1578
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1579 1580 1581 1582 1583
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1584
    VIR_FREE(name_candidate);
1585 1586 1587 1588 1589 1590 1591 1592 1593

    return domain;
}



static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
M
Matthias Bolte 已提交
1594
    esxPrivate *priv = conn->privateData;
1595 1596 1597
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1598 1599
    int id = -1;
    char *name = NULL;
1600 1601
    virDomainPtr domain = NULL;

1602
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1603
        return NULL;
1604 1605
    }

1606
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1607
                                           "name\0"
1608
                                           "runtime.powerState\0") < 0 ||
1609
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1610
                                         &virtualMachine,
M
Matthias Bolte 已提交
1611
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1612 1613
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1614
        goto cleanup;
1615 1616
    }

1617
    domain = virGetDomain(conn, name, uuid);
1618 1619

    if (domain == NULL) {
M
Matthias Bolte 已提交
1620
        goto cleanup;
1621
    }
1622

1623 1624 1625 1626 1627
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1628 1629 1630 1631
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1632 1633
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1634 1635 1636 1637 1638 1639 1640 1641 1642

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1643
    esxPrivate *priv = conn->privateData;
1644 1645 1646
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1647 1648
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1649 1650
    virDomainPtr domain = NULL;

1651
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1652
        return NULL;
1653 1654
    }

1655
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1656
                                           "configStatus\0"
1657
                                           "runtime.powerState\0"
1658
                                           "config.uuid\0") < 0 ||
1659
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1660 1661
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1662
        goto cleanup;
1663 1664
    }

1665
    if (virtualMachine == NULL) {
1666
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1667
        goto cleanup;
1668
    }
1669

M
Matthias Bolte 已提交
1670 1671 1672
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1673
    }
1674

1675
    domain = virGetDomain(conn, name, uuid);
1676

1677
    if (domain == NULL) {
M
Matthias Bolte 已提交
1678
        goto cleanup;
1679 1680
    }

1681 1682 1683 1684 1685
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1686 1687 1688 1689
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1690
    esxVI_ObjectContent_Free(&virtualMachine);
1691 1692 1693 1694 1695 1696 1697 1698 1699

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1700
    int result = -1;
M
Matthias Bolte 已提交
1701
    esxPrivate *priv = domain->conn->privateData;
1702 1703 1704 1705 1706
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1707
    char *taskInfoErrorMessage = NULL;
1708

1709
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1710
        return -1;
1711 1712
    }

1713
    if (esxVI_String_AppendValueToList(&propertyNameList,
1714
                                       "runtime.powerState") < 0 ||
1715
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1716
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1717
           priv->parsedUri->autoAnswer) < 0 ||
1718
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1719
        goto cleanup;
1720 1721 1722
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1723 1724
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1725
        goto cleanup;
1726 1727
    }

1728 1729
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1730
                                    esxVI_Occurrence_RequiredItem,
1731
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1732
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1733
        goto cleanup;
1734 1735 1736
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1737 1738
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1739
        goto cleanup;
1740 1741
    }

M
Matthias Bolte 已提交
1742 1743
    result = 0;

1744 1745 1746 1747
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1748
    VIR_FREE(taskInfoErrorMessage);
1749 1750 1751 1752 1753 1754 1755 1756 1757

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1758
    int result = -1;
M
Matthias Bolte 已提交
1759
    esxPrivate *priv = domain->conn->privateData;
1760 1761 1762 1763 1764
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1765
    char *taskInfoErrorMessage = NULL;
1766

1767
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1768
        return -1;
1769 1770
    }

1771
    if (esxVI_String_AppendValueToList(&propertyNameList,
1772
                                       "runtime.powerState") < 0 ||
1773
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1774
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1775
           priv->parsedUri->autoAnswer) < 0 ||
1776
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1777
        goto cleanup;
1778 1779 1780
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1781
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1782
        goto cleanup;
1783 1784
    }

1785
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1786
                             &task) < 0 ||
1787
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1788
                                    esxVI_Occurrence_RequiredItem,
1789
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1790
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1791
        goto cleanup;
1792 1793 1794
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1795 1796
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1797
        goto cleanup;
1798 1799
    }

M
Matthias Bolte 已提交
1800 1801
    result = 0;

1802 1803 1804 1805
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1806
    VIR_FREE(taskInfoErrorMessage);
1807 1808 1809 1810 1811 1812 1813

    return result;
}



static int
1814
esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
1815
{
M
Matthias Bolte 已提交
1816
    int result = -1;
M
Matthias Bolte 已提交
1817
    esxPrivate *priv = domain->conn->privateData;
1818 1819 1820 1821
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1822 1823
    virCheckFlags(0, -1);

1824
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1825
        return -1;
1826 1827
    }

1828
    if (esxVI_String_AppendValueToList(&propertyNameList,
1829
                                       "runtime.powerState") < 0 ||
1830
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1831
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1832
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1833
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1834
        goto cleanup;
1835 1836 1837
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1838 1839
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1840
        goto cleanup;
1841 1842
    }

1843
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1844
        goto cleanup;
1845 1846
    }

M
Matthias Bolte 已提交
1847 1848
    result = 0;

1849 1850 1851 1852 1853 1854 1855 1856
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


1857 1858 1859 1860 1861 1862
static int
esxDomainShutdown(virDomainPtr domain)
{
    return esxDomainShutdownFlags(domain, 0);
}

1863 1864

static int
E
Eric Blake 已提交
1865
esxDomainReboot(virDomainPtr domain, unsigned int flags)
1866
{
M
Matthias Bolte 已提交
1867
    int result = -1;
M
Matthias Bolte 已提交
1868
    esxPrivate *priv = domain->conn->privateData;
1869 1870 1871 1872
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

E
Eric Blake 已提交
1873 1874
    virCheckFlags(0, -1);

1875
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1876
        return -1;
1877 1878
    }

1879
    if (esxVI_String_AppendValueToList(&propertyNameList,
1880
                                       "runtime.powerState") < 0 ||
1881
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1882
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1883
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1884
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1885
        goto cleanup;
1886 1887 1888
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1889 1890
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1891
        goto cleanup;
1892 1893
    }

1894
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1895
        goto cleanup;
1896 1897
    }

M
Matthias Bolte 已提交
1898 1899
    result = 0;

1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
1910 1911
esxDomainDestroyFlags(virDomainPtr domain,
                      unsigned int flags)
1912
{
M
Matthias Bolte 已提交
1913
    int result = -1;
M
Matthias Bolte 已提交
1914
    esxPrivate *priv = domain->conn->privateData;
1915
    esxVI_Context *ctx = NULL;
1916 1917 1918 1919 1920
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1921
    char *taskInfoErrorMessage = NULL;
1922

1923 1924
    virCheckFlags(0, -1);

1925 1926 1927 1928 1929 1930
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1931
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
1932
        return -1;
1933 1934
    }

1935
    if (esxVI_String_AppendValueToList(&propertyNameList,
1936
                                       "runtime.powerState") < 0 ||
1937
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1938
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1939
           priv->parsedUri->autoAnswer) < 0 ||
1940
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1941
        goto cleanup;
1942 1943 1944
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1945 1946
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1947
        goto cleanup;
1948 1949
    }

1950
    if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1951 1952
        esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
1953
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1954
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1955
        goto cleanup;
1956 1957 1958
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1959 1960
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1961
        goto cleanup;
1962 1963
    }

1964
    domain->id = -1;
M
Matthias Bolte 已提交
1965 1966
    result = 0;

1967 1968 1969 1970
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1971
    VIR_FREE(taskInfoErrorMessage);
1972 1973 1974 1975 1976

    return result;
}


1977 1978 1979 1980 1981 1982
static int
esxDomainDestroy(virDomainPtr dom)
{
    return esxDomainDestroyFlags(dom, 0);
}

1983 1984

static char *
1985
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
1986
{
1987
    char *osType;
1988

1989
    ignore_value(VIR_STRDUP(osType, "hvm"));
1990
    return osType;
1991 1992 1993 1994
}



1995
static unsigned long long
1996 1997
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1998
    esxPrivate *priv = domain->conn->privateData;
1999 2000 2001 2002 2003
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

2004
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2005
        return 0;
2006 2007
    }

2008
    if (esxVI_String_AppendValueToList(&propertyNameList,
2009
                                       "config.hardware.memoryMB") < 0 ||
2010
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2011
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2012
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2013
        goto cleanup;
2014 2015 2016 2017 2018
    }

    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2019
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2020
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2021
                goto cleanup;
2022 2023 2024
            }

            if (dynamicProperty->val->int32 < 0) {
2025 2026 2027
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Got invalid memory size %d"),
                               dynamicProperty->val->int32);
2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
            } else {
                memoryMB = dynamicProperty->val->int32;
            }

            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return memoryMB * 1024; /* Scale from megabyte to kilobyte */
}



static int
esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2050
    int result = -1;
M
Matthias Bolte 已提交
2051
    esxPrivate *priv = domain->conn->privateData;
2052
    esxVI_String *propertyNameList = NULL;
2053
    esxVI_ObjectContent *virtualMachine = NULL;
2054
    esxVI_VirtualMachinePowerState powerState;
2055 2056 2057
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2058
    char *taskInfoErrorMessage = NULL;
2059

2060
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2061
        return -1;
2062 2063
    }

2064 2065 2066 2067
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2068
           priv->parsedUri->autoAnswer) < 0 ||
2069 2070 2071 2072 2073
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2074 2075
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
2076 2077 2078 2079
        goto cleanup;
    }

    if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
2080
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
2081
        goto cleanup;
2082 2083
    }

2084
    /* max-memory must be a multiple of 4096 kilobyte */
2085
    spec->memoryMB->value =
2086
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2087

2088
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2089
                              &task) < 0 ||
2090
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2091
                                    esxVI_Occurrence_RequiredItem,
2092
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2093
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2094
        goto cleanup;
2095 2096 2097
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2098 2099 2100
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set max-memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2101
        goto cleanup;
2102 2103
    }

M
Matthias Bolte 已提交
2104 2105
    result = 0;

2106
  cleanup:
2107
    esxVI_String_Free(&propertyNameList);
2108 2109 2110
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2111
    VIR_FREE(taskInfoErrorMessage);
2112 2113 2114 2115 2116 2117 2118 2119 2120

    return result;
}



static int
esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2121
    int result = -1;
M
Matthias Bolte 已提交
2122
    esxPrivate *priv = domain->conn->privateData;
2123 2124 2125 2126
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2127
    char *taskInfoErrorMessage = NULL;
2128

2129
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2130
        return -1;
2131 2132
    }

2133
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2134
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2135
           priv->parsedUri->autoAnswer) < 0 ||
2136 2137 2138
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
        esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
M
Matthias Bolte 已提交
2139
        goto cleanup;
2140 2141 2142
    }

    spec->memoryAllocation->limit->value =
2143
      VIR_DIV_UP(memory, 1024); /* Scale from kilobytes to megabytes */
2144

2145
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2146
                              &task) < 0 ||
2147
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2148
                                    esxVI_Occurrence_RequiredItem,
2149
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2150
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2151
        goto cleanup;
2152 2153 2154
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2155 2156 2157
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2158
        goto cleanup;
2159 2160
    }

M
Matthias Bolte 已提交
2161 2162
    result = 0;

2163 2164 2165 2166
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2167
    VIR_FREE(taskInfoErrorMessage);
2168 2169 2170 2171 2172 2173

    return result;
}



2174 2175 2176 2177 2178 2179 2180 2181 2182
/*
 * libvirt exposed virtual CPU usage in absolute time, ESX doesn't provide this
 * information in this format. It exposes it in 20 seconds slots, but it's hard
 * to get a reliable absolute time from this. Therefore, disable the code that
 * queries the performance counters here for now, but keep it as example for how
 * to query a selected performance counter for its values.
 */
#define ESX_QUERY_FOR_USED_CPU_TIME 0

2183 2184 2185
static int
esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
M
Matthias Bolte 已提交
2186
    int result = -1;
M
Matthias Bolte 已提交
2187
    esxPrivate *priv = domain->conn->privateData;
2188 2189 2190 2191 2192
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int64_t memory_limit = -1;
2193
#if ESX_QUERY_FOR_USED_CPU_TIME
2194 2195 2196 2197 2198 2199 2200
    esxVI_PerfMetricId *perfMetricId = NULL;
    esxVI_PerfMetricId *perfMetricIdList = NULL;
    esxVI_Int *counterId = NULL;
    esxVI_Int *counterIdList = NULL;
    esxVI_PerfCounterInfo *perfCounterInfo = NULL;
    esxVI_PerfCounterInfo *perfCounterInfoList = NULL;
    esxVI_PerfQuerySpec *querySpec = NULL;
2201 2202
    esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
    esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2203 2204 2205
    esxVI_PerfEntityMetric *perfEntityMetric = NULL;
    esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
    esxVI_Long *value = NULL;
2206
#endif
2207

2208
    memset(info, 0, sizeof(*info));
M
Matthias Bolte 已提交
2209

2210
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2211
        return -1;
2212 2213
    }

2214
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2215 2216 2217 2218
                                           "runtime.powerState\0"
                                           "config.hardware.memoryMB\0"
                                           "config.hardware.numCPU\0"
                                           "config.memoryAllocation.limit\0") < 0 ||
2219
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2220
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2221
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2222
        goto cleanup;
2223 2224 2225 2226 2227 2228 2229 2230
    }

    info->state = VIR_DOMAIN_NOSTATE;

    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.powerState")) {
            if (esxVI_VirtualMachinePowerState_CastFromAnyType
2231
                  (dynamicProperty->val, &powerState) < 0) {
M
Matthias Bolte 已提交
2232
                goto cleanup;
2233 2234
            }

2235 2236
            info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                            (powerState);
2237
        } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2238
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2239
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2240
                goto cleanup;
2241 2242 2243 2244
            }

            info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
        } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2245
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2246
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2247
                goto cleanup;
2248 2249 2250 2251 2252
            }

            info->nrVirtCpu = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "config.memoryAllocation.limit")) {
2253
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2254
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
2255
                goto cleanup;
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
            }

            memory_limit = dynamicProperty->val->int64;

            if (memory_limit > 0) {
                memory_limit *= 1024; /* Scale from megabyte to kilobyte */
            }
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    /* memory_limit < 0 means no memory limit is set */
    info->memory = memory_limit < 0 ? info->maxMem : memory_limit;

2271
#if ESX_QUERY_FOR_USED_CPU_TIME
2272
    /* Verify the cached 'used CPU time' performance counter ID */
2273 2274 2275 2276 2277 2278
    /* FIXME: Currently no host for a vpx:// connection */
    if (priv->host != NULL) {
        if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
            if (esxVI_Int_Alloc(&counterId) < 0) {
                goto cleanup;
            }
2279

2280
            counterId->value = priv->usedCpuTimeCounterId;
2281

2282 2283 2284
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                goto cleanup;
            }
2285

2286 2287 2288 2289
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2290

2291 2292 2293 2294 2295
            if (STRNEQ(perfCounterInfo->groupInfo->key, "cpu") ||
                STRNEQ(perfCounterInfo->nameInfo->key, "used") ||
                STRNEQ(perfCounterInfo->unitInfo->key, "millisecond")) {
                VIR_DEBUG("Cached usedCpuTimeCounterId %d is invalid",
                          priv->usedCpuTimeCounterId);
2296

2297 2298 2299 2300 2301
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2302 2303
        }

2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
        /*
         * Query the PerformanceManager for the 'used CPU time' performance
         * counter ID and cache it, if it's not already cached.
         */
        if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId < 0) {
            if (esxVI_QueryAvailablePerfMetric(priv->host, virtualMachine->obj,
                                               NULL, NULL, NULL,
                                               &perfMetricIdList) < 0) {
                goto cleanup;
            }
2314

2315 2316 2317 2318
            for (perfMetricId = perfMetricIdList; perfMetricId != NULL;
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2319

2320
                counterId = NULL;
2321

2322 2323 2324 2325 2326
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2327

2328 2329
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2330
                goto cleanup;
2331 2332
            }

2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
            for (perfCounterInfo = perfCounterInfoList; perfCounterInfo != NULL;
                 perfCounterInfo = perfCounterInfo->_next) {
                VIR_DEBUG("perfCounterInfo key %d, nameInfo '%s', groupInfo '%s', "
                          "unitInfo '%s', rollupType %d, statsType %d",
                          perfCounterInfo->key->value,
                          perfCounterInfo->nameInfo->key,
                          perfCounterInfo->groupInfo->key,
                          perfCounterInfo->unitInfo->key,
                          perfCounterInfo->rollupType,
                          perfCounterInfo->statsType);

                if (STREQ(perfCounterInfo->groupInfo->key, "cpu") &&
                    STREQ(perfCounterInfo->nameInfo->key, "used") &&
                    STREQ(perfCounterInfo->unitInfo->key, "millisecond")) {
                    priv->usedCpuTimeCounterId = perfCounterInfo->key->value;
                    break;
                }
2350 2351
            }

2352
            if (priv->usedCpuTimeCounterId < 0) {
2353
                VIR_WARN("Could not find 'used CPU time' performance counter");
2354
            }
2355 2356
        }

2357 2358 2359 2360 2361 2362
        /*
         * Query the PerformanceManager for the 'used CPU time' performance
         * counter value.
         */
        if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
            VIR_DEBUG("usedCpuTimeCounterId %d BEGIN", priv->usedCpuTimeCounterId);
2363

2364 2365 2366 2367 2368 2369
            if (esxVI_PerfQuerySpec_Alloc(&querySpec) < 0 ||
                esxVI_Int_Alloc(&querySpec->maxSample) < 0 ||
                esxVI_PerfMetricId_Alloc(&querySpec->metricId) < 0 ||
                esxVI_Int_Alloc(&querySpec->metricId->counterId) < 0) {
                goto cleanup;
            }
2370

2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
            querySpec->entity = virtualMachine->obj;
            querySpec->maxSample->value = 1;
            querySpec->metricId->counterId->value = priv->usedCpuTimeCounterId;
            querySpec->metricId->instance = (char *)"";
            querySpec->format = (char *)"normal";

            if (esxVI_QueryPerf(priv->host, querySpec,
                                &perfEntityMetricBaseList) < 0) {
                goto cleanup;
            }
2381

2382 2383 2384
            for (perfEntityMetricBase = perfEntityMetricBaseList;
                 perfEntityMetricBase != NULL;
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2385
                VIR_DEBUG("perfEntityMetric ...");
2386

2387 2388
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2389

2390
                if (perfEntityMetric == NULL) {
2391 2392 2393
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetricBase->_type));
2394
                    goto cleanup;
2395
                }
2396

2397 2398
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2399

2400
                if (perfMetricIntSeries == NULL) {
2401 2402 2403
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetric->value->_type));
2404
                    goto cleanup;
2405
                }
2406

2407 2408
                for (; perfMetricIntSeries != NULL;
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2409
                    VIR_DEBUG("perfMetricIntSeries ...");
2410

2411 2412 2413 2414 2415
                    for (value = perfMetricIntSeries->value;
                         value != NULL;
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2416 2417 2418
                }
            }

2419
            VIR_DEBUG("usedCpuTimeCounterId %d END", priv->usedCpuTimeCounterId);
M
Matthias Bolte 已提交
2420

2421
            /*
E
Eric Blake 已提交
2422
             * FIXME: Cannot map between relative used-cpu-time and absolute
2423 2424 2425
             *        info->cpuTime
             */
        }
2426
    }
2427
#endif
2428

M
Matthias Bolte 已提交
2429 2430
    result = 0;

2431
  cleanup:
2432
#if ESX_QUERY_FOR_USED_CPU_TIME
2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
    /*
     * Remove values owned by data structures to prevent them from being freed
     * by the call to esxVI_PerfQuerySpec_Free().
     */
    if (querySpec != NULL) {
        querySpec->entity = NULL;
        querySpec->format = NULL;

        if (querySpec->metricId != NULL) {
            querySpec->metricId->instance = NULL;
        }
    }
2445
#endif
2446

2447 2448
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2449
#if ESX_QUERY_FOR_USED_CPU_TIME
2450 2451 2452 2453
    esxVI_PerfMetricId_Free(&perfMetricIdList);
    esxVI_Int_Free(&counterIdList);
    esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
    esxVI_PerfQuerySpec_Free(&querySpec);
2454
    esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2455
#endif
2456 2457 2458 2459 2460 2461

    return result;
}



2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
static int
esxDomainGetState(virDomainPtr domain,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;

    virCheckFlags(0, -1);

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         propertyNameList, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState);

    if (reason)
        *reason = 0;

    result = 0;

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
}



2505
static int
2506 2507
esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                       unsigned int flags)
2508
{
M
Matthias Bolte 已提交
2509
    int result = -1;
M
Matthias Bolte 已提交
2510
    esxPrivate *priv = domain->conn->privateData;
M
Matthias Bolte 已提交
2511
    int maxVcpus;
2512 2513 2514 2515
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2516
    char *taskInfoErrorMessage = NULL;
2517

2518
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2519
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2520 2521 2522
        return -1;
    }

2523
    if (nvcpus < 1) {
2524 2525
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2526
        return -1;
2527 2528
    }

2529
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2530
        return -1;
2531 2532
    }

M
Matthias Bolte 已提交
2533
    maxVcpus = esxDomainGetMaxVcpus(domain);
2534

M
Matthias Bolte 已提交
2535
    if (maxVcpus < 0) {
M
Matthias Bolte 已提交
2536
        return -1;
2537 2538
    }

M
Matthias Bolte 已提交
2539
    if (nvcpus > maxVcpus) {
2540 2541 2542 2543
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Requested number of virtual CPUs is greater than max "
                         "allowable number of virtual CPUs for the domain: %d > %d"),
                       nvcpus, maxVcpus);
M
Matthias Bolte 已提交
2544
        return -1;
2545 2546
    }

2547
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2548
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2549
           priv->parsedUri->autoAnswer) < 0 ||
2550 2551
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_Int_Alloc(&spec->numCPUs) < 0) {
M
Matthias Bolte 已提交
2552
        goto cleanup;
2553 2554 2555 2556
    }

    spec->numCPUs->value = nvcpus;

2557
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2558
                              &task) < 0 ||
2559
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2560
                                    esxVI_Occurrence_RequiredItem,
2561
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2562
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2563
        goto cleanup;
2564 2565 2566
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2567 2568 2569
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2570
        goto cleanup;
2571 2572
    }

M
Matthias Bolte 已提交
2573 2574
    result = 0;

2575 2576 2577 2578
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2579
    VIR_FREE(taskInfoErrorMessage);
2580 2581 2582 2583 2584

    return result;
}


M
Matthias Bolte 已提交
2585

2586 2587 2588
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
2589
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2590 2591
}

2592

M
Matthias Bolte 已提交
2593

2594
static int
2595
esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2596
{
M
Matthias Bolte 已提交
2597
    esxPrivate *priv = domain->conn->privateData;
2598 2599 2600 2601
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

2602
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2603
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2604 2605 2606
        return -1;
    }

M
Matthias Bolte 已提交
2607 2608
    if (priv->maxVcpus > 0) {
        return priv->maxVcpus;
2609 2610
    }

M
Matthias Bolte 已提交
2611 2612
    priv->maxVcpus = -1;

2613
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2614
        return -1;
2615 2616
    }

2617
    if (esxVI_String_AppendValueToList(&propertyNameList,
2618
                                       "capability.maxSupportedVcpus") < 0 ||
2619 2620
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
2621
        goto cleanup;
2622 2623 2624 2625 2626
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2627
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2628
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2629
                goto cleanup;
2630 2631
            }

M
Matthias Bolte 已提交
2632
            priv->maxVcpus = dynamicProperty->val->int32;
2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
2643
    return priv->maxVcpus;
2644 2645
}

M
Matthias Bolte 已提交
2646 2647


2648 2649 2650
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
2651
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2652 2653
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2654

M
Matthias Bolte 已提交
2655 2656


2657
static char *
2658
esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2659
{
M
Matthias Bolte 已提交
2660
    esxPrivate *priv = domain->conn->privateData;
2661 2662
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2663 2664
    esxVI_VirtualMachinePowerState powerState;
    int id;
2665
    char *vmPathName = NULL;
2666
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2667
    char *directoryName = NULL;
2668
    char *directoryAndFileName = NULL;
2669
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2670 2671
    char *url = NULL;
    char *vmx = NULL;
2672
    virVMXContext ctx;
2673
    esxVMX_Data data;
2674 2675 2676
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2677 2678
    /* Flags checked by virDomainDefFormat */

2679
    memset(&data, 0, sizeof(data));
2680

2681
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2682
        return NULL;
2683 2684
    }

2685 2686 2687
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "config.files.vmPathName\0"
                                           "runtime.powerState\0") < 0 ||
2688
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2689
                                         propertyNameList, &virtualMachine,
2690
                                         esxVI_Occurrence_RequiredItem) < 0 ||
2691 2692
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2693 2694
        esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
                             &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2695
        goto cleanup;
2696 2697
    }

2698
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2699
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2700
        goto cleanup;
2701 2702
    }

2703
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2704
                      domain->conn->uri->server, domain->conn->uri->port);
2705
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2706
    virBufferAddLit(&buffer, "?dcPath=");
2707
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
2708 2709 2710 2711
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
2712
        virReportOOMError();
M
Matthias Bolte 已提交
2713
        goto cleanup;
2714 2715
    }

2716 2717
    url = virBufferContentAndReset(&buffer);

2718
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx, 0, NULL) < 0) {
M
Matthias Bolte 已提交
2719
        goto cleanup;
2720 2721
    }

2722
    data.ctx = priv->primary;
2723 2724 2725

    if (directoryName == NULL) {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s]",
2726
                        datastoreName) < 0)
2727 2728 2729
            goto cleanup;
    } else {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s] %s",
2730
                        datastoreName, directoryName) < 0)
2731 2732
            goto cleanup;
    }
2733 2734 2735 2736 2737 2738

    ctx.opaque = &data;
    ctx.parseFileName = esxParseVMXFileName;
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;

2739
    def = virVMXParseConfig(&ctx, priv->xmlopt, vmx);
2740 2741

    if (def != NULL) {
2742 2743 2744 2745
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
            def->id = id;
        }

2746
        xml = virDomainDefFormat(def, flags);
2747 2748 2749
    }

  cleanup:
M
Matthias Bolte 已提交
2750 2751 2752 2753
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

2754 2755
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2756
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2757
    VIR_FREE(directoryName);
2758
    VIR_FREE(directoryAndFileName);
2759
    VIR_FREE(url);
2760
    VIR_FREE(data.datastorePathWithoutFileName);
2761
    VIR_FREE(vmx);
2762
    virDomainDefFree(def);
2763 2764 2765 2766 2767 2768 2769

    return xml;
}



static char *
2770 2771 2772
esxConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                              const char *nativeConfig,
                              unsigned int flags)
2773
{
M
Matthias Bolte 已提交
2774
    esxPrivate *priv = conn->privateData;
2775
    virVMXContext ctx;
2776
    esxVMX_Data data;
2777 2778 2779
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2780 2781
    virCheckFlags(0, NULL);

2782
    memset(&data, 0, sizeof(data));
2783

2784
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2785 2786
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
2787
        return NULL;
2788 2789
    }

2790
    data.ctx = priv->primary;
2791
    data.datastorePathWithoutFileName = (char *)"[?] ?";
2792 2793 2794 2795 2796 2797

    ctx.opaque = &data;
    ctx.parseFileName = esxParseVMXFileName;
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;

2798
    def = virVMXParseConfig(&ctx, priv->xmlopt, nativeConfig);
2799 2800

    if (def != NULL) {
2801
        xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
2802 2803 2804 2805 2806 2807 2808 2809 2810
    }

    virDomainDefFree(def);

    return xml;
}



M
Matthias Bolte 已提交
2811
static char *
2812 2813 2814
esxConnectDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                            const char *domainXml,
                            unsigned int flags)
M
Matthias Bolte 已提交
2815
{
M
Matthias Bolte 已提交
2816
    esxPrivate *priv = conn->privateData;
2817 2818
    int virtualHW_version;
    virVMXContext ctx;
2819
    esxVMX_Data data;
M
Matthias Bolte 已提交
2820 2821 2822
    virDomainDefPtr def = NULL;
    char *vmx = NULL;

E
Eric Blake 已提交
2823 2824
    virCheckFlags(0, NULL);

2825
    memset(&data, 0, sizeof(data));
2826

M
Matthias Bolte 已提交
2827
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2828 2829
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
M
Matthias Bolte 已提交
2830 2831 2832
        return NULL;
    }

2833 2834 2835 2836 2837 2838 2839
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        return NULL;
    }

2840 2841
    def = virDomainDefParseString(domainXml, priv->caps, priv->xmlopt,
                                  1 << VIR_DOMAIN_VIRT_VMWARE, 0);
M
Matthias Bolte 已提交
2842 2843 2844 2845 2846

    if (def == NULL) {
        return NULL;
    }

2847
    data.ctx = priv->primary;
2848
    data.datastorePathWithoutFileName = NULL;
2849 2850 2851 2852 2853 2854

    ctx.opaque = &data;
    ctx.parseFileName = NULL;
    ctx.formatFileName = esxFormatVMXFileName;
    ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;

2855
    vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
M
Matthias Bolte 已提交
2856 2857 2858 2859 2860 2861 2862 2863

    virDomainDefFree(def);

    return vmx;
}



2864
static int
2865
esxConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
2866
{
M
Matthias Bolte 已提交
2867
    bool success = false;
M
Matthias Bolte 已提交
2868
    esxPrivate *priv = conn->privateData;
2869 2870 2871 2872 2873
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;
2874
    size_t i;
2875 2876 2877 2878 2879

    if (maxnames == 0) {
        return 0;
    }

2880
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2881
        return -1;
2882 2883
    }

2884
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2885 2886
                                           "name\0"
                                           "runtime.powerState\0") < 0 ||
2887 2888
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
2889
        goto cleanup;
2890 2891 2892 2893
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
2894
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2895
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
2896
            goto cleanup;
2897 2898 2899 2900 2901 2902
        }

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2903
        names[count] = NULL;
2904

2905 2906 2907
        if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
                                            NULL) < 0) {
            goto cleanup;
2908 2909
        }

2910 2911
        ++count;

2912 2913 2914 2915 2916
        if (count >= maxnames) {
            break;
        }
    }

M
Matthias Bolte 已提交
2917
    success = true;
2918

M
Matthias Bolte 已提交
2919 2920 2921 2922 2923
  cleanup:
    if (! success) {
        for (i = 0; i < count; ++i) {
            VIR_FREE(names[i]);
        }
2924

M
Matthias Bolte 已提交
2925
        count = -1;
2926 2927
    }

M
Matthias Bolte 已提交
2928 2929
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2930

M
Matthias Bolte 已提交
2931
    return count;
2932 2933 2934 2935 2936
}



static int
2937
esxConnectNumOfDefinedDomains(virConnectPtr conn)
2938
{
M
Matthias Bolte 已提交
2939
    esxPrivate *priv = conn->privateData;
2940

2941
    if (esxVI_EnsureSession(priv->primary) < 0) {
2942 2943 2944
        return -1;
    }

2945
    return esxVI_LookupNumberOfDomainsByPowerState
2946
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
2947 2948 2949 2950 2951
}



static int
2952
esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
2953
{
M
Matthias Bolte 已提交
2954
    int result = -1;
M
Matthias Bolte 已提交
2955
    esxPrivate *priv = domain->conn->privateData;
2956 2957 2958
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
2959
    int id = -1;
2960 2961
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2962
    char *taskInfoErrorMessage = NULL;
2963

2964 2965
    virCheckFlags(0, -1);

2966
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2967
        return -1;
2968 2969
    }

2970
    if (esxVI_String_AppendValueToList(&propertyNameList,
2971
                                       "runtime.powerState") < 0 ||
2972
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2973
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2974
           priv->parsedUri->autoAnswer) < 0 ||
2975 2976
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
M
Matthias Bolte 已提交
2977
        goto cleanup;
2978 2979 2980
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2981 2982
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
M
Matthias Bolte 已提交
2983
        goto cleanup;
2984 2985
    }

2986
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
2987
                             &task) < 0 ||
2988
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2989
                                    esxVI_Occurrence_RequiredItem,
2990
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2991
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2992
        goto cleanup;
2993 2994 2995
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2996 2997
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2998
        goto cleanup;
2999 3000
    }

3001
    domain->id = id;
M
Matthias Bolte 已提交
3002 3003
    result = 0;

3004 3005 3006 3007
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
3008
    VIR_FREE(taskInfoErrorMessage);
3009 3010 3011 3012

    return result;
}

3013 3014


3015 3016 3017 3018 3019
static int
esxDomainCreate(virDomainPtr domain)
{
    return esxDomainCreateWithFlags(domain, 0);
}
3020

3021 3022


M
Matthias Bolte 已提交
3023
static virDomainPtr
3024
esxDomainDefineXML(virConnectPtr conn, const char *xml)
M
Matthias Bolte 已提交
3025
{
M
Matthias Bolte 已提交
3026
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3027 3028
    virDomainDefPtr def = NULL;
    char *vmx = NULL;
3029
    size_t i;
3030
    virDomainDiskDefPtr disk = NULL;
M
Matthias Bolte 已提交
3031
    esxVI_ObjectContent *virtualMachine = NULL;
3032 3033
    int virtualHW_version;
    virVMXContext ctx;
3034
    esxVMX_Data data;
M
Matthias Bolte 已提交
3035 3036
    char *datastoreName = NULL;
    char *directoryName = NULL;
3037
    char *escapedName = NULL;
M
Matthias Bolte 已提交
3038 3039 3040 3041 3042 3043 3044 3045
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *url = NULL;
    char *datastoreRelatedPath = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_ManagedObjectReference *resourcePool = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3046
    char *taskInfoErrorMessage = NULL;
M
Matthias Bolte 已提交
3047 3048
    virDomainPtr domain = NULL;

3049
    memset(&data, 0, sizeof(data));
3050

3051
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3052
        return NULL;
M
Matthias Bolte 已提交
3053 3054 3055
    }

    /* Parse domain XML */
3056 3057
    def = virDomainDefParseString(xml, priv->caps, priv->xmlopt,
                                  1 << VIR_DOMAIN_VIRT_VMWARE,
M
Matthias Bolte 已提交
3058 3059 3060
                                  VIR_DOMAIN_XML_INACTIVE);

    if (def == NULL) {
M
Matthias Bolte 已提交
3061
        return NULL;
M
Matthias Bolte 已提交
3062 3063 3064
    }

    /* Check if an existing domain should be edited */
3065
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3066
                                         &virtualMachine,
M
Matthias Bolte 已提交
3067
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3068
        goto cleanup;
M
Matthias Bolte 已提交
3069 3070
    }

3071 3072 3073 3074 3075 3076 3077
    if (virtualMachine == NULL &&
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

M
Matthias Bolte 已提交
3078 3079
    if (virtualMachine != NULL) {
        /* FIXME */
3080 3081 3082
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain already exists, editing existing domains is not "
                         "supported yet"));
M
Matthias Bolte 已提交
3083
        goto cleanup;
M
Matthias Bolte 已提交
3084 3085 3086
    }

    /* Build VMX from domain XML */
3087 3088 3089 3090 3091 3092 3093
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        goto cleanup;
    }

3094
    data.ctx = priv->primary;
3095
    data.datastorePathWithoutFileName = NULL;
3096 3097 3098 3099 3100 3101

    ctx.opaque = &data;
    ctx.parseFileName = NULL;
    ctx.formatFileName = esxFormatVMXFileName;
    ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;

3102
    vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
M
Matthias Bolte 已提交
3103 3104

    if (vmx == NULL) {
M
Matthias Bolte 已提交
3105
        goto cleanup;
M
Matthias Bolte 已提交
3106 3107
    }

3108 3109 3110 3111 3112 3113 3114
    /*
     * Build VMX datastore URL. Use the source of the first file-based harddisk
     * to deduce the datastore and path for the VMX file. Don't just use the
     * first disk, because it may be CDROM disk and ISO images are normaly not
     * located in the virtual machine's directory. This approach to deduce the
     * datastore isn't perfect but should work in the majority of cases.
     */
M
Matthias Bolte 已提交
3115
    if (def->ndisks < 1) {
3116 3117 3118
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any disks, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3119
        goto cleanup;
3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130
    }

    for (i = 0; i < def->ndisks; ++i) {
        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
            def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) {
            disk = def->disks[i];
            break;
        }
    }

    if (disk == NULL) {
3131 3132 3133
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any file-based harddisks, "
                         "cannot deduce datastore and path for VMX file"));
M
Matthias Bolte 已提交
3134
        goto cleanup;
M
Matthias Bolte 已提交
3135 3136
    }

3137
    if (disk->src == NULL) {
3138 3139 3140
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("First file-based harddisk has no source, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3141
        goto cleanup;
M
Matthias Bolte 已提交
3142 3143
    }

3144
    if (esxUtil_ParseDatastorePath(disk->src, &datastoreName, &directoryName,
3145
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3146
        goto cleanup;
M
Matthias Bolte 已提交
3147 3148
    }

3149
    if (! virFileHasSuffix(disk->src, ".vmdk")) {
3150 3151 3152
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting source '%s' of first file-based harddisk to "
                         "be a VMDK image"), disk->src);
M
Matthias Bolte 已提交
3153
        goto cleanup;
M
Matthias Bolte 已提交
3154 3155
    }

3156
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3157 3158 3159 3160 3161 3162 3163
                      conn->uri->server, conn->uri->port);

    if (directoryName != NULL) {
        virBufferURIEncodeString(&buffer, directoryName);
        virBufferAddChar(&buffer, '/');
    }

3164 3165 3166 3167 3168 3169 3170
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

    if (escapedName == NULL) {
        goto cleanup;
    }

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3171
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3172
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
M
Matthias Bolte 已提交
3173 3174 3175 3176
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
3177
        virReportOOMError();
M
Matthias Bolte 已提交
3178
        goto cleanup;
M
Matthias Bolte 已提交
3179 3180 3181 3182
    }

    url = virBufferContentAndReset(&buffer);

3183 3184 3185 3186 3187 3188
    /* Check, if VMX file already exists */
    /* FIXME */

    /* Upload VMX file */
    VIR_DEBUG("Uploading .vmx config, url='%s' vmx='%s'", url, vmx);

3189
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0) {
3190 3191 3192 3193
        goto cleanup;
    }

    /* Register the domain */
M
Matthias Bolte 已提交
3194 3195
    if (directoryName != NULL) {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s/%s.vmx", datastoreName,
3196
                        directoryName, escapedName) < 0)
M
Matthias Bolte 已提交
3197
            goto cleanup;
M
Matthias Bolte 已提交
3198 3199
    } else {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s.vmx", datastoreName,
3200
                        escapedName) < 0)
M
Matthias Bolte 已提交
3201
            goto cleanup;
M
Matthias Bolte 已提交
3202 3203
    }

3204
    if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
M
Matthias Bolte 已提交
3205
                              datastoreRelatedPath, NULL, esxVI_Boolean_False,
3206 3207 3208 3209
                              priv->primary->computeResource->resourcePool,
                              priv->primary->hostSystem->_reference,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3210
                                    esxVI_Occurrence_OptionalItem,
3211
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3212
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3213
        goto cleanup;
M
Matthias Bolte 已提交
3214 3215 3216
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3217 3218
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3219
        goto cleanup;
M
Matthias Bolte 已提交
3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230
    }

    domain = virGetDomain(conn, def->name, def->uuid);

    if (domain != NULL) {
        domain->id = -1;
    }

    /* FIXME: Add proper rollback in case of an error */

  cleanup:
M
Matthias Bolte 已提交
3231 3232 3233 3234
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

M
Matthias Bolte 已提交
3235 3236 3237 3238
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3239
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3240 3241 3242 3243 3244 3245 3246
    VIR_FREE(url);
    VIR_FREE(datastoreRelatedPath);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);
    esxVI_ManagedObjectReference_Free(&resourcePool);
    esxVI_ManagedObjectReference_Free(&task);
3247
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3248 3249 3250 3251 3252 3253

    return domain;
}



3254
static int
3255 3256
esxDomainUndefineFlags(virDomainPtr domain,
                       unsigned int flags)
3257
{
M
Matthias Bolte 已提交
3258
    int result = -1;
M
Matthias Bolte 已提交
3259
    esxPrivate *priv = domain->conn->privateData;
3260
    esxVI_Context *ctx = NULL;
3261 3262 3263 3264
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3265 3266 3267 3268
    /* No managed save, so we explicitly reject
     * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
     * ESX, so we can trivially ignore that flag.  */
    virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
3269

3270 3271 3272 3273 3274 3275
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3276
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
3277
        return -1;
3278 3279
    }

3280
    if (esxVI_String_AppendValueToList(&propertyNameList,
3281
                                       "runtime.powerState") < 0 ||
3282 3283
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3284
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3285
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3286
        goto cleanup;
3287 3288 3289 3290
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3291 3292
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3293
        goto cleanup;
3294 3295
    }

3296
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
3297
        goto cleanup;
3298 3299
    }

M
Matthias Bolte 已提交
3300 3301
    result = 0;

3302 3303 3304 3305 3306 3307 3308 3309
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


3310 3311 3312 3313 3314
static int
esxDomainUndefine(virDomainPtr domain)
{
    return esxDomainUndefineFlags(domain, 0);
}
3315

3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395
static int
esxDomainGetAutostart(virDomainPtr domain, int *autostart)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_AutoStartDefaults *defaults = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;

    *autostart = 0;

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    /* Check general autostart config */
    if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0) {
        goto cleanup;
    }

    if (defaults->enabled != esxVI_Boolean_True) {
        /* Autostart is disabled in general, exit early here */
        result = 0;
        goto cleanup;
    }

    /* Check specific autostart config */
    if (esxVI_LookupAutoStartPowerInfoList(priv->primary, &powerInfoList) < 0) {
        goto cleanup;
    }

    if (powerInfoList == NULL) {
        /* powerInfo list is empty, exit early here */
        result = 0;
        goto cleanup;
    }

    if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         NULL, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    for (powerInfo = powerInfoList; powerInfo != NULL;
         powerInfo = powerInfo->_next) {
        if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
            if (STRCASEEQ(powerInfo->startAction, "powerOn")) {
                *autostart = 1;
            }

            break;
        }
    }

    result = 0;

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_AutoStartDefaults_Free(&defaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
}



static int
esxDomainSetAutostart(virDomainPtr domain, int autostart)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_HostAutoStartManagerConfig *spec = NULL;
    esxVI_AutoStartDefaults *defaults = NULL;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_AutoStartPowerInfo *newPowerInfo = NULL;
3396
    bool newPowerInfo_isAppended = false;
3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         NULL, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_HostAutoStartManagerConfig_Alloc(&spec) < 0) {
        goto cleanup;
    }

    if (autostart) {
        /*
         * There is a general autostart option that affects the autostart
         * behavior of all domains. If it's disabled then no domain does
         * autostart. If it's enabled then the autostart behavior depends on
         * the per-domain autostart config.
         */
        if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0) {
            goto cleanup;
        }

        if (defaults->enabled != esxVI_Boolean_True) {
            /*
             * Autostart is disabled in general. Check if no other domain is
             * in the list of autostarted domains, so it's safe to enable the
             * general autostart option without affecting the autostart
             * behavior of other domains.
             */
            if (esxVI_LookupAutoStartPowerInfoList(priv->primary,
                                                   &powerInfoList) < 0) {
                goto cleanup;
            }

            for (powerInfo = powerInfoList; powerInfo != NULL;
                 powerInfo = powerInfo->_next) {
                if (STRNEQ(powerInfo->key->value, virtualMachine->obj->value)) {
3435 3436 3437
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("Cannot enable general autostart option "
                                     "without affecting other domains"));
3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453
                    goto cleanup;
                }
            }

            /* Enable autostart in general */
            if (esxVI_AutoStartDefaults_Alloc(&spec->defaults) < 0) {
                goto cleanup;
            }

            spec->defaults->enabled = esxVI_Boolean_True;
        }
    }

    if (esxVI_AutoStartPowerInfo_Alloc(&newPowerInfo) < 0 ||
        esxVI_Int_Alloc(&newPowerInfo->startOrder) < 0 ||
        esxVI_Int_Alloc(&newPowerInfo->startDelay) < 0 ||
3454
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0) {
3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465
        goto cleanup;
    }

    newPowerInfo->key = virtualMachine->obj;
    newPowerInfo->startOrder->value = -1; /* no specific start order */
    newPowerInfo->startDelay->value = -1; /* use system default */
    newPowerInfo->waitForHeartbeat = esxVI_AutoStartWaitHeartbeatSetting_SystemDefault;
    newPowerInfo->startAction = autostart ? (char *)"powerOn" : (char *)"none";
    newPowerInfo->stopDelay->value = -1; /* use system default */
    newPowerInfo->stopAction = (char *)"none";

3466 3467 3468 3469 3470 3471 3472
    if (esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
                                              newPowerInfo) < 0) {
        goto cleanup;
    }

    newPowerInfo_isAppended = true;

3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493
    if (esxVI_ReconfigureAutostart
          (priv->primary,
           priv->primary->hostSystem->configManager->autoStartManager,
           spec) < 0) {
        goto cleanup;
    }

    result = 0;

  cleanup:
    if (newPowerInfo != NULL) {
        newPowerInfo->key = NULL;
        newPowerInfo->startAction = NULL;
        newPowerInfo->stopAction = NULL;
    }

    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_HostAutoStartManagerConfig_Free(&spec);
    esxVI_AutoStartDefaults_Free(&defaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);

3494 3495 3496 3497
    if (!newPowerInfo_isAppended) {
        esxVI_AutoStartPowerInfo_Free(&newPowerInfo);
    }

3498 3499 3500 3501 3502
    return result;
}



3503 3504 3505 3506 3507 3508 3509 3510 3511 3512
/*
 * The scheduler interface exposes basically the CPU ResourceAllocationInfo:
 *
 * - http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.ResourceAllocationInfo.html
 * - http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.SharesInfo.html
 * - http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.SharesInfo.Level.html
 *
 *
 * Available parameters:
 *
3513
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3514
 *
3515
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3516 3517
 *
 *
3518
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3519
 *
3520 3521
 *   The CPU utilization of the domain will be limited to this value, even if
 *   more CPU resources are available. If the limit is set to -1, the CPU
3522 3523 3524 3525
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3526
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3527 3528 3529 3530 3531 3532
 *
 *   Shares are used to determine relative CPU allocation between domains. In
 *   general, a domain with more shares gets proportionally more of the CPU
 *   resource. The special values -1, -2 and -3 represent the predefined
 *   SharesLevel 'low', 'normal' and 'high'.
 */
3533
static char *
3534
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3535
{
3536
    char *type;
3537

3538
    if (VIR_STRDUP(type, "allocation") < 0)
3539
        return NULL;
3540

3541 3542 3543
    if (nparams != NULL) {
        *nparams = 3; /* reservation, limit, shares */
    }
3544 3545 3546 3547 3548 3549 3550

    return type;
}



static int
3551 3552 3553
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int *nparams,
                                     unsigned int flags)
3554
{
M
Matthias Bolte 已提交
3555
    int result = -1;
M
Matthias Bolte 已提交
3556
    esxPrivate *priv = domain->conn->privateData;
3557 3558 3559 3560 3561
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    unsigned int mask = 0;
3562
    size_t i = 0;
3563

3564 3565
    virCheckFlags(0, -1);

3566
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3567
        return -1;
3568 3569
    }

3570
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3571 3572 3573
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3574
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3575
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3576
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3577
        goto cleanup;
3578 3579 3580
    }

    for (dynamicProperty = virtualMachine->propSet;
3581
         dynamicProperty != NULL && mask != 7 && i < 3 && i < *nparams;
3582 3583
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
M
Matthias Bolte 已提交
3584
            ! (mask & (1 << 0))) {
3585
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3586
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3587
                goto cleanup;
3588
            }
3589 3590 3591 3592 3593
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_RESERVATION,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3594 3595 3596 3597
            mask |= 1 << 0;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.limit") &&
M
Matthias Bolte 已提交
3598
                   ! (mask & (1 << 1))) {
3599
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3600
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3601
                goto cleanup;
3602
            }
3603 3604 3605 3606 3607
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_LIMIT,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3608 3609 3610 3611
            mask |= 1 << 1;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.shares") &&
M
Matthias Bolte 已提交
3612
                   ! (mask & (1 << 2))) {
3613 3614 3615 3616
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_SHARES,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
                goto cleanup;
3617
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3618
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3619
                goto cleanup;
3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639
            }

            switch (sharesInfo->level) {
              case esxVI_SharesLevel_Custom:
                params[i].value.i = sharesInfo->shares->value;
                break;

              case esxVI_SharesLevel_Low:
                params[i].value.i = -1;
                break;

              case esxVI_SharesLevel_Normal:
                params[i].value.i = -2;
                break;

              case esxVI_SharesLevel_High:
                params[i].value.i = -3;
                break;

              default:
3640 3641 3642
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Shares level has unknown value %d"),
                               (int)sharesInfo->level);
M
Matthias Bolte 已提交
3643
                goto cleanup;
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655
            }

            esxVI_SharesInfo_Free(&sharesInfo);

            mask |= 1 << 2;
            ++i;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    *nparams = i;
M
Matthias Bolte 已提交
3656
    result = 0;
3657 3658 3659 3660 3661 3662 3663 3664

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
}

3665 3666 3667 3668 3669 3670
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3671 3672 3673


static int
3674 3675 3676
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3677
{
M
Matthias Bolte 已提交
3678
    int result = -1;
M
Matthias Bolte 已提交
3679
    esxPrivate *priv = domain->conn->privateData;
3680 3681 3682 3683 3684
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3685
    char *taskInfoErrorMessage = NULL;
3686
    size_t i;
3687

3688
    virCheckFlags(0, -1);
3689 3690 3691 3692 3693 3694 3695 3696
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_RESERVATION,
                               VIR_TYPED_PARAM_LLONG,
                               VIR_DOMAIN_SCHEDULER_LIMIT,
                               VIR_TYPED_PARAM_LLONG,
                               VIR_DOMAIN_SCHEDULER_SHARES,
                               VIR_TYPED_PARAM_INT,
                               NULL) < 0)
3697
        return -1;
3698

3699
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3700
        return -1;
3701 3702
    }

3703
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3704
          (priv->primary, domain->uuid, NULL, &virtualMachine,
3705
           priv->parsedUri->autoAnswer) < 0 ||
3706 3707
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
M
Matthias Bolte 已提交
3708
        goto cleanup;
3709 3710 3711
    }

    for (i = 0; i < nparams; ++i) {
3712
        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_RESERVATION)) {
3713
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0) {
M
Matthias Bolte 已提交
3714
                goto cleanup;
3715 3716 3717
            }

            if (params[i].value.l < 0) {
3718 3719 3720
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Could not set reservation to %lld MHz, expecting "
                                 "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3721
                goto cleanup;
3722 3723 3724
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
3725
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_LIMIT)) {
3726
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0) {
M
Matthias Bolte 已提交
3727
                goto cleanup;
3728 3729 3730
            }

            if (params[i].value.l < -1) {
3731 3732 3733 3734
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Could not set limit to %lld MHz, expecting "
                                 "positive value or -1 (unlimited)"),
                               params[i].value.l);
M
Matthias Bolte 已提交
3735
                goto cleanup;
3736 3737 3738
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
3739
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_SHARES)) {
3740 3741
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3742
                goto cleanup;
3743 3744 3745 3746
            }

            spec->cpuAllocation->shares = sharesInfo;

3747
            if (params[i].value.i >= 0) {
3748
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3749
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3750
            } else {
3751
                switch (params[i].value.i) {
3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769
                  case -1:
                    spec->cpuAllocation->shares->level = esxVI_SharesLevel_Low;
                    spec->cpuAllocation->shares->shares->value = -1;
                    break;

                  case -2:
                    spec->cpuAllocation->shares->level =
                      esxVI_SharesLevel_Normal;
                    spec->cpuAllocation->shares->shares->value = -1;
                    break;

                  case -3:
                    spec->cpuAllocation->shares->level =
                      esxVI_SharesLevel_High;
                    spec->cpuAllocation->shares->shares->value = -1;
                    break;

                  default:
3770 3771 3772 3773
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("Could not set shares to %d, expecting positive "
                                     "value or -1 (low), -2 (normal) or -3 (high)"),
                                   params[i].value.i);
M
Matthias Bolte 已提交
3774
                    goto cleanup;
3775 3776 3777 3778 3779
                }
            }
        }
    }

3780
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3781
                              &task) < 0 ||
3782
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3783
                                    esxVI_Occurrence_RequiredItem,
3784
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3785
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3786
        goto cleanup;
3787 3788 3789
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3790 3791 3792
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change scheduler parameters: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3793
        goto cleanup;
3794 3795
    }

M
Matthias Bolte 已提交
3796 3797
    result = 0;

3798 3799 3800 3801
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3802
    VIR_FREE(taskInfoErrorMessage);
3803 3804 3805 3806

    return result;
}

3807 3808 3809 3810 3811 3812
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3813

E
Eric Blake 已提交
3814 3815 3816 3817 3818 3819
/* The subset of migration flags we are able to support.  */
#define ESX_MIGRATION_FLAGS                     \
    (VIR_MIGRATE_PERSIST_DEST |                 \
     VIR_MIGRATE_UNDEFINE_SOURCE |              \
     VIR_MIGRATE_LIVE |                         \
     VIR_MIGRATE_PAUSED)
3820 3821 3822 3823 3824

static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3825 3826
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
E
Eric Blake 已提交
3827
                        unsigned long flags,
3828 3829 3830
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3831
    esxPrivate *priv = dconn->privateData;
3832

E
Eric Blake 已提交
3833 3834
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3835
    if (uri_in == NULL) {
3836 3837 3838
        if (virAsprintf(uri_out, "vpxmigr://%s/%s/%s",
                        priv->vCenter->ipAddress,
                        priv->vCenter->computeResource->resourcePool->value,
3839
                        priv->vCenter->hostSystem->_reference->value) < 0)
3840
            return -1;
3841 3842
    }

3843
    return 0;
3844 3845 3846 3847 3848 3849 3850 3851 3852
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
E
Eric Blake 已提交
3853
                        unsigned long flags,
3854 3855 3856
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3857
    int result = -1;
M
Matthias Bolte 已提交
3858
    esxPrivate *priv = domain->conn->privateData;
M
Martin Kletzander 已提交
3859
    virURIPtr parsedUri = NULL;
3860 3861 3862
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3863
    esxVI_ObjectContent *virtualMachine = NULL;
3864 3865
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3866 3867 3868
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3869
    char *taskInfoErrorMessage = NULL;
3870

E
Eric Blake 已提交
3871 3872
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

M
Matthias Bolte 已提交
3873
    if (priv->vCenter == NULL) {
3874 3875
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration not possible without a vCenter"));
M
Matthias Bolte 已提交
3876
        return -1;
3877 3878 3879
    }

    if (dname != NULL) {
3880 3881
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Renaming domains on migration not supported"));
M
Matthias Bolte 已提交
3882
        return -1;
3883 3884
    }

3885
    if (esxVI_EnsureSession(priv->vCenter) < 0) {
M
Matthias Bolte 已提交
3886
        return -1;
3887 3888
    }

3889
    /* Parse migration URI */
3890
    if (!(parsedUri = virURIParse(uri)))
M
Matthias Bolte 已提交
3891
        return -1;
3892

3893
    if (parsedUri->scheme == NULL || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
3894 3895
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3896
        goto cleanup;
3897 3898
    }

3899
    if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
3900 3901 3902
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration source and destination have to refer to "
                         "the same vCenter"));
3903 3904 3905 3906 3907 3908 3909
        goto cleanup;
    }

    path_resourcePool = strtok_r(parsedUri->path, "/", &saveptr);
    path_hostSystem = strtok_r(NULL, "", &saveptr);

    if (path_resourcePool == NULL || path_hostSystem == NULL) {
3910 3911
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration URI has to specify resource pool and host system"));
M
Matthias Bolte 已提交
3912
        goto cleanup;
3913 3914
    }

3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927
    resourcePool._next = NULL;
    resourcePool._type = esxVI_Type_ManagedObjectReference;
    resourcePool.type = (char *)"ResourcePool";
    resourcePool.value = path_resourcePool;

    hostSystem._next = NULL;
    hostSystem._type = esxVI_Type_ManagedObjectReference;
    hostSystem.type = (char *)"HostSystem";
    hostSystem.value = path_hostSystem;

    /* Lookup VirtualMachine */
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->vCenter, domain->uuid, NULL, &virtualMachine,
3928
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
3929
        goto cleanup;
3930 3931 3932
    }

    /* Validate the purposed migration */
3933
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3934 3935
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
3936
        goto cleanup;
3937 3938 3939 3940 3941 3942 3943 3944
    }

    if (eventList != NULL) {
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
        if (eventList->fullFormattedMessage != NULL) {
3945 3946 3947
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not migrate domain, validation reported a "
                             "problem: %s"), eventList->fullFormattedMessage);
3948
        } else {
3949 3950 3951
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not migrate domain, validation reported a "
                             "problem"));
3952 3953
        }

M
Matthias Bolte 已提交
3954
        goto cleanup;
3955 3956 3957
    }

    /* Perform the purposed migration */
3958 3959
    if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
                             &resourcePool, &hostSystem,
3960 3961 3962
                             esxVI_VirtualMachineMovePriority_DefaultPriority,
                             esxVI_VirtualMachinePowerState_Undefined,
                             &task) < 0 ||
3963
        esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
3964
                                    esxVI_Occurrence_RequiredItem,
3965
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3966
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3967
        goto cleanup;
3968 3969 3970
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3971 3972 3973 3974
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not migrate domain, migration task finished with "
                         "an error: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3975
        goto cleanup;
3976 3977
    }

M
Matthias Bolte 已提交
3978 3979
    result = 0;

3980
  cleanup:
3981
    virURIFree(parsedUri);
3982 3983 3984
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
3985
    VIR_FREE(taskInfoErrorMessage);
3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996

    return result;
}



static virDomainPtr
esxDomainMigrateFinish(virConnectPtr dconn, const char *dname,
                       const char *cookie ATTRIBUTE_UNUSED,
                       int cookielen ATTRIBUTE_UNUSED,
                       const char *uri ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
3997
                       unsigned long flags)
3998
{
E
Eric Blake 已提交
3999 4000
    virCheckFlags(ESX_MIGRATION_FLAGS, NULL);

4001 4002 4003 4004 4005
    return esxDomainLookupByName(dconn, dname);
}



M
Matthias Bolte 已提交
4006 4007 4008 4009
static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)
{
    unsigned long long result = 0;
M
Matthias Bolte 已提交
4010
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
4011 4012 4013 4014 4015
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *resourcePool = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_ResourcePoolResourceUsage *resourcePoolResourceUsage = NULL;

4016
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4017
        return 0;
M
Matthias Bolte 已提交
4018 4019 4020
    }

    /* Get memory usage of resource pool */
4021
    if (esxVI_String_AppendValueToList(&propertyNameList,
M
Matthias Bolte 已提交
4022
                                       "runtime.memory") < 0 ||
4023 4024
        esxVI_LookupObjectContentByType(priv->primary,
                                        priv->primary->computeResource->resourcePool,
4025
                                        "ResourcePool", propertyNameList,
4026 4027
                                        &resourcePool,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4028
        goto cleanup;
M
Matthias Bolte 已提交
4029 4030 4031 4032 4033 4034
    }

    for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.memory")) {
            if (esxVI_ResourcePoolResourceUsage_CastFromAnyType
4035
                  (dynamicProperty->val, &resourcePoolResourceUsage) < 0) {
M
Matthias Bolte 已提交
4036
                goto cleanup;
M
Matthias Bolte 已提交
4037 4038 4039 4040 4041 4042 4043 4044 4045
            }

            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    if (resourcePoolResourceUsage == NULL) {
4046 4047
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not retrieve memory usage of resource pool"));
M
Matthias Bolte 已提交
4048
        goto cleanup;
M
Matthias Bolte 已提交
4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062
    }

    result = resourcePoolResourceUsage->unreservedForVm->value;

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&resourcePool);
    esxVI_ResourcePoolResourceUsage_Free(&resourcePoolResourceUsage);

    return result;
}



4063
static int
4064
esxConnectIsEncrypted(virConnectPtr conn)
4065
{
M
Matthias Bolte 已提交
4066
    esxPrivate *priv = conn->privateData;
4067

4068
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4069 4070 4071 4072 4073 4074 4075 4076 4077
        return 1;
    } else {
        return 0;
    }
}



static int
4078
esxConnectIsSecure(virConnectPtr conn)
4079
{
M
Matthias Bolte 已提交
4080
    esxPrivate *priv = conn->privateData;
4081

4082
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4083 4084 4085 4086 4087 4088 4089 4090
        return 1;
    } else {
        return 0;
    }
}



4091
static int
4092
esxConnectIsAlive(virConnectPtr conn)
4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107
{
    esxPrivate *priv = conn->privateData;

    /* XXX we should be able to do something better than this but this is
     * simple, safe, and good enough for now. In worst case, the function will
     * return true even though the connection is not alive.
     */
    if (priv->primary)
        return 1;
    else
        return 0;
}



4108 4109 4110
static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4111
    int result = -1;
M
Matthias Bolte 已提交
4112
    esxPrivate *priv = domain->conn->privateData;
4113 4114 4115 4116
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4117
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4118
        return -1;
4119 4120
    }

4121
    if (esxVI_String_AppendValueToList(&propertyNameList,
4122
                                       "runtime.powerState") < 0 ||
4123
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4124
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4125
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4126
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4127
        goto cleanup;
4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        result = 1;
    } else {
        result = 0;
    }

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
4146
esxDomainIsPersistent(virDomainPtr domain)
4147
{
4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167
    /* ESX has no concept of transient domains, so all of them are
     * persistent.  However, we do want to check for existence. */
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;

    if (esxVI_EnsureSession(priv->primary) < 0)
        return -1;

    if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         NULL, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0)
        goto cleanup;

    result = 1;

cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4168 4169
}

M
Matthias Bolte 已提交
4170 4171


4172 4173 4174
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194
    /* ESX domains never have a persistent state that differs from
     * current state.  However, we do want to check for existence.  */
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;

    if (esxVI_EnsureSession(priv->primary) < 0)
        return -1;

    if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         NULL, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0)
        goto cleanup;

    result = 0;

cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4195
}
4196

M
Matthias Bolte 已提交
4197 4198


4199 4200
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4201
                           unsigned int flags)
4202 4203 4204 4205 4206 4207 4208 4209
{
    esxPrivate *priv = domain->conn->privateData;
    virDomainSnapshotDefPtr def = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4210
    char *taskInfoErrorMessage = NULL;
4211
    virDomainSnapshotPtr snapshot = NULL;
4212 4213
    bool diskOnly = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) != 0;
    bool quiesce = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) != 0;
4214

4215 4216 4217 4218 4219
    /* ESX supports disk-only and quiesced snapshots; libvirt tracks no
     * snapshot metadata so supporting that flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
4220

4221
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4222
        return NULL;
4223 4224
    }

4225
    def = virDomainSnapshotDefParseString(xmlDesc, priv->caps,
4226
                                          priv->xmlopt, 0, 0);
4227 4228

    if (def == NULL) {
M
Matthias Bolte 已提交
4229
        return NULL;
4230 4231
    }

4232
    if (def->ndisks) {
4233 4234
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
4235 4236 4237
        return NULL;
    }

4238
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4239
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4240
           priv->parsedUri->autoAnswer) < 0 ||
4241
        esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4242 4243
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
4244
                                    &snapshotTree, NULL,
4245
                                    esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4246
        goto cleanup;
4247 4248 4249
    }

    if (snapshotTree != NULL) {
4250 4251
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Snapshot '%s' already exists"), def->name);
M
Matthias Bolte 已提交
4252
        goto cleanup;
4253 4254
    }

4255
    if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4256
                                  def->name, def->description,
4257 4258 4259
                                  diskOnly ? esxVI_Boolean_False : esxVI_Boolean_True,
                                  quiesce ? esxVI_Boolean_True : esxVI_Boolean_False,
                                  &task) < 0 ||
4260
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4261
                                    esxVI_Occurrence_RequiredItem,
4262
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4263
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4264
        goto cleanup;
4265 4266 4267
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4268 4269
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4270
        goto cleanup;
4271 4272 4273 4274 4275 4276 4277 4278 4279
    }

    snapshot = virGetDomainSnapshot(domain, def->name);

  cleanup:
    virDomainSnapshotDefFree(def);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4280
    VIR_FREE(taskInfoErrorMessage);
4281 4282 4283 4284 4285 4286 4287

    return snapshot;
}



static char *
4288 4289
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4290 4291 4292 4293 4294 4295 4296 4297 4298
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotDef def;
    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
    char *xml = NULL;

4299 4300
    virCheckFlags(0, NULL);

4301
    memset(&def, 0, sizeof(def));
4302

4303
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4304
        return NULL;
4305 4306
    }

4307
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4308 4309 4310 4311
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4312
        goto cleanup;
4313 4314 4315 4316 4317 4318 4319 4320
    }

    def.name = snapshot->name;
    def.description = snapshotTree->description;
    def.parent = snapshotTreeParent != NULL ? snapshotTreeParent->name : NULL;

    if (esxVI_DateTime_ConvertToCalendarTime(snapshotTree->createTime,
                                             &def.creationTime) < 0) {
M
Matthias Bolte 已提交
4321
        goto cleanup;
4322 4323 4324 4325 4326 4327 4328
    }

    def.state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                  (snapshotTree->state);

    virUUIDFormat(snapshot->domain->uuid, uuid_string);

4329
    xml = virDomainSnapshotDefFormat(uuid_string, &def, flags, 0);
4330 4331 4332 4333 4334 4335 4336 4337 4338 4339

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



static int
4340
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4341
{
M
Matthias Bolte 已提交
4342
    int count;
4343 4344
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4345
    bool recurse;
4346
    bool leaves;
4347

4348
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4349 4350
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4351 4352

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4353
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4354

4355
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4356
        return -1;
4357 4358
    }

4359 4360 4361 4362
    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)
        return 0;

4363
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4364
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4365
        return -1;
4366 4367
    }

4368 4369
    count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList, recurse,
                                           leaves);
4370 4371 4372

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

M
Matthias Bolte 已提交
4373
    return count;
4374 4375 4376 4377 4378 4379
}



static int
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4380
                           unsigned int flags)
4381
{
M
Matthias Bolte 已提交
4382
    int result;
4383 4384
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4385
    bool recurse;
4386
    bool leaves;
4387 4388

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4389 4390
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4391

4392
    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4393
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4394

4395
    if (names == NULL || nameslen < 0) {
4396
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4397 4398 4399
        return -1;
    }

4400
    if (nameslen == 0 || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)) {
4401 4402 4403
        return 0;
    }

4404
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4405
        return -1;
4406 4407
    }

4408
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4409
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4410
        return -1;
4411 4412
    }

4413
    result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen,
4414
                                        recurse, leaves);
4415 4416 4417 4418 4419 4420 4421 4422

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4423 4424 4425 4426 4427 4428 4429 4430
static int
esxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    int count = -1;
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    bool recurse;
4431
    bool leaves;
4432 4433

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4434 4435
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4436 4437

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4438
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, snapshot->name,
                                    &snapshotTree, NULL,
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        count = 0;
        goto cleanup;
    }

    count = esxVI_GetNumberOfSnapshotTrees(snapshotTree->childSnapshotList,
4459
                                           recurse, leaves);
4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return count;
}



static int
esxDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
                                   char **names, int nameslen,
                                   unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    bool recurse;
4479
    bool leaves;
4480 4481

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4482 4483
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4484 4485

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4486
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4487 4488

    if (names == NULL || nameslen < 0) {
4489
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515
        return -1;
    }

    if (nameslen == 0) {
        return 0;
    }

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, snapshot->name,
                                    &snapshotTree, NULL,
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        result = 0;
        goto cleanup;
    }

    result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
4516
                                        names, nameslen, recurse, leaves);
4517 4518 4519 4520 4521 4522 4523 4524 4525

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4526 4527
static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4528
                              unsigned int flags)
4529 4530 4531 4532 4533 4534
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    virDomainSnapshotPtr snapshot = NULL;

4535 4536
    virCheckFlags(0, NULL);

4537
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4538
        return NULL;
4539 4540
    }

4541
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4542 4543
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
4544
                                    NULL,
4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, name);

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return snapshot;
}



static int
esxDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;

4565
    virCheckFlags(0, -1);
4566

4567
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4568
        return -1;
4569 4570
    }

4571
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4572 4573
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4574
        return -1;
4575 4576 4577
    }

    if (currentSnapshotTree != NULL) {
M
Matthias Bolte 已提交
4578 4579
        esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
        return 1;
4580 4581
    }

M
Matthias Bolte 已提交
4582
    return 0;
4583 4584 4585 4586
}



E
Eric Blake 已提交
4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610
static virDomainSnapshotPtr
esxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return NULL;
    }

    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    if (!snapshotTreeParent) {
4611 4612 4613
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshotTree->name);
E
Eric Blake 已提交
4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snapshotTreeParent->name);

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



4627 4628 4629 4630 4631
static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
M
Matthias Bolte 已提交
4632
    virDomainSnapshotPtr snapshot = NULL;
4633

4634
    virCheckFlags(0, NULL);
4635

4636
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4637
        return NULL;
4638 4639
    }

4640
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4641 4642
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4643
        return NULL;
4644 4645 4646 4647 4648 4649 4650 4651 4652 4653
    }

    snapshot = virGetDomainSnapshot(domain, currentSnapshotTree->name);

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}


4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722
static int
esxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    /* Check that snapshot exists.  */
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, NULL,
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    if (esxVI_LookupCurrentSnapshotTree(priv->primary, snapshot->domain->uuid,
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    ret = STREQ(snapshot->name, currentSnapshotTree->name);

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    return ret;
}


static int
esxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    /* Check that snapshot exists.  If so, there is no metadata.  */
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, NULL,
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    ret = 0;

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    return ret;
}

4723 4724 4725 4726

static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4727
    int result = -1;
4728 4729 4730 4731 4732
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4733
    char *taskInfoErrorMessage = NULL;
4734

4735
    virCheckFlags(0, -1);
4736

4737
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4738
        return -1;
4739 4740
    }

4741
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4742 4743
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4744
                                    &snapshotTree, NULL,
4745
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4746
        goto cleanup;
4747 4748
    }

4749
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4750
                                    esxVI_Boolean_Undefined, &task) < 0 ||
4751
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4752
                                    esxVI_Occurrence_RequiredItem,
4753
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4754
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4755
        goto cleanup;
4756 4757 4758
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4759 4760 4761
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not revert to snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4762
        goto cleanup;
4763 4764
    }

M
Matthias Bolte 已提交
4765 4766
    result = 0;

4767 4768 4769
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4770
    VIR_FREE(taskInfoErrorMessage);
4771 4772 4773 4774 4775 4776 4777 4778 4779

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4780
    int result = -1;
4781 4782 4783 4784 4785 4786
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_Boolean removeChildren = esxVI_Boolean_False;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4787
    char *taskInfoErrorMessage = NULL;
4788

4789 4790
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4791

4792
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4793
        return -1;
4794 4795 4796 4797 4798 4799
    }

    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) {
        removeChildren = esxVI_Boolean_True;
    }

4800
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4801 4802
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4803
                                    &snapshotTree, NULL,
4804
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4805
        goto cleanup;
4806 4807
    }

4808 4809 4810 4811 4812 4813 4814
    /* ESX snapshots do not require any libvirt metadata, making this
     * flag trivial once we know we have a valid snapshot.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
        result = 0;
        goto cleanup;
    }

4815
    if (esxVI_RemoveSnapshot_Task(priv->primary, snapshotTree->snapshot,
4816
                                  removeChildren, &task) < 0 ||
4817
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4818
                                    esxVI_Occurrence_RequiredItem,
4819
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4820
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4821
        goto cleanup;
4822 4823 4824
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4825 4826 4827
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not delete snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4828
        goto cleanup;
4829 4830
    }

M
Matthias Bolte 已提交
4831 4832
    result = 0;

4833 4834 4835
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4836
    VIR_FREE(taskInfoErrorMessage);
4837 4838 4839 4840 4841 4842

    return result;
}



4843
static int
4844
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4845 4846 4847 4848 4849 4850 4851 4852
                             int nparams, unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4853
    char *taskInfoErrorMessage = NULL;
4854
    size_t i;
4855 4856

    virCheckFlags(0, -1);
4857 4858 4859 4860
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
4861
        return -1;
4862 4863 4864 4865 4866 4867 4868

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4869
           priv->parsedUri->autoAnswer) < 0 ||
4870 4871 4872 4873 4874 4875
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
        goto cleanup;
    }

    for (i = 0; i < nparams; ++i) {
4876
        if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
4877 4878 4879 4880 4881
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) {
                goto cleanup;
            }

            spec->memoryAllocation->reservation->value =
4882
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4883 4884 4885 4886 4887 4888 4889
        }
    }

    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
4890
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4891
                                    &taskInfoErrorMessage) < 0) {
4892 4893 4894 4895
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4896 4897 4898
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change memory parameters: %s"),
                       taskInfoErrorMessage);
4899 4900 4901 4902 4903 4904 4905 4906 4907
        goto cleanup;
    }

    result = 0;

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4908
    VIR_FREE(taskInfoErrorMessage);
4909 4910 4911 4912 4913 4914 4915

    return result;
}



static int
4916
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945
                             int *nparams, unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_Long *reservation = NULL;

    virCheckFlags(0, -1);

    if (*nparams == 0) {
        *nparams = 1; /* min_guarantee */
        return 0;
    }

    if (esxVI_EnsureSession(priv->primary) < 0) {
        return -1;
    }

    if (esxVI_String_AppendValueToList
          (&propertyNameList, "config.memoryAllocation.reservation") < 0 ||
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
                                         propertyNameList, &virtualMachine,
                                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetLong(virtualMachine, "config.memoryAllocation.reservation",
                      &reservation, esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

4946 4947 4948 4949
    /* Scale from megabytes to kilobytes */
    if (virTypedParameterAssign(params, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                VIR_TYPED_PARAM_ULLONG,
                                reservation->value * 1024) < 0)
4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962
        goto cleanup;

    *nparams = 1;
    result = 0;

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Long_Free(&reservation);

    return result;
}

4963 4964
#define MATCH(FLAG) (flags & (FLAG))
static int
4965 4966 4967
esxConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
                         unsigned int flags)
4968 4969 4970
{
    int ret = -1;
    esxPrivate *priv = conn->privateData;
4971 4972
    bool needIdentity;
    bool needPowerState;
4973 4974 4975
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    size_t ndoms = 0;
4976
    esxVI_String *propertyNameList = NULL;
4977 4978
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
4979
    esxVI_AutoStartDefaults *autoStartDefaults = NULL;
4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996
    esxVI_VirtualMachinePowerState powerState;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    char *name = NULL;
    int id;
    unsigned char uuid[VIR_UUID_BUFLEN];
    int count = 0;
    bool autostart;
    int state;

    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);

    /* check for flags that would produce empty output lists:
     * - persistence: all esx machines are persistent
     * - managed save: esx doesn't support managed save
     */
4997
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
4998 4999 5000 5001 5002
         !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
        if (domains &&
            VIR_ALLOC_N(*domains, 1) < 0)
5003
            goto cleanup;
5004 5005 5006 5007 5008

        ret = 0;
        goto cleanup;
    }

5009
    if (esxVI_EnsureSession(priv->primary) < 0)
5010 5011 5012 5013 5014
        return -1;

    /* check system default autostart value */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
        if (esxVI_LookupAutoStartDefaults(priv->primary,
5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035
                                          &autoStartDefaults) < 0) {
            goto cleanup;
        }

        if (autoStartDefaults->enabled == esxVI_Boolean_True) {
            if (esxVI_LookupAutoStartPowerInfoList(priv->primary,
                                                   &powerInfoList) < 0) {
                goto cleanup;
            }
        }
    }

    needIdentity = MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT) ||
                   domains != NULL;

    if (needIdentity) {
        /* Request required data for esxVI_GetVirtualMachineIdentity */
        if (esxVI_String_AppendValueListToList(&propertyNameList,
                                               "configStatus\0"
                                               "name\0"
                                               "config.uuid\0") < 0) {
5036
            goto cleanup;
5037 5038 5039 5040 5041 5042
        }
    }

    needPowerState = MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) ||
                     MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) ||
                     domains != NULL;
5043

5044 5045 5046
    if (needPowerState) {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "runtime.powerState") < 0) {
5047
            goto cleanup;
5048
        }
5049 5050
    }

5051
    if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
5052 5053 5054 5055 5056
                                       &virtualMachineList) < 0)
        goto cleanup;

    if (domains) {
        if (VIR_ALLOC_N(doms, 1) < 0)
5057
            goto cleanup;
5058 5059 5060 5061 5062
        ndoms = 1;
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
5063 5064
        if (needIdentity) {
            VIR_FREE(name);
5065

5066 5067 5068 5069 5070
            if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id,
                                                &name, uuid) < 0) {
                goto cleanup;
            }
        }
5071

5072 5073 5074 5075 5076 5077
        if (needPowerState) {
            if (esxVI_GetVirtualMachinePowerState(virtualMachine,
                                                  &powerState) < 0) {
                goto cleanup;
            }
        }
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088

        /* filter by active state */
        if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
            !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) &&
               powerState != esxVI_VirtualMachinePowerState_PoweredOff) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) &&
               powerState == esxVI_VirtualMachinePowerState_PoweredOff)))
            continue;

        /* filter by snapshot existence */
        if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
5089 5090
            esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5091 5092 5093 5094 5095 5096
            if (esxVI_LookupRootSnapshotTreeList(priv->primary, uuid,
                                                 &rootSnapshotTreeList) < 0) {
                goto cleanup;
            }

            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
5097
                   rootSnapshotTreeList != NULL) ||
5098
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
5099
                   rootSnapshotTreeList == NULL)))
5100 5101 5102 5103 5104 5105 5106
                continue;
        }

        /* filter by autostart */
        if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
            autostart = false;

5107 5108 5109 5110 5111 5112
            if (autoStartDefaults->enabled == esxVI_Boolean_True) {
                for (powerInfo = powerInfoList; powerInfo != NULL;
                     powerInfo = powerInfo->_next) {
                    if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
                        if (STRCASEEQ(powerInfo->startAction, "powerOn"))
                            autostart = true;
5113

5114 5115
                        break;
                    }
5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128
                }
            }

            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
                   autostart) ||
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) &&
                   !autostart)))
                continue;
        }

        /* filter by domain state */
        if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) {
            state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState);
5129

5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148
            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
                   state == VIR_DOMAIN_RUNNING) ||
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
                   state == VIR_DOMAIN_PAUSED) ||
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
                   state == VIR_DOMAIN_SHUTOFF) ||
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
                   (state != VIR_DOMAIN_RUNNING &&
                    state != VIR_DOMAIN_PAUSED &&
                    state != VIR_DOMAIN_SHUTOFF))))
                continue;
        }

        /* just count the machines */
        if (!doms) {
            count++;
            continue;
        }

5149
        if (VIR_RESIZE_N(doms, ndoms, count, 2) < 0)
5150
            goto cleanup;
5151

5152 5153 5154
        if (!(dom = virGetDomain(conn, name, uuid)))
            goto cleanup;

5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171
        /* Only running/suspended virtual machines have an ID != -1 */
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff)
            dom->id = id;
        else
            dom->id = -1;

        doms[count++] = dom;
    }

    if (doms)
        *domains = doms;
    doms = NULL;
    ret = count;

cleanup:
    if (doms) {
        for (id = 0; id < count; id++) {
5172
            virDomainFree(doms[id]);
5173
        }
5174 5175

        VIR_FREE(doms);
5176
    }
5177

5178
    VIR_FREE(name);
5179 5180
    esxVI_AutoStartDefaults_Free(&autoStartDefaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);
5181 5182
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
5183 5184
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5185 5186 5187
    return ret;
}
#undef MATCH
5188 5189


5190
static virDriver esxDriver = {
5191 5192
    .no = VIR_DRV_ESX,
    .name = "ESX",
5193 5194 5195 5196 5197 5198
    .connectOpen = esxConnectOpen, /* 0.7.0 */
    .connectClose = esxConnectClose, /* 0.7.0 */
    .connectSupportsFeature = esxConnectSupportsFeature, /* 0.7.0 */
    .connectGetType = esxConnectGetType, /* 0.7.0 */
    .connectGetVersion = esxConnectGetVersion, /* 0.7.0 */
    .connectGetHostname = esxConnectGetHostname, /* 0.7.0 */
5199
    .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
5200 5201 5202 5203
    .connectGetCapabilities = esxConnectGetCapabilities, /* 0.7.1 */
    .connectListDomains = esxConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = esxConnectNumOfDomains, /* 0.7.0 */
    .connectListAllDomains = esxConnectListAllDomains, /* 0.10.2 */
5204 5205 5206 5207 5208 5209
    .domainLookupByID = esxDomainLookupByID, /* 0.7.0 */
    .domainLookupByUUID = esxDomainLookupByUUID, /* 0.7.0 */
    .domainLookupByName = esxDomainLookupByName, /* 0.7.0 */
    .domainSuspend = esxDomainSuspend, /* 0.7.0 */
    .domainResume = esxDomainResume, /* 0.7.0 */
    .domainShutdown = esxDomainShutdown, /* 0.7.0 */
5210
    .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
5211 5212
    .domainReboot = esxDomainReboot, /* 0.7.0 */
    .domainDestroy = esxDomainDestroy, /* 0.7.0 */
5213
    .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226
    .domainGetOSType = esxDomainGetOSType, /* 0.7.0 */
    .domainGetMaxMemory = esxDomainGetMaxMemory, /* 0.7.0 */
    .domainSetMaxMemory = esxDomainSetMaxMemory, /* 0.7.0 */
    .domainSetMemory = esxDomainSetMemory, /* 0.7.0 */
    .domainSetMemoryParameters = esxDomainSetMemoryParameters, /* 0.8.6 */
    .domainGetMemoryParameters = esxDomainGetMemoryParameters, /* 0.8.6 */
    .domainGetInfo = esxDomainGetInfo, /* 0.7.0 */
    .domainGetState = esxDomainGetState, /* 0.9.2 */
    .domainSetVcpus = esxDomainSetVcpus, /* 0.7.0 */
    .domainSetVcpusFlags = esxDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = esxDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = esxDomainGetMaxVcpus, /* 0.7.0 */
    .domainGetXMLDesc = esxDomainGetXMLDesc, /* 0.7.0 */
5227 5228 5229 5230
    .connectDomainXMLFromNative = esxConnectDomainXMLFromNative, /* 0.7.0 */
    .connectDomainXMLToNative = esxConnectDomainXMLToNative, /* 0.7.2 */
    .connectListDefinedDomains = esxConnectListDefinedDomains, /* 0.7.0 */
    .connectNumOfDefinedDomains = esxConnectNumOfDefinedDomains, /* 0.7.0 */
5231 5232 5233 5234
    .domainCreate = esxDomainCreate, /* 0.7.0 */
    .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
    .domainUndefine = esxDomainUndefine, /* 0.7.1 */
5235
    .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
5236 5237 5238 5239
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
5240
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
5241
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
5242
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
5243 5244 5245 5246
    .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
    .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
    .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
    .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
5247 5248
    .connectIsEncrypted = esxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = esxConnectIsSecure, /* 0.7.3 */
5249 5250 5251 5252 5253 5254 5255
    .domainIsActive = esxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = esxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = esxDomainIsUpdated, /* 0.8.6 */
    .domainSnapshotCreateXML = esxDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = esxDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = esxDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = esxDomainSnapshotListNames, /* 0.8.0 */
5256 5257
    .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
5258 5259
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
E
Eric Blake 已提交
5260
    .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
5261 5262
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
5263 5264
    .domainSnapshotIsCurrent = esxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = esxDomainSnapshotHasMetadata, /* 0.9.13 */
5265
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
5266
    .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */
5267 5268 5269 5270 5271 5272 5273
};



int
esxRegister(void)
{
5274 5275 5276 5277 5278
    if (virRegisterDriver(&esxDriver) < 0 ||
        esxInterfaceRegister() < 0 ||
        esxNetworkRegister() < 0 ||
        esxStorageRegister() < 0 ||
        esxDeviceRegister() < 0 ||
M
Matthias Bolte 已提交
5279 5280
        esxSecretRegister() < 0 ||
        esxNWFilterRegister() < 0) {
5281 5282
        return -1;
    }
5283 5284 5285

    return 0;
}