esx_driver.c 169.9 KB
Newer Older
1 2

/*
3
 * esx_driver.c: core driver functions for managing VMware ESX hosts
4
 *
5
 * Copyright (C) 2010-2012 Red Hat, Inc.
6
 * Copyright (C) 2009-2012 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 "virutil.h"
32
#include "viralloc.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"
M
Martin Kletzander 已提交
48
#include "viruri.h"
49 50 51 52 53

#define VIR_FROM_THIS VIR_FROM_ESX

static int esxDomainGetMaxVcpus(virDomainPtr domain);

54 55 56 57
typedef struct _esxVMX_Data esxVMX_Data;

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



63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
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);
    virCapabilitiesFree((*priv)->caps);
    VIR_FREE(*priv);
}



79
/*
80 81
 * 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:
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
 *
 * - 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
 *
103 104 105 106 107 108 109 110
 * - 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.
 *
111 112 113 114 115 116 117
 * 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
118
 * function via the opaque parameter by the caller of virVMXParseConfig.
119 120 121 122 123 124 125 126 127
 *
 * 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.
 */
128
static char *
129
esxParseVMXFileName(const char *fileName, void *opaque)
130
{
131
    char *result = NULL;
132
    esxVMX_Data *data = opaque;
133
    esxVI_String *propertyNameList = NULL;
134
    esxVI_ObjectContent *datastoreList = NULL;
135
    esxVI_ObjectContent *datastore = NULL;
136 137 138 139 140 141 142 143 144 145
    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 */
146
        if (virAsprintf(&result, "%s/%s",
147
                        data->datastorePathWithoutFileName, fileName) < 0) {
148 149 150 151 152 153 154 155 156 157
            virReportOOMError();
            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 185 186
            if (esxVI_String_DeepCopyValue(&strippedFileName, tmp) < 0) {
                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 201 202 203
                            strippedFileName) < 0) {
                virReportOOMError();
                goto cleanup;
            }
204

205 206
            break;
        }
207

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

214 215 216 217
            /* 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) {
218 219 220
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("File name '%s' doesn't have expected format "
                                 "'/vmfs/volumes/<datastore>/<path>'"), fileName);
221 222
                goto cleanup;
            }
223

224
            esxVI_ObjectContent_Free(&datastoreList);
225

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

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

239
            if (virAsprintf(&result, "[%s] %s", datastoreName,
240 241 242 243
                            directoryAndFileName) < 0) {
                virReportOOMError();
                goto cleanup;
            }
244 245
        }

246 247 248 249 250 251 252 253 254
        /* 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 */
            if (esxVI_String_DeepCopyValue(&result, fileName) < 0) {
                goto cleanup;
            }
        }

        if (result == NULL) {
255 256
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not handle file name '%s'"), fileName);
257
            goto cleanup;
258
        }
259
    }
260

261 262 263 264 265 266
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&datastoreList);
    esxVI_DatastoreHostMount_Free(&hostMount);
    VIR_FREE(strippedFileName);
    VIR_FREE(copyOfFileName);
267

268
    return result;
269 270 271 272
}



273
/*
E
Eric Blake 已提交
274
 * This function does the inverse of esxParseVMXFileName. It takes a file name
275 276
 * in datastore path format or in absolute format and converts it to a file
 * name that can be used in a .vmx file.
277 278 279 280 281 282
 *
 * 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 已提交
283
 * and file name to an absolute path and return it. Detect the separator type
284 285
 * based on the mount path.
 */
286
static char *
287
esxFormatVMXFileName(const char *fileName, void *opaque)
288 289
{
    bool success = false;
290
    char *result = NULL;
291
    esxVMX_Data *data = opaque;
292
    char *datastoreName = NULL;
293
    char *directoryAndFileName = NULL;
294 295 296 297 298
    esxVI_ObjectContent *datastore = NULL;
    esxVI_DatastoreHostMount *hostMount = NULL;
    char separator = '/';
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *tmp;
299
    size_t length;
300

301 302 303 304 305 306
    if (*fileName == '[') {
        /* Parse datastore path and lookup datastore */
        if (esxUtil_ParseDatastorePath(fileName, &datastoreName, NULL,
                                       &directoryAndFileName) < 0) {
            goto cleanup;
        }
307

308 309 310
        if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
                                        esxVI_Occurrence_RequiredItem) < 0 ||
            esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
311 312
                                           &hostMount,
                                           esxVI_Occurrence_RequiredItem) < 0) {
313 314
            goto cleanup;
        }
315

316 317 318 319
        /* Detect separator type */
        if (strchr(hostMount->mountInfo->path, '\\') != NULL) {
            separator = '\\';
        }
320

321 322
        /* Strip trailing separators */
        length = strlen(hostMount->mountInfo->path);
323

324 325 326
        while (length > 0 && hostMount->mountInfo->path[length - 1] == separator) {
            --length;
        }
327

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

331 332
        if (separator != '/') {
            tmp = directoryAndFileName;
333

334 335 336 337
            while (*tmp != '\0') {
                if (*tmp == '/') {
                    *tmp = separator;
                }
338

339 340
                ++tmp;
            }
341
        }
342

343 344
        virBufferAddChar(&buffer, separator);
        virBufferAdd(&buffer, directoryAndFileName, -1);
345

346 347 348 349 350 351 352 353 354 355 356 357
        if (virBufferError(&buffer)) {
            virReportOOMError();
            goto cleanup;
        }

        result = virBufferContentAndReset(&buffer);
    } else if (*fileName == '/') {
        /* FIXME: need to deal with Windows paths here too */
        if (esxVI_String_DeepCopyValue(&result, fileName) < 0) {
            goto cleanup;
        }
    } else {
358 359
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not handle file name '%s'"), fileName);
360 361 362 363 364 365 366 367 368
        goto cleanup;
    }

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

    success = true;

  cleanup:
    if (! success) {
369
        virBufferFreeAndReset(&buffer);
370
        VIR_FREE(result);
371 372 373
    }

    VIR_FREE(datastoreName);
374
    VIR_FREE(directoryAndFileName);
375 376
    esxVI_ObjectContent_Free(&datastore);
    esxVI_DatastoreHostMount_Free(&hostMount);
377

378
    return result;
379 380 381 382 383 384 385 386 387 388
}



static int
esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model,
                                 void *opaque)
{
    int result = -1;
    esxVMX_Data *data = opaque;
389
    esxVI_FileInfo *fileInfo = NULL;
390 391 392 393 394 395 396 397 398 399 400 401 402 403
    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;
    }

404 405
    if (esxVI_LookupFileInfoByDatastorePath(data->ctx, def->src,
                                            false, &fileInfo,
406
                                            esxVI_Occurrence_RequiredItem) < 0) {
407 408 409
        goto cleanup;
    }

410
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
411 412

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

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

    result = 0;

  cleanup:
440
    esxVI_FileInfo_Free(&fileInfo);
441 442 443 444

    return result;
}

445 446


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

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

462
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
463
        return esxVI_Boolean_Undefined;
464 465
    }

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

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

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

489
                    edxLongModeBit = parsedHostCpuIdInfo.edx[29];
490 491 492 493 494 495

                    if (edxLongModeBit == '1') {
                        priv->supportsLongMode = esxVI_Boolean_True;
                    } else if (edxLongModeBit == '0') {
                        priv->supportsLongMode = esxVI_Boolean_False;
                    } else {
496 497 498 499 500
                        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 已提交
501
                        goto cleanup;
502 503 504 505 506 507 508 509 510 511 512 513 514
                    }

                    break;
                }
            }

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

  cleanup:
M
Matthias Bolte 已提交
515 516 517 518
    /*
     * 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.
     */
519 520 521 522 523 524 525 526 527
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);
    esxVI_HostCpuIdInfo_Free(&hostCpuIdInfoList);

    return priv->supportsLongMode;
}



528 529 530 531 532 533
static int
esxLookupHostSystemBiosUuid(esxPrivate *priv, unsigned char *uuid)
{
    int result = -1;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
534
    char *uuid_string = NULL;
535

536
    if (esxVI_EnsureSession(priv->primary) < 0) {
537 538 539 540 541
        return -1;
    }

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

549 550 551
    if (strlen(uuid_string) > 0) {
        if (virUUIDParse(uuid_string, uuid) < 0) {
            VIR_WARN("Could not parse host UUID from string '%s'", uuid_string);
552

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

    result = 0;

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

    return result;
}


571
static int esxDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED,
572
                                 virArch arch ATTRIBUTE_UNUSED)
573 574 575 576
{
    return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
}

577

578
static virCapsPtr
579
esxCapsInit(esxPrivate *priv)
580
{
581
    esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
582 583 584
    virCapsPtr caps = NULL;
    virCapsGuestPtr guest = NULL;

585 586 587 588 589
    if (supportsLongMode == esxVI_Boolean_Undefined) {
        return NULL;
    }

    if (supportsLongMode == esxVI_Boolean_True) {
590
        caps = virCapabilitiesNew(VIR_ARCH_X86_64, 1, 1);
591
    } else {
592
        caps = virCapabilitiesNew(VIR_ARCH_I686, 1, 1);
593
    }
594 595

    if (caps == NULL) {
596
        virReportOOMError();
597 598 599
        return NULL;
    }

600
    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x0c, 0x29 });
601
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
602

603
    caps->hasWideScsiBus = true;
604
    caps->defaultConsoleTargetType = esxDefaultConsoleType;
605

606 607 608 609
    if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0) {
        goto failure;
    }

610
    /* i686 */
611 612 613
    guest = virCapabilitiesAddGuest(caps, "hvm",
                                    VIR_ARCH_I686,
                                    NULL, NULL, 0,
614
                                    NULL);
615 616 617 618 619 620 621 622 623 624

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

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

625 626
    /* x86_64 */
    if (supportsLongMode == esxVI_Boolean_True) {
627 628 629
        guest = virCapabilitiesAddGuest(caps, "hvm",
                                        VIR_ARCH_X86_64,
                                        NULL, NULL,
630 631 632 633 634 635 636 637 638 639 640 641
                                        0, NULL);

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

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

642 643 644 645 646 647 648 649 650 651
    return caps;

  failure:
    virCapabilitiesFree(caps);

    return NULL;
}



652
static int
653 654
esxConnectToHost(virConnectPtr conn,
                 virConnectAuthPtr auth,
655 656 657 658 659
                 char **vCenterIpAddress)
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
660
    char *unescapedPassword = NULL;
661 662 663 664 665
    char *password = NULL;
    char *url = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;
666 667 668 669
    esxPrivate *priv = conn->privateData;
    esxVI_ProductVersion expectedProductVersion = STRCASEEQ(conn->uri->scheme, "esx")
        ? esxVI_ProductVersion_ESX
        : esxVI_ProductVersion_GSX;
670 671

    if (vCenterIpAddress == NULL || *vCenterIpAddress != NULL) {
672
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
673 674 675
        return -1;
    }

676
    if (esxUtil_ResolveHostname(conn->uri->server, ipAddress, NI_MAXHOST) < 0) {
677 678 679
        return -1;
    }

680 681
    if (conn->uri->user != NULL) {
        username = strdup(conn->uri->user);
682 683 684 685 686 687

        if (username == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
688
        username = virAuthGetUsername(conn, auth, "esx", "root", conn->uri->server);
689 690

        if (username == NULL) {
691
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
692 693 694 695
            goto cleanup;
        }
    }

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

M
Matthias Bolte 已提交
698
    if (unescapedPassword == NULL) {
699
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
700 701 702
        goto cleanup;
    }

M
Matthias Bolte 已提交
703 704 705 706 707 708
    password = esxUtil_EscapeForXml(unescapedPassword);

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

709
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
710
                    conn->uri->server, conn->uri->port) < 0) {
711 712 713 714 715 716
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->host) < 0 ||
        esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
717
                              priv->parsedUri) < 0 ||
718
        esxVI_Context_LookupManagedObjects(priv->host) < 0) {
719 720 721 722 723
        goto cleanup;
    }

    if (expectedProductVersion == esxVI_ProductVersion_ESX) {
        if (priv->host->productVersion != esxVI_ProductVersion_ESX35 &&
M
Matthias Bolte 已提交
724 725
            priv->host->productVersion != esxVI_ProductVersion_ESX40 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX41 &&
P
Patrice LACHANCE 已提交
726 727
            priv->host->productVersion != esxVI_ProductVersion_ESX4x &&
            priv->host->productVersion != esxVI_ProductVersion_ESX50 &&
M
Martin Kletzander 已提交
728
            priv->host->productVersion != esxVI_ProductVersion_ESX51 &&
P
Patrice LACHANCE 已提交
729
            priv->host->productVersion != esxVI_ProductVersion_ESX5x) {
730 731 732
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s is neither an ESX 3.5, 4.x nor 5.x host"),
                           conn->uri->server);
733 734 735 736
            goto cleanup;
        }
    } else { /* GSX */
        if (priv->host->productVersion != esxVI_ProductVersion_GSX20) {
737 738
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s isn't a GSX 2.0 host"), conn->uri->server);
739 740 741 742 743 744 745 746
            goto cleanup;
        }
    }

    /* Query the host for maintenance mode and vCenter IP address */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "runtime.inMaintenanceMode\0"
                                           "summary.managementServerIp\0") < 0 ||
747 748
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
749 750 751 752 753 754 755 756 757 758 759
        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) {
760
        VIR_WARN("The server is in maintenance mode");
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    }

    if (*vCenterIpAddress != NULL) {
        *vCenterIpAddress = strdup(*vCenterIpAddress);

        if (*vCenterIpAddress == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    }

    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
776 777
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
778 779 780 781 782 783 784 785 786 787
    VIR_FREE(url);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



static int
788 789 790
esxConnectToVCenter(virConnectPtr conn,
                    virConnectAuthPtr auth,
                    const char *hostname,
791
                    const char *hostSystemIpAddress)
792 793 794 795
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
796
    char *unescapedPassword = NULL;
797 798
    char *password = NULL;
    char *url = NULL;
799
    esxPrivate *priv = conn->privateData;
800

801
    if (hostSystemIpAddress == NULL &&
802
        (priv->parsedUri->path == NULL || STREQ(priv->parsedUri->path, "/"))) {
803 804
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Path has to specify the datacenter and compute resource"));
805 806 807
        return -1;
    }

808 809 810 811
    if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST) < 0) {
        return -1;
    }

812 813
    if (conn->uri->user != NULL) {
        username = strdup(conn->uri->user);
814 815 816 817 818 819

        if (username == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
820
        username = virAuthGetUsername(conn, auth, "esx", "administrator", hostname);
821 822

        if (username == NULL) {
823
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
824 825 826 827
            goto cleanup;
        }
    }

828
    unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, hostname);
829

M
Matthias Bolte 已提交
830
    if (unescapedPassword == NULL) {
831
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
832 833 834
        goto cleanup;
    }

M
Matthias Bolte 已提交
835 836 837 838 839 840
    password = esxUtil_EscapeForXml(unescapedPassword);

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

841
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
842
                    hostname, conn->uri->port) < 0) {
843 844 845 846 847 848
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
        esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
849
                              password, priv->parsedUri) < 0) {
850 851 852 853
        goto cleanup;
    }

    if (priv->vCenter->productVersion != esxVI_ProductVersion_VPX25 &&
M
Matthias Bolte 已提交
854 855
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX40 &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX41 &&
P
Patrice LACHANCE 已提交
856 857
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX4x &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX50 &&
M
Martin Kletzander 已提交
858
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX51 &&
P
Patrice LACHANCE 已提交
859
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX5x) {
860 861 862
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s is neither a vCenter 2.5, 4.x nor 5.x server"),
                       hostname);
863 864 865
        goto cleanup;
    }

866
    if (hostSystemIpAddress != NULL) {
867 868
        if (esxVI_Context_LookupManagedObjectsByHostSystemIp
              (priv->vCenter, hostSystemIpAddress) < 0) {
869 870 871
            goto cleanup;
        }
    } else {
872 873
        if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter,
                                                     priv->parsedUri->path) < 0) {
874 875 876 877
            goto cleanup;
        }
    }

878 879 880 881
    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
882 883
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
884 885 886 887 888 889 890
    VIR_FREE(url);

    return result;
}



891
/*
892 893
 * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
 *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
894
 *
895 896
 * If no port is specified the default port is set dependent on the scheme and
 * transport parameter:
897 898
 * - vpx+http  80
 * - vpx+https 443
899
 * - esx+http  80
900
 * - esx+https 443
901 902 903
 * - gsx+http  8222
 * - gsx+https 8333
 *
904 905 906
 * 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
907 908
 * can be omitted. As datacenters and computeresources can be organized in
 * folders those have to be included in <path>.
909
 *
910 911
 * Optional query parameters:
 * - transport={http|https}
912
 * - vcenter={<vcenter>|*}             only useful for an esx:// connection
913 914
 * - no_verify={0|1}
 * - auto_answer={0|1}
M
Matthias Bolte 已提交
915
 * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
916
 *
917 918 919
 * If no transport parameter is specified https is used.
 *
 * The vcenter parameter is only necessary for migration, because the vCenter
920
 * server is in charge to initiate a migration between two ESX hosts. The
921
 * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
922 923
 * 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.
924 925
 *
 * If the no_verify parameter is set to 1, this disables libcurl client checks
926
 * of the server's certificate. The default value it 0.
927 928 929 930
 *
 * 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 已提交
931 932 933 934
 *
 * 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.
935 936
 */
static virDrvOpenStatus
937
esxOpen(virConnectPtr conn, virConnectAuthPtr auth,
E
Eric Blake 已提交
938
        unsigned int flags)
939
{
M
Matthias Bolte 已提交
940
    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
941
    char *plus;
942
    esxPrivate *priv = NULL;
943
    char *potentialVCenterIpAddress = NULL;
M
Matthias Bolte 已提交
944
    char vCenterIpAddress[NI_MAXHOST] = "";
945

E
Eric Blake 已提交
946 947
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

948 949
    /* Decline if the URI is NULL or the scheme is NULL */
    if (conn->uri == NULL || conn->uri->scheme == NULL) {
950 951 952
        return VIR_DRV_OPEN_DECLINED;
    }

953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
    /* 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;
        }

970 971 972
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Transport '%s' in URI scheme is not supported, try again "
                         "without the transport part"), plus + 1);
973 974 975
        return VIR_DRV_OPEN_ERROR;
    }

976 977 978 979 980 981
    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);
    }

982 983
    /* Require server part */
    if (conn->uri->server == NULL) {
984 985
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("URI is missing the server part"));
986 987 988 989 990
        return VIR_DRV_OPEN_ERROR;
    }

    /* Require auth */
    if (auth == NULL || auth->cb == NULL) {
991 992
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Missing or invalid auth pointer"));
993
        return VIR_DRV_OPEN_ERROR;
994 995 996 997
    }

    /* Allocate per-connection private data */
    if (VIR_ALLOC(priv) < 0) {
998
        virReportOOMError();
M
Matthias Bolte 已提交
999
        goto cleanup;
1000 1001
    }

1002
    if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0) {
1003 1004 1005
        goto cleanup;
    }

M
Matthias Bolte 已提交
1006 1007
    priv->maxVcpus = -1;
    priv->supportsVMotion = esxVI_Boolean_Undefined;
1008
    priv->supportsLongMode = esxVI_Boolean_Undefined;
1009 1010
    priv->usedCpuTimeCounterId = -1;

1011 1012
    conn->privateData = priv;

M
Matthias Bolte 已提交
1013 1014 1015 1016 1017 1018 1019
    /*
     * 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) {
1020 1021
        if (STRCASEEQ(conn->uri->scheme, "vpx") ||
            STRCASEEQ(conn->uri->scheme, "esx")) {
1022
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
1023 1024 1025 1026 1027
                conn->uri->port = 443;
            } else {
                conn->uri->port = 80;
            }
        } else { /* GSX */
1028
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
1029 1030 1031 1032
                conn->uri->port = 8333;
            } else {
                conn->uri->port = 8222;
            }
1033
        }
M
Matthias Bolte 已提交
1034
    }
1035

1036 1037 1038
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
1039
        if (esxConnectToHost(conn, auth,
1040
                             &potentialVCenterIpAddress) < 0) {
M
Matthias Bolte 已提交
1041
            goto cleanup;
1042
        }
1043

1044
        /* Connect to vCenter */
1045 1046
        if (priv->parsedUri->vCenter != NULL) {
            if (STREQ(priv->parsedUri->vCenter, "*")) {
1047
                if (potentialVCenterIpAddress == NULL) {
1048 1049
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("This host is not managed by a vCenter"));
M
Matthias Bolte 已提交
1050
                    goto cleanup;
1051 1052
                }

1053 1054
                if (virStrcpyStatic(vCenterIpAddress,
                                    potentialVCenterIpAddress) == NULL) {
1055 1056 1057
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("vCenter IP address %s too big for destination"),
                                   potentialVCenterIpAddress);
1058 1059 1060
                    goto cleanup;
                }
            } else {
1061
                if (esxUtil_ResolveHostname(priv->parsedUri->vCenter,
1062 1063 1064
                                            vCenterIpAddress, NI_MAXHOST) < 0) {
                    goto cleanup;
                }
1065

1066 1067
                if (potentialVCenterIpAddress != NULL &&
                    STRNEQ(vCenterIpAddress, potentialVCenterIpAddress)) {
1068 1069 1070 1071 1072 1073
                    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 已提交
1074
                    goto cleanup;
1075 1076
                }
            }
1077

1078 1079
            if (esxConnectToVCenter(conn, auth,
                                    vCenterIpAddress,
1080
                                    priv->host->ipAddress) < 0) {
1081 1082
                goto cleanup;
            }
1083 1084
        }

1085 1086 1087
        priv->primary = priv->host;
    } else { /* VPX */
        /* Connect to vCenter */
1088 1089 1090
        if (esxConnectToVCenter(conn, auth,
                                conn->uri->server,
                                NULL) < 0) {
M
Matthias Bolte 已提交
1091
            goto cleanup;
1092 1093
        }

1094
        priv->primary = priv->vCenter;
1095 1096
    }

M
Matthias Bolte 已提交
1097
    /* Setup capabilities */
1098
    priv->caps = esxCapsInit(priv);
1099

M
Matthias Bolte 已提交
1100
    if (priv->caps == NULL) {
M
Matthias Bolte 已提交
1101
        goto cleanup;
1102 1103
    }

M
Matthias Bolte 已提交
1104
    result = VIR_DRV_OPEN_SUCCESS;
1105

M
Matthias Bolte 已提交
1106
  cleanup:
1107 1108
    if (result == VIR_DRV_OPEN_ERROR) {
        esxFreePrivate(&priv);
1109 1110
    }

1111
    VIR_FREE(potentialVCenterIpAddress);
1112

M
Matthias Bolte 已提交
1113
    return result;
1114 1115 1116 1117 1118 1119 1120
}



static int
esxClose(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1121
    esxPrivate *priv = conn->privateData;
E
Eric Blake 已提交
1122
    int result = 0;
1123

1124 1125 1126 1127 1128 1129
    if (priv->host != NULL) {
        if (esxVI_EnsureSession(priv->host) < 0 ||
            esxVI_Logout(priv->host) < 0) {
            result = -1;
        }
    }
1130

M
Matthias Bolte 已提交
1131
    if (priv->vCenter != NULL) {
E
Eric Blake 已提交
1132 1133 1134 1135
        if (esxVI_EnsureSession(priv->vCenter) < 0 ||
            esxVI_Logout(priv->vCenter) < 0) {
            result = -1;
        }
1136 1137
    }

1138
    esxFreePrivate(&priv);
1139 1140 1141

    conn->privateData = NULL;

E
Eric Blake 已提交
1142
    return result;
1143 1144 1145 1146 1147
}



static esxVI_Boolean
1148
esxSupportsVMotion(esxPrivate *priv)
1149 1150 1151 1152
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

M
Matthias Bolte 已提交
1153 1154
    if (priv->supportsVMotion != esxVI_Boolean_Undefined) {
        return priv->supportsVMotion;
1155 1156
    }

1157
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1158
        return esxVI_Boolean_Undefined;
1159 1160
    }

1161
    if (esxVI_String_AppendValueToList(&propertyNameList,
1162
                                       "capability.vmotionSupported") < 0 ||
1163
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1164 1165
                                         &hostSystem) < 0 ||
        esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
1166 1167 1168
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1169 1170 1171
    }

  cleanup:
M
Matthias Bolte 已提交
1172 1173 1174 1175
    /*
     * 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.
     */
1176 1177 1178
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
1179
    return priv->supportsVMotion;
1180 1181 1182 1183 1184 1185 1186
}



static int
esxSupportsFeature(virConnectPtr conn, int feature)
{
M
Matthias Bolte 已提交
1187
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1188
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1189 1190 1191

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1192
        supportsVMotion = esxSupportsVMotion(priv);
1193

M
Matthias Bolte 已提交
1194
        if (supportsVMotion == esxVI_Boolean_Undefined) {
1195 1196 1197
            return -1;
        }

M
Matthias Bolte 已提交
1198 1199 1200
        /* Migration is only possible via a vCenter and if VMotion is enabled */
        return priv->vCenter != NULL &&
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219

      default:
        return 0;
    }
}



static const char *
esxGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return "ESX";
}



static int
esxGetVersion(virConnectPtr conn, unsigned long *version)
{
M
Matthias Bolte 已提交
1220
    esxPrivate *priv = conn->privateData;
1221

1222
    if (virParseVersionString(priv->primary->service->about->version,
1223
                              version, false) < 0) {
1224 1225 1226
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse version number from '%s'"),
                       priv->primary->service->about->version);
1227

1228
        return -1;
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
    }

    return 0;
}



static char *
esxGetHostname(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1239
    esxPrivate *priv = conn->privateData;
1240 1241 1242 1243 1244 1245 1246
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1247
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1248
        return NULL;
1249 1250 1251
    }

    if (esxVI_String_AppendValueListToList
1252
          (&propertyNameList,
1253 1254
           "config.network.dnsConfig.hostName\0"
           "config.network.dnsConfig.domainName\0") < 0 ||
1255 1256
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1257
        goto cleanup;
1258 1259 1260 1261 1262 1263
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1264
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1265
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1266
                goto cleanup;
1267 1268 1269 1270 1271
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1272
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1273
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1274
                goto cleanup;
1275 1276 1277 1278 1279 1280 1281 1282
            }

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

M
Matthias Bolte 已提交
1283
    if (hostName == NULL || strlen(hostName) < 1) {
1284 1285
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1286
        goto cleanup;
1287 1288
    }

M
Matthias Bolte 已提交
1289
    if (domainName == NULL || strlen(domainName) < 1) {
1290
        complete = strdup(hostName);
1291

1292
        if (complete == NULL) {
1293
            virReportOOMError();
M
Matthias Bolte 已提交
1294
            goto cleanup;
1295 1296 1297
        }
    } else {
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0) {
1298
            virReportOOMError();
M
Matthias Bolte 已提交
1299
            goto cleanup;
1300
        }
1301 1302 1303
    }

  cleanup:
M
Matthias Bolte 已提交
1304 1305 1306 1307 1308
    /*
     * If we goto cleanup in case of an error then complete is still NULL,
     * either strdup returned NULL or virAsprintf failed. When virAsprintf
     * fails it guarantees setting complete to NULL
     */
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1320
    int result = -1;
M
Matthias Bolte 已提交
1321
    esxPrivate *priv = conn->privateData;
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
    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;

1333
    memset(nodeinfo, 0, sizeof(*nodeinfo));
1334

1335
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1336
        return -1;
1337 1338
    }

1339
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1340 1341 1342 1343 1344 1345 1346
                                           "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 ||
1347 1348
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1349
        goto cleanup;
1350 1351 1352 1353 1354
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1355
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1356
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1357
                goto cleanup;
1358 1359 1360 1361 1362
            }

            cpuInfo_hz = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuCores")) {
1363
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1364
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1365
                goto cleanup;
1366 1367 1368 1369 1370
            }

            cpuInfo_numCpuCores = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuPackages")) {
1371
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1372
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1373
                goto cleanup;
1374 1375 1376 1377 1378
            }

            cpuInfo_numCpuPackages = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuThreads")) {
1379
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1380
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1381
                goto cleanup;
1382 1383 1384 1385
            }

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1386
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1387
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1388
                goto cleanup;
1389 1390 1391 1392 1393
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1394
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1395
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1396
                goto cleanup;
1397 1398 1399 1400 1401
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1402
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1403
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1404
                goto cleanup;
1405 1406 1407 1408 1409 1410
            }

            ptr = dynamicProperty->val->string;

            /* Strip the string to fit more relevant information in 32 chars */
            while (*ptr != '\0') {
M
Matthias Bolte 已提交
1411 1412
                if (STRPREFIX(ptr, "  ")) {
                    memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1413
                    continue;
1414
                } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
M
Matthias Bolte 已提交
1415
                    memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1416
                    continue;
1417 1418 1419
                } else if (STRPREFIX(ptr, "(TM)")) {
                    memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
                    continue;
1420 1421 1422 1423 1424
                }

                ++ptr;
            }

C
Chris Lalancette 已提交
1425 1426 1427
            if (virStrncpy(nodeinfo->model, dynamicProperty->val->string,
                           sizeof(nodeinfo->model) - 1,
                           sizeof(nodeinfo->model)) == NULL) {
1428 1429 1430
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("CPU Model %s too long for destination"),
                               dynamicProperty->val->string);
M
Matthias Bolte 已提交
1431
                goto cleanup;
C
Chris Lalancette 已提交
1432
            }
1433 1434 1435 1436 1437 1438 1439
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1440
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1441 1442 1443 1444 1445 1446 1447 1448 1449
    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 已提交
1450 1451
    result = 0;

1452 1453 1454 1455 1456 1457 1458 1459 1460
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1461 1462 1463
static char *
esxGetCapabilities(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1464
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1465
    char *xml = virCapabilitiesFormatXML(priv->caps);
1466 1467

    if (xml == NULL) {
1468
        virReportOOMError();
1469 1470 1471 1472 1473 1474 1475 1476
        return NULL;
    }

    return xml;
}



1477 1478 1479
static int
esxListDomains(virConnectPtr conn, int *ids, int maxids)
{
M
Matthias Bolte 已提交
1480
    bool success = false;
M
Matthias Bolte 已提交
1481
    esxPrivate *priv = conn->privateData;
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

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

1492
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1493
        return -1;
1494 1495
    }

1496
    if (esxVI_String_AppendValueToList(&propertyNameList,
1497
                                       "runtime.powerState") < 0 ||
1498 1499
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1500
        goto cleanup;
1501 1502 1503 1504
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1505
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1506
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1507
            goto cleanup;
1508 1509 1510 1511 1512 1513 1514 1515 1516
        }

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1517 1518 1519
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to parse positive integer from '%s'"),
                           virtualMachine->obj->value);
M
Matthias Bolte 已提交
1520
            goto cleanup;
1521 1522 1523 1524 1525 1526 1527 1528 1529
        }

        count++;

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

M
Matthias Bolte 已提交
1530 1531
    success = true;

1532 1533 1534 1535
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1536
    return success ? count : -1;
1537 1538 1539 1540 1541 1542 1543
}



static int
esxNumberOfDomains(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1544
    esxPrivate *priv = conn->privateData;
1545

1546
    if (esxVI_EnsureSession(priv->primary) < 0) {
1547 1548 1549
        return -1;
    }

1550
    return esxVI_LookupNumberOfDomainsByPowerState
1551
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1552 1553 1554 1555 1556 1557 1558
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1559
    esxPrivate *priv = conn->privateData;
1560 1561 1562 1563
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1564 1565 1566
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1567 1568
    virDomainPtr domain = NULL;

1569
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1570
        return NULL;
1571 1572
    }

1573
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1574
                                           "configStatus\0"
1575 1576
                                           "name\0"
                                           "runtime.powerState\0"
1577
                                           "config.uuid\0") < 0 ||
1578 1579
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1580
        goto cleanup;
1581 1582 1583 1584
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1585
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1586
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1587
            goto cleanup;
1588 1589 1590 1591 1592 1593 1594
        }

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

M
Matthias Bolte 已提交
1595
        VIR_FREE(name_candidate);
1596

1597
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1598 1599
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1600
            goto cleanup;
1601 1602
        }

M
Matthias Bolte 已提交
1603
        if (id != id_candidate) {
1604 1605 1606
            continue;
        }

M
Matthias Bolte 已提交
1607
        domain = virGetDomain(conn, name_candidate, uuid_candidate);
1608 1609

        if (domain == NULL) {
M
Matthias Bolte 已提交
1610
            goto cleanup;
1611 1612 1613 1614 1615 1616 1617 1618
        }

        domain->id = id;

        break;
    }

    if (domain == NULL) {
1619
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1620 1621 1622 1623 1624
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1625
    VIR_FREE(name_candidate);
1626 1627 1628 1629 1630 1631 1632 1633 1634

    return domain;
}



static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
M
Matthias Bolte 已提交
1635
    esxPrivate *priv = conn->privateData;
1636 1637 1638
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1639 1640
    int id = -1;
    char *name = NULL;
1641 1642
    virDomainPtr domain = NULL;

1643
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1644
        return NULL;
1645 1646
    }

1647
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1648
                                           "name\0"
1649
                                           "runtime.powerState\0") < 0 ||
1650
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1651
                                         &virtualMachine,
M
Matthias Bolte 已提交
1652
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1653 1654
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1655
        goto cleanup;
1656 1657
    }

1658
    domain = virGetDomain(conn, name, uuid);
1659 1660

    if (domain == NULL) {
M
Matthias Bolte 已提交
1661
        goto cleanup;
1662
    }
1663

1664 1665 1666 1667 1668
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1669 1670 1671 1672
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1673 1674
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1675 1676 1677 1678 1679 1680 1681 1682 1683

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1684
    esxPrivate *priv = conn->privateData;
1685 1686 1687
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1688 1689
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1690 1691
    virDomainPtr domain = NULL;

1692
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1693
        return NULL;
1694 1695
    }

1696
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1697
                                           "configStatus\0"
1698
                                           "runtime.powerState\0"
1699
                                           "config.uuid\0") < 0 ||
1700
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1701 1702
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1703
        goto cleanup;
1704 1705
    }

1706
    if (virtualMachine == NULL) {
1707
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1708
        goto cleanup;
1709
    }
1710

M
Matthias Bolte 已提交
1711 1712 1713
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1714
    }
1715

1716
    domain = virGetDomain(conn, name, uuid);
1717

1718
    if (domain == NULL) {
M
Matthias Bolte 已提交
1719
        goto cleanup;
1720 1721
    }

1722 1723 1724 1725 1726
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1727 1728 1729 1730
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1731
    esxVI_ObjectContent_Free(&virtualMachine);
1732 1733 1734 1735 1736 1737 1738 1739 1740

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1741
    int result = -1;
M
Matthias Bolte 已提交
1742
    esxPrivate *priv = domain->conn->privateData;
1743 1744 1745 1746 1747
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1748
    char *taskInfoErrorMessage = NULL;
1749

1750
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1751
        return -1;
1752 1753
    }

1754
    if (esxVI_String_AppendValueToList(&propertyNameList,
1755
                                       "runtime.powerState") < 0 ||
1756
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1757
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1758
           priv->parsedUri->autoAnswer) < 0 ||
1759
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1760
        goto cleanup;
1761 1762 1763
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1764 1765
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1766
        goto cleanup;
1767 1768
    }

1769 1770
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1771
                                    esxVI_Occurrence_RequiredItem,
1772
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1773
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1774
        goto cleanup;
1775 1776 1777
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1778 1779
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1780
        goto cleanup;
1781 1782
    }

M
Matthias Bolte 已提交
1783 1784
    result = 0;

1785 1786 1787 1788
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1789
    VIR_FREE(taskInfoErrorMessage);
1790 1791 1792 1793 1794 1795 1796 1797 1798

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1799
    int result = -1;
M
Matthias Bolte 已提交
1800
    esxPrivate *priv = domain->conn->privateData;
1801 1802 1803 1804 1805
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1806
    char *taskInfoErrorMessage = NULL;
1807

1808
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1809
        return -1;
1810 1811
    }

1812
    if (esxVI_String_AppendValueToList(&propertyNameList,
1813
                                       "runtime.powerState") < 0 ||
1814
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1815
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1816
           priv->parsedUri->autoAnswer) < 0 ||
1817
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1818
        goto cleanup;
1819 1820 1821
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1822
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1823
        goto cleanup;
1824 1825
    }

1826
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1827
                             &task) < 0 ||
1828
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1829
                                    esxVI_Occurrence_RequiredItem,
1830
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1831
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1832
        goto cleanup;
1833 1834 1835
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1836 1837
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1838
        goto cleanup;
1839 1840
    }

M
Matthias Bolte 已提交
1841 1842
    result = 0;

1843 1844 1845 1846
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1847
    VIR_FREE(taskInfoErrorMessage);
1848 1849 1850 1851 1852 1853 1854

    return result;
}



static int
1855
esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
1856
{
M
Matthias Bolte 已提交
1857
    int result = -1;
M
Matthias Bolte 已提交
1858
    esxPrivate *priv = domain->conn->privateData;
1859 1860 1861 1862
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1863 1864
    virCheckFlags(0, -1);

1865
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1866
        return -1;
1867 1868
    }

1869
    if (esxVI_String_AppendValueToList(&propertyNameList,
1870
                                       "runtime.powerState") < 0 ||
1871
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1872
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1873
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1874
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1875
        goto cleanup;
1876 1877 1878
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1879 1880
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1881
        goto cleanup;
1882 1883
    }

1884
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1885
        goto cleanup;
1886 1887
    }

M
Matthias Bolte 已提交
1888 1889
    result = 0;

1890 1891 1892 1893 1894 1895 1896 1897
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


1898 1899 1900 1901 1902 1903
static int
esxDomainShutdown(virDomainPtr domain)
{
    return esxDomainShutdownFlags(domain, 0);
}

1904 1905

static int
E
Eric Blake 已提交
1906
esxDomainReboot(virDomainPtr domain, unsigned int flags)
1907
{
M
Matthias Bolte 已提交
1908
    int result = -1;
M
Matthias Bolte 已提交
1909
    esxPrivate *priv = domain->conn->privateData;
1910 1911 1912 1913
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

E
Eric Blake 已提交
1914 1915
    virCheckFlags(0, -1);

1916
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1917
        return -1;
1918 1919
    }

1920
    if (esxVI_String_AppendValueToList(&propertyNameList,
1921
                                       "runtime.powerState") < 0 ||
1922
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1923
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1924
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1925
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1926
        goto cleanup;
1927 1928 1929
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1930 1931
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1932
        goto cleanup;
1933 1934
    }

1935
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1936
        goto cleanup;
1937 1938
    }

M
Matthias Bolte 已提交
1939 1940
    result = 0;

1941 1942 1943 1944 1945 1946 1947 1948 1949 1950
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
1951 1952
esxDomainDestroyFlags(virDomainPtr domain,
                      unsigned int flags)
1953
{
M
Matthias Bolte 已提交
1954
    int result = -1;
M
Matthias Bolte 已提交
1955
    esxPrivate *priv = domain->conn->privateData;
1956
    esxVI_Context *ctx = NULL;
1957 1958 1959 1960 1961
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1962
    char *taskInfoErrorMessage = NULL;
1963

1964 1965
    virCheckFlags(0, -1);

1966 1967 1968 1969 1970 1971
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1972
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
1973
        return -1;
1974 1975
    }

1976
    if (esxVI_String_AppendValueToList(&propertyNameList,
1977
                                       "runtime.powerState") < 0 ||
1978
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1979
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1980
           priv->parsedUri->autoAnswer) < 0 ||
1981
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1982
        goto cleanup;
1983 1984 1985
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1986 1987
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1988
        goto cleanup;
1989 1990
    }

1991
    if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1992 1993
        esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
1994
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1995
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1996
        goto cleanup;
1997 1998 1999
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2000 2001
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2002
        goto cleanup;
2003 2004
    }

2005
    domain->id = -1;
M
Matthias Bolte 已提交
2006 2007
    result = 0;

2008 2009 2010 2011
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
2012
    VIR_FREE(taskInfoErrorMessage);
2013 2014 2015 2016 2017

    return result;
}


2018 2019 2020 2021 2022 2023
static int
esxDomainDestroy(virDomainPtr dom)
{
    return esxDomainDestroyFlags(dom, 0);
}

2024 2025

static char *
2026
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
2027
{
2028 2029 2030
    char *osType = strdup("hvm");

    if (osType == NULL) {
2031
        virReportOOMError();
2032 2033 2034 2035
        return NULL;
    }

    return osType;
2036 2037 2038 2039
}



2040
static unsigned long long
2041 2042
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
2043
    esxPrivate *priv = domain->conn->privateData;
2044 2045 2046 2047 2048
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

2049
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2050
        return 0;
2051 2052
    }

2053
    if (esxVI_String_AppendValueToList(&propertyNameList,
2054
                                       "config.hardware.memoryMB") < 0 ||
2055
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2056
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2057
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2058
        goto cleanup;
2059 2060 2061 2062 2063
    }

    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2064
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2065
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2066
                goto cleanup;
2067 2068 2069
            }

            if (dynamicProperty->val->int32 < 0) {
2070 2071 2072
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Got invalid memory size %d"),
                               dynamicProperty->val->int32);
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094
            } 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 已提交
2095
    int result = -1;
M
Matthias Bolte 已提交
2096
    esxPrivate *priv = domain->conn->privateData;
2097
    esxVI_String *propertyNameList = NULL;
2098
    esxVI_ObjectContent *virtualMachine = NULL;
2099
    esxVI_VirtualMachinePowerState powerState;
2100 2101 2102
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2103
    char *taskInfoErrorMessage = NULL;
2104

2105
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2106
        return -1;
2107 2108
    }

2109 2110 2111 2112
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2113
           priv->parsedUri->autoAnswer) < 0 ||
2114 2115 2116 2117 2118
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2119 2120
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
2121 2122 2123 2124
        goto cleanup;
    }

    if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
2125
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
2126
        goto cleanup;
2127 2128
    }

2129
    /* max-memory must be a multiple of 4096 kilobyte */
2130
    spec->memoryMB->value =
2131
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2132

2133
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2134
                              &task) < 0 ||
2135
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2136
                                    esxVI_Occurrence_RequiredItem,
2137
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2138
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2139
        goto cleanup;
2140 2141 2142
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2143 2144 2145
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set max-memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2146
        goto cleanup;
2147 2148
    }

M
Matthias Bolte 已提交
2149 2150
    result = 0;

2151
  cleanup:
2152
    esxVI_String_Free(&propertyNameList);
2153 2154 2155
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2156
    VIR_FREE(taskInfoErrorMessage);
2157 2158 2159 2160 2161 2162 2163 2164 2165

    return result;
}



static int
esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2166
    int result = -1;
M
Matthias Bolte 已提交
2167
    esxPrivate *priv = domain->conn->privateData;
2168 2169 2170 2171
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2172
    char *taskInfoErrorMessage = NULL;
2173

2174
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2175
        return -1;
2176 2177
    }

2178
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2179
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2180
           priv->parsedUri->autoAnswer) < 0 ||
2181 2182 2183
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
        esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
M
Matthias Bolte 已提交
2184
        goto cleanup;
2185 2186 2187
    }

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

2190
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2191
                              &task) < 0 ||
2192
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2193
                                    esxVI_Occurrence_RequiredItem,
2194
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2195
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2196
        goto cleanup;
2197 2198 2199
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2200 2201 2202
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2203
        goto cleanup;
2204 2205
    }

M
Matthias Bolte 已提交
2206 2207
    result = 0;

2208 2209 2210 2211
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2212
    VIR_FREE(taskInfoErrorMessage);
2213 2214 2215 2216 2217 2218

    return result;
}



2219 2220 2221 2222 2223 2224 2225 2226 2227
/*
 * 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

2228 2229 2230
static int
esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
M
Matthias Bolte 已提交
2231
    int result = -1;
M
Matthias Bolte 已提交
2232
    esxPrivate *priv = domain->conn->privateData;
2233 2234 2235 2236 2237
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int64_t memory_limit = -1;
2238
#if ESX_QUERY_FOR_USED_CPU_TIME
2239 2240 2241 2242 2243 2244 2245
    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;
2246 2247
    esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
    esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2248 2249 2250
    esxVI_PerfEntityMetric *perfEntityMetric = NULL;
    esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
    esxVI_Long *value = NULL;
2251
#endif
2252

2253
    memset(info, 0, sizeof(*info));
M
Matthias Bolte 已提交
2254

2255
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2256
        return -1;
2257 2258
    }

2259
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2260 2261 2262 2263
                                           "runtime.powerState\0"
                                           "config.hardware.memoryMB\0"
                                           "config.hardware.numCPU\0"
                                           "config.memoryAllocation.limit\0") < 0 ||
2264
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2265
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2266
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2267
        goto cleanup;
2268 2269 2270 2271 2272 2273 2274 2275
    }

    info->state = VIR_DOMAIN_NOSTATE;

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

2280 2281
            info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                            (powerState);
2282
        } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2283
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2284
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2285
                goto cleanup;
2286 2287 2288 2289
            }

            info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
        } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2290
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2291
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2292
                goto cleanup;
2293 2294 2295 2296 2297
            }

            info->nrVirtCpu = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "config.memoryAllocation.limit")) {
2298
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2299
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
2300
                goto cleanup;
2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
            }

            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;

2316
#if ESX_QUERY_FOR_USED_CPU_TIME
2317
    /* Verify the cached 'used CPU time' performance counter ID */
2318 2319 2320 2321 2322 2323
    /* 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;
            }
2324

2325
            counterId->value = priv->usedCpuTimeCounterId;
2326

2327 2328 2329
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                goto cleanup;
            }
2330

2331 2332 2333 2334
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2335

2336 2337 2338 2339 2340
            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);
2341

2342 2343 2344 2345 2346
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2347 2348
        }

2349 2350 2351 2352 2353 2354 2355 2356 2357 2358
        /*
         * 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;
            }
2359

2360 2361 2362 2363
            for (perfMetricId = perfMetricIdList; perfMetricId != NULL;
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2364

2365
                counterId = NULL;
2366

2367 2368 2369 2370 2371
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2372

2373 2374
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2375
                goto cleanup;
2376 2377
            }

2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
            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;
                }
2395 2396
            }

2397
            if (priv->usedCpuTimeCounterId < 0) {
2398
                VIR_WARN("Could not find 'used CPU time' performance counter");
2399
            }
2400 2401
        }

2402 2403 2404 2405 2406 2407
        /*
         * 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);
2408

2409 2410 2411 2412 2413 2414
            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;
            }
2415

2416 2417 2418 2419 2420 2421 2422 2423 2424 2425
            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;
            }
2426

2427 2428 2429
            for (perfEntityMetricBase = perfEntityMetricBaseList;
                 perfEntityMetricBase != NULL;
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2430
                VIR_DEBUG("perfEntityMetric ...");
2431

2432 2433
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2434

2435
                if (perfEntityMetric == NULL) {
2436 2437 2438
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetricBase->_type));
2439
                    goto cleanup;
2440
                }
2441

2442 2443
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2444

2445
                if (perfMetricIntSeries == NULL) {
2446 2447 2448
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetric->value->_type));
2449
                    goto cleanup;
2450
                }
2451

2452 2453
                for (; perfMetricIntSeries != NULL;
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2454
                    VIR_DEBUG("perfMetricIntSeries ...");
2455

2456 2457 2458 2459 2460
                    for (value = perfMetricIntSeries->value;
                         value != NULL;
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2461 2462 2463
                }
            }

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

2466
            /*
E
Eric Blake 已提交
2467
             * FIXME: Cannot map between relative used-cpu-time and absolute
2468 2469 2470
             *        info->cpuTime
             */
        }
2471
    }
2472
#endif
2473

M
Matthias Bolte 已提交
2474 2475
    result = 0;

2476
  cleanup:
2477
#if ESX_QUERY_FOR_USED_CPU_TIME
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489
    /*
     * 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;
        }
    }
2490
#endif
2491

2492 2493
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2494
#if ESX_QUERY_FOR_USED_CPU_TIME
2495 2496 2497 2498
    esxVI_PerfMetricId_Free(&perfMetricIdList);
    esxVI_Int_Free(&counterIdList);
    esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
    esxVI_PerfQuerySpec_Free(&querySpec);
2499
    esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2500
#endif
2501 2502 2503 2504 2505 2506

    return result;
}



2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
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;
}



2550
static int
2551 2552
esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                       unsigned int flags)
2553
{
M
Matthias Bolte 已提交
2554
    int result = -1;
M
Matthias Bolte 已提交
2555
    esxPrivate *priv = domain->conn->privateData;
M
Matthias Bolte 已提交
2556
    int maxVcpus;
2557 2558 2559 2560
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2561
    char *taskInfoErrorMessage = NULL;
2562

2563
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2564
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2565 2566 2567
        return -1;
    }

2568
    if (nvcpus < 1) {
2569 2570
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2571
        return -1;
2572 2573
    }

2574
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2575
        return -1;
2576 2577
    }

M
Matthias Bolte 已提交
2578
    maxVcpus = esxDomainGetMaxVcpus(domain);
2579

M
Matthias Bolte 已提交
2580
    if (maxVcpus < 0) {
M
Matthias Bolte 已提交
2581
        return -1;
2582 2583
    }

M
Matthias Bolte 已提交
2584
    if (nvcpus > maxVcpus) {
2585 2586 2587 2588
        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 已提交
2589
        return -1;
2590 2591
    }

2592
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2593
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2594
           priv->parsedUri->autoAnswer) < 0 ||
2595 2596
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_Int_Alloc(&spec->numCPUs) < 0) {
M
Matthias Bolte 已提交
2597
        goto cleanup;
2598 2599 2600 2601
    }

    spec->numCPUs->value = nvcpus;

2602
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2603
                              &task) < 0 ||
2604
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2605
                                    esxVI_Occurrence_RequiredItem,
2606
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2607
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2608
        goto cleanup;
2609 2610 2611
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2612 2613 2614
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2615
        goto cleanup;
2616 2617
    }

M
Matthias Bolte 已提交
2618 2619
    result = 0;

2620 2621 2622 2623
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2624
    VIR_FREE(taskInfoErrorMessage);
2625 2626 2627 2628 2629

    return result;
}


M
Matthias Bolte 已提交
2630

2631 2632 2633
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
2634
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2635 2636
}

2637

M
Matthias Bolte 已提交
2638

2639
static int
2640
esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2641
{
M
Matthias Bolte 已提交
2642
    esxPrivate *priv = domain->conn->privateData;
2643 2644 2645 2646
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

2647
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2648
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2649 2650 2651
        return -1;
    }

M
Matthias Bolte 已提交
2652 2653
    if (priv->maxVcpus > 0) {
        return priv->maxVcpus;
2654 2655
    }

M
Matthias Bolte 已提交
2656 2657
    priv->maxVcpus = -1;

2658
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2659
        return -1;
2660 2661
    }

2662
    if (esxVI_String_AppendValueToList(&propertyNameList,
2663
                                       "capability.maxSupportedVcpus") < 0 ||
2664 2665
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
2666
        goto cleanup;
2667 2668 2669 2670 2671
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2672
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2673
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2674
                goto cleanup;
2675 2676
            }

M
Matthias Bolte 已提交
2677
            priv->maxVcpus = dynamicProperty->val->int32;
2678 2679 2680 2681 2682 2683 2684 2685 2686 2687
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

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

M
Matthias Bolte 已提交
2688
    return priv->maxVcpus;
2689 2690
}

M
Matthias Bolte 已提交
2691 2692


2693 2694 2695
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
2696
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2697 2698
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2699

M
Matthias Bolte 已提交
2700 2701


2702
static char *
2703
esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2704
{
M
Matthias Bolte 已提交
2705
    esxPrivate *priv = domain->conn->privateData;
2706 2707
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2708 2709
    esxVI_VirtualMachinePowerState powerState;
    int id;
2710
    char *vmPathName = NULL;
2711
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2712
    char *directoryName = NULL;
2713
    char *directoryAndFileName = NULL;
2714
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2715 2716
    char *url = NULL;
    char *vmx = NULL;
2717
    virVMXContext ctx;
2718
    esxVMX_Data data;
2719 2720 2721
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2722 2723
    /* Flags checked by virDomainDefFormat */

2724
    memset(&data, 0, sizeof(data));
2725

2726
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2727
        return NULL;
2728 2729
    }

2730 2731 2732
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "config.files.vmPathName\0"
                                           "runtime.powerState\0") < 0 ||
2733
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2734
                                         propertyNameList, &virtualMachine,
2735
                                         esxVI_Occurrence_RequiredItem) < 0 ||
2736 2737
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2738 2739
        esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
                             &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2740
        goto cleanup;
2741 2742
    }

2743
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2744
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2745
        goto cleanup;
2746 2747
    }

2748
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2749
                      domain->conn->uri->server, domain->conn->uri->port);
2750
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2751
    virBufferAddLit(&buffer, "?dcPath=");
2752
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
2753 2754 2755 2756
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
2757
        virReportOOMError();
M
Matthias Bolte 已提交
2758
        goto cleanup;
2759 2760
    }

2761 2762
    url = virBufferContentAndReset(&buffer);

2763
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx, 0, NULL) < 0) {
M
Matthias Bolte 已提交
2764
        goto cleanup;
2765 2766
    }

2767
    data.ctx = priv->primary;
2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781

    if (directoryName == NULL) {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s]",
                        datastoreName) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s] %s",
                        datastoreName, directoryName) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }
2782 2783 2784 2785 2786 2787

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

2788
    def = virVMXParseConfig(&ctx, priv->caps, vmx);
2789 2790

    if (def != NULL) {
2791 2792 2793 2794
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
            def->id = id;
        }

2795
        xml = virDomainDefFormat(def, flags);
2796 2797 2798
    }

  cleanup:
M
Matthias Bolte 已提交
2799 2800 2801 2802
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

2803 2804
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2805
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2806
    VIR_FREE(directoryName);
2807
    VIR_FREE(directoryAndFileName);
2808
    VIR_FREE(url);
2809
    VIR_FREE(data.datastorePathWithoutFileName);
2810
    VIR_FREE(vmx);
2811
    virDomainDefFree(def);
2812 2813 2814 2815 2816 2817 2818 2819 2820

    return xml;
}



static char *
esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                       const char *nativeConfig,
E
Eric Blake 已提交
2821
                       unsigned int flags)
2822
{
M
Matthias Bolte 已提交
2823
    esxPrivate *priv = conn->privateData;
2824
    virVMXContext ctx;
2825
    esxVMX_Data data;
2826 2827 2828
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2829 2830
    virCheckFlags(0, NULL);

2831
    memset(&data, 0, sizeof(data));
2832

2833
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2834 2835
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
2836
        return NULL;
2837 2838
    }

2839
    data.ctx = priv->primary;
2840
    data.datastorePathWithoutFileName = (char *)"[?] ?";
2841 2842 2843 2844 2845 2846

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

2847
    def = virVMXParseConfig(&ctx, priv->caps, nativeConfig);
2848 2849

    if (def != NULL) {
2850
        xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
2851 2852 2853 2854 2855 2856 2857 2858 2859
    }

    virDomainDefFree(def);

    return xml;
}



M
Matthias Bolte 已提交
2860 2861 2862
static char *
esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                     const char *domainXml,
E
Eric Blake 已提交
2863
                     unsigned int flags)
M
Matthias Bolte 已提交
2864
{
M
Matthias Bolte 已提交
2865
    esxPrivate *priv = conn->privateData;
2866 2867
    int virtualHW_version;
    virVMXContext ctx;
2868
    esxVMX_Data data;
M
Matthias Bolte 已提交
2869 2870 2871
    virDomainDefPtr def = NULL;
    char *vmx = NULL;

E
Eric Blake 已提交
2872 2873
    virCheckFlags(0, NULL);

2874
    memset(&data, 0, sizeof(data));
2875

M
Matthias Bolte 已提交
2876
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2877 2878
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
M
Matthias Bolte 已提交
2879 2880 2881
        return NULL;
    }

2882 2883 2884 2885 2886 2887 2888
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        return NULL;
    }

M
Matthias Bolte 已提交
2889 2890
    def = virDomainDefParseString(priv->caps, domainXml,
                                  1 << VIR_DOMAIN_VIRT_VMWARE, 0);
M
Matthias Bolte 已提交
2891 2892 2893 2894 2895

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

2896
    data.ctx = priv->primary;
2897
    data.datastorePathWithoutFileName = NULL;
2898 2899 2900 2901 2902 2903

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

2904
    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
M
Matthias Bolte 已提交
2905 2906 2907 2908 2909 2910 2911 2912

    virDomainDefFree(def);

    return vmx;
}



2913 2914 2915
static int
esxListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
{
M
Matthias Bolte 已提交
2916
    bool success = false;
M
Matthias Bolte 已提交
2917
    esxPrivate *priv = conn->privateData;
2918 2919 2920 2921 2922
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;
2923
    int i;
2924 2925 2926 2927 2928

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

2929
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2930
        return -1;
2931 2932
    }

2933
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2934 2935
                                           "name\0"
                                           "runtime.powerState\0") < 0 ||
2936 2937
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
2938
        goto cleanup;
2939 2940 2941 2942
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
2943
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2944
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
2945
            goto cleanup;
2946 2947 2948 2949 2950 2951
        }

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2952
        names[count] = NULL;
2953

2954 2955 2956
        if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
                                            NULL) < 0) {
            goto cleanup;
2957 2958
        }

2959 2960
        ++count;

2961 2962 2963 2964 2965
        if (count >= maxnames) {
            break;
        }
    }

M
Matthias Bolte 已提交
2966
    success = true;
2967

M
Matthias Bolte 已提交
2968 2969 2970 2971 2972
  cleanup:
    if (! success) {
        for (i = 0; i < count; ++i) {
            VIR_FREE(names[i]);
        }
2973

M
Matthias Bolte 已提交
2974
        count = -1;
2975 2976
    }

M
Matthias Bolte 已提交
2977 2978
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2979

M
Matthias Bolte 已提交
2980
    return count;
2981 2982 2983 2984 2985 2986 2987
}



static int
esxNumberOfDefinedDomains(virConnectPtr conn)
{
M
Matthias Bolte 已提交
2988
    esxPrivate *priv = conn->privateData;
2989

2990
    if (esxVI_EnsureSession(priv->primary) < 0) {
2991 2992 2993
        return -1;
    }

2994
    return esxVI_LookupNumberOfDomainsByPowerState
2995
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
2996 2997 2998 2999 3000
}



static int
3001
esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
3002
{
M
Matthias Bolte 已提交
3003
    int result = -1;
M
Matthias Bolte 已提交
3004
    esxPrivate *priv = domain->conn->privateData;
3005 3006 3007
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
3008
    int id = -1;
3009 3010
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3011
    char *taskInfoErrorMessage = NULL;
3012

3013 3014
    virCheckFlags(0, -1);

3015
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3016
        return -1;
3017 3018
    }

3019
    if (esxVI_String_AppendValueToList(&propertyNameList,
3020
                                       "runtime.powerState") < 0 ||
3021
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3022
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
3023
           priv->parsedUri->autoAnswer) < 0 ||
3024 3025
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
M
Matthias Bolte 已提交
3026
        goto cleanup;
3027 3028 3029
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3030 3031
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
M
Matthias Bolte 已提交
3032
        goto cleanup;
3033 3034
    }

3035
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
3036
                             &task) < 0 ||
3037
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3038
                                    esxVI_Occurrence_RequiredItem,
3039
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3040
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3041
        goto cleanup;
3042 3043 3044
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3045 3046
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3047
        goto cleanup;
3048 3049
    }

3050
    domain->id = id;
M
Matthias Bolte 已提交
3051 3052
    result = 0;

3053 3054 3055 3056
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
3057
    VIR_FREE(taskInfoErrorMessage);
3058 3059 3060 3061

    return result;
}

3062 3063


3064 3065 3066 3067 3068
static int
esxDomainCreate(virDomainPtr domain)
{
    return esxDomainCreateWithFlags(domain, 0);
}
3069

3070 3071


M
Matthias Bolte 已提交
3072
static virDomainPtr
3073
esxDomainDefineXML(virConnectPtr conn, const char *xml)
M
Matthias Bolte 已提交
3074
{
M
Matthias Bolte 已提交
3075
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3076 3077
    virDomainDefPtr def = NULL;
    char *vmx = NULL;
3078 3079
    int i;
    virDomainDiskDefPtr disk = NULL;
M
Matthias Bolte 已提交
3080
    esxVI_ObjectContent *virtualMachine = NULL;
3081 3082
    int virtualHW_version;
    virVMXContext ctx;
3083
    esxVMX_Data data;
M
Matthias Bolte 已提交
3084 3085
    char *datastoreName = NULL;
    char *directoryName = NULL;
3086
    char *escapedName = NULL;
M
Matthias Bolte 已提交
3087 3088 3089 3090 3091 3092 3093 3094
    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;
3095
    char *taskInfoErrorMessage = NULL;
M
Matthias Bolte 已提交
3096 3097
    virDomainPtr domain = NULL;

3098
    memset(&data, 0, sizeof(data));
3099

3100
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3101
        return NULL;
M
Matthias Bolte 已提交
3102 3103 3104
    }

    /* Parse domain XML */
M
Matthias Bolte 已提交
3105
    def = virDomainDefParseString(priv->caps, xml, 1 << VIR_DOMAIN_VIRT_VMWARE,
M
Matthias Bolte 已提交
3106 3107 3108
                                  VIR_DOMAIN_XML_INACTIVE);

    if (def == NULL) {
M
Matthias Bolte 已提交
3109
        return NULL;
M
Matthias Bolte 已提交
3110 3111 3112
    }

    /* Check if an existing domain should be edited */
3113
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3114
                                         &virtualMachine,
M
Matthias Bolte 已提交
3115
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3116
        goto cleanup;
M
Matthias Bolte 已提交
3117 3118
    }

3119 3120 3121 3122 3123 3124 3125
    if (virtualMachine == NULL &&
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

M
Matthias Bolte 已提交
3126 3127
    if (virtualMachine != NULL) {
        /* FIXME */
3128 3129 3130
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain already exists, editing existing domains is not "
                         "supported yet"));
M
Matthias Bolte 已提交
3131
        goto cleanup;
M
Matthias Bolte 已提交
3132 3133 3134
    }

    /* Build VMX from domain XML */
3135 3136 3137 3138 3139 3140 3141
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        goto cleanup;
    }

3142
    data.ctx = priv->primary;
3143
    data.datastorePathWithoutFileName = NULL;
3144 3145 3146 3147 3148 3149

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

3150
    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
M
Matthias Bolte 已提交
3151 3152

    if (vmx == NULL) {
M
Matthias Bolte 已提交
3153
        goto cleanup;
M
Matthias Bolte 已提交
3154 3155
    }

3156 3157 3158 3159 3160 3161 3162
    /*
     * 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 已提交
3163
    if (def->ndisks < 1) {
3164 3165 3166
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any disks, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3167
        goto cleanup;
3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178
    }

    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) {
3179 3180 3181
        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 已提交
3182
        goto cleanup;
M
Matthias Bolte 已提交
3183 3184
    }

3185
    if (disk->src == NULL) {
3186 3187 3188
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("First file-based harddisk has no source, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3189
        goto cleanup;
M
Matthias Bolte 已提交
3190 3191
    }

3192
    if (esxUtil_ParseDatastorePath(disk->src, &datastoreName, &directoryName,
3193
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3194
        goto cleanup;
M
Matthias Bolte 已提交
3195 3196
    }

3197
    if (! virFileHasSuffix(disk->src, ".vmdk")) {
3198 3199 3200
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting source '%s' of first file-based harddisk to "
                         "be a VMDK image"), disk->src);
M
Matthias Bolte 已提交
3201
        goto cleanup;
M
Matthias Bolte 已提交
3202 3203
    }

3204
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3205 3206 3207 3208 3209 3210 3211
                      conn->uri->server, conn->uri->port);

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

3212 3213 3214 3215 3216 3217 3218
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

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

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3219
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3220
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
M
Matthias Bolte 已提交
3221 3222 3223 3224
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
3225
        virReportOOMError();
M
Matthias Bolte 已提交
3226
        goto cleanup;
M
Matthias Bolte 已提交
3227 3228 3229 3230
    }

    url = virBufferContentAndReset(&buffer);

3231 3232 3233 3234 3235 3236
    /* Check, if VMX file already exists */
    /* FIXME */

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

3237
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0) {
3238 3239 3240 3241
        goto cleanup;
    }

    /* Register the domain */
M
Matthias Bolte 已提交
3242 3243
    if (directoryName != NULL) {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s/%s.vmx", datastoreName,
3244
                        directoryName, escapedName) < 0) {
3245
            virReportOOMError();
M
Matthias Bolte 已提交
3246
            goto cleanup;
M
Matthias Bolte 已提交
3247 3248 3249
        }
    } else {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s.vmx", datastoreName,
3250
                        escapedName) < 0) {
3251
            virReportOOMError();
M
Matthias Bolte 已提交
3252
            goto cleanup;
M
Matthias Bolte 已提交
3253 3254 3255
        }
    }

3256
    if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
M
Matthias Bolte 已提交
3257
                              datastoreRelatedPath, NULL, esxVI_Boolean_False,
3258 3259 3260 3261
                              priv->primary->computeResource->resourcePool,
                              priv->primary->hostSystem->_reference,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3262
                                    esxVI_Occurrence_OptionalItem,
3263
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3264
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3265
        goto cleanup;
M
Matthias Bolte 已提交
3266 3267 3268
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3269 3270
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3271
        goto cleanup;
M
Matthias Bolte 已提交
3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282
    }

    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 已提交
3283 3284 3285 3286
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

M
Matthias Bolte 已提交
3287 3288 3289 3290
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3291
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3292 3293 3294 3295 3296 3297 3298
    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);
3299
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3300 3301 3302 3303 3304 3305

    return domain;
}



3306
static int
3307 3308
esxDomainUndefineFlags(virDomainPtr domain,
                       unsigned int flags)
3309
{
M
Matthias Bolte 已提交
3310
    int result = -1;
M
Matthias Bolte 已提交
3311
    esxPrivate *priv = domain->conn->privateData;
3312
    esxVI_Context *ctx = NULL;
3313 3314 3315 3316
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3317 3318 3319 3320
    /* 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);
3321

3322 3323 3324 3325 3326 3327
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3328
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
3329
        return -1;
3330 3331
    }

3332
    if (esxVI_String_AppendValueToList(&propertyNameList,
3333
                                       "runtime.powerState") < 0 ||
3334 3335
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3336
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3337
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3338
        goto cleanup;
3339 3340 3341 3342
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3343 3344
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3345
        goto cleanup;
3346 3347
    }

3348
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
3349
        goto cleanup;
3350 3351
    }

M
Matthias Bolte 已提交
3352 3353
    result = 0;

3354 3355 3356 3357 3358 3359 3360 3361
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


3362 3363 3364 3365 3366
static int
esxDomainUndefine(virDomainPtr domain)
{
    return esxDomainUndefineFlags(domain, 0);
}
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 3396 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 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447
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;
3448
    bool newPowerInfo_isAppended = false;
3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486

    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)) {
3487 3488 3489
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("Cannot enable general autostart option "
                                     "without affecting other domains"));
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505
                    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 ||
3506
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0) {
3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
        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";

3518 3519 3520 3521 3522 3523 3524
    if (esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
                                              newPowerInfo) < 0) {
        goto cleanup;
    }

    newPowerInfo_isAppended = true;

3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545
    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);

3546 3547 3548 3549
    if (!newPowerInfo_isAppended) {
        esxVI_AutoStartPowerInfo_Free(&newPowerInfo);
    }

3550 3551 3552 3553 3554
    return result;
}



3555 3556 3557 3558 3559 3560 3561 3562 3563 3564
/*
 * 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:
 *
3565
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3566
 *
3567
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3568 3569
 *
 *
3570
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3571
 *
3572 3573
 *   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
3574 3575 3576 3577
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3578
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3579 3580 3581 3582 3583 3584
 *
 *   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'.
 */
3585
static char *
3586
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3587 3588 3589 3590
{
    char *type = strdup("allocation");

    if (type == NULL) {
3591
        virReportOOMError();
3592
        return NULL;
3593 3594
    }

3595 3596 3597
    if (nparams != NULL) {
        *nparams = 3; /* reservation, limit, shares */
    }
3598 3599 3600 3601 3602 3603 3604

    return type;
}



static int
3605 3606 3607
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int *nparams,
                                     unsigned int flags)
3608
{
M
Matthias Bolte 已提交
3609
    int result = -1;
M
Matthias Bolte 已提交
3610
    esxPrivate *priv = domain->conn->privateData;
3611 3612 3613 3614 3615 3616 3617
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    unsigned int mask = 0;
    int i = 0;

3618 3619
    virCheckFlags(0, -1);

3620
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3621
        return -1;
3622 3623
    }

3624
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3625 3626 3627
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3628
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3629
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3630
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3631
        goto cleanup;
3632 3633 3634
    }

    for (dynamicProperty = virtualMachine->propSet;
3635
         dynamicProperty != NULL && mask != 7 && i < 3 && i < *nparams;
3636 3637
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
M
Matthias Bolte 已提交
3638
            ! (mask & (1 << 0))) {
3639
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3640
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3641
                goto cleanup;
3642
            }
3643 3644 3645 3646 3647
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_RESERVATION,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3648 3649 3650 3651
            mask |= 1 << 0;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.limit") &&
M
Matthias Bolte 已提交
3652
                   ! (mask & (1 << 1))) {
3653
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3654
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3655
                goto cleanup;
3656
            }
3657 3658 3659 3660 3661
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_LIMIT,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3662 3663 3664 3665
            mask |= 1 << 1;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.shares") &&
M
Matthias Bolte 已提交
3666
                   ! (mask & (1 << 2))) {
3667 3668 3669 3670
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_SHARES,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
                goto cleanup;
3671
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3672
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3673
                goto cleanup;
3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693
            }

            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:
3694 3695 3696
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Shares level has unknown value %d"),
                               (int)sharesInfo->level);
M
Matthias Bolte 已提交
3697
                goto cleanup;
3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
            }

            esxVI_SharesInfo_Free(&sharesInfo);

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

    *nparams = i;
M
Matthias Bolte 已提交
3710
    result = 0;
3711 3712 3713 3714 3715 3716 3717 3718

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

    return result;
}

3719 3720 3721 3722 3723 3724
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3725 3726 3727


static int
3728 3729 3730
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3731
{
M
Matthias Bolte 已提交
3732
    int result = -1;
M
Matthias Bolte 已提交
3733
    esxPrivate *priv = domain->conn->privateData;
3734 3735 3736 3737 3738
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3739
    char *taskInfoErrorMessage = NULL;
3740 3741
    int i;

3742
    virCheckFlags(0, -1);
3743 3744 3745 3746 3747 3748 3749 3750 3751
    if (virTypedParameterArrayValidate(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)
        return -1;
3752

3753
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3754
        return -1;
3755 3756
    }

3757
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3758
          (priv->primary, domain->uuid, NULL, &virtualMachine,
3759
           priv->parsedUri->autoAnswer) < 0 ||
3760 3761
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
M
Matthias Bolte 已提交
3762
        goto cleanup;
3763 3764 3765
    }

    for (i = 0; i < nparams; ++i) {
3766
        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_RESERVATION)) {
3767
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0) {
M
Matthias Bolte 已提交
3768
                goto cleanup;
3769 3770 3771
            }

            if (params[i].value.l < 0) {
3772 3773 3774
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Could not set reservation to %lld MHz, expecting "
                                 "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3775
                goto cleanup;
3776 3777 3778
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
3779
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_LIMIT)) {
3780
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0) {
M
Matthias Bolte 已提交
3781
                goto cleanup;
3782 3783 3784
            }

            if (params[i].value.l < -1) {
3785 3786 3787 3788
                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 已提交
3789
                goto cleanup;
3790 3791 3792
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
3793
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_SHARES)) {
3794 3795
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3796
                goto cleanup;
3797 3798 3799 3800
            }

            spec->cpuAllocation->shares = sharesInfo;

3801
            if (params[i].value.i >= 0) {
3802
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3803
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3804
            } else {
3805
                switch (params[i].value.i) {
3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823
                  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:
3824 3825 3826 3827
                    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 已提交
3828
                    goto cleanup;
3829 3830 3831 3832 3833
                }
            }
        }
    }

3834
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3835
                              &task) < 0 ||
3836
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3837
                                    esxVI_Occurrence_RequiredItem,
3838
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3839
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3840
        goto cleanup;
3841 3842 3843
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3844 3845 3846
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change scheduler parameters: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3847
        goto cleanup;
3848 3849
    }

M
Matthias Bolte 已提交
3850 3851
    result = 0;

3852 3853 3854 3855
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3856
    VIR_FREE(taskInfoErrorMessage);
3857 3858 3859 3860

    return result;
}

3861 3862 3863 3864 3865 3866
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3867

E
Eric Blake 已提交
3868 3869 3870 3871 3872 3873
/* 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)
3874 3875 3876 3877 3878

static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3879 3880
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
E
Eric Blake 已提交
3881
                        unsigned long flags,
3882 3883 3884
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3885
    esxPrivate *priv = dconn->privateData;
3886

E
Eric Blake 已提交
3887 3888
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3889
    if (uri_in == NULL) {
3890 3891 3892 3893
        if (virAsprintf(uri_out, "vpxmigr://%s/%s/%s",
                        priv->vCenter->ipAddress,
                        priv->vCenter->computeResource->resourcePool->value,
                        priv->vCenter->hostSystem->_reference->value) < 0) {
3894
            virReportOOMError();
3895
            return -1;
3896 3897 3898
        }
    }

3899
    return 0;
3900 3901 3902 3903 3904 3905 3906 3907 3908
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
E
Eric Blake 已提交
3909
                        unsigned long flags,
3910 3911 3912
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3913
    int result = -1;
M
Matthias Bolte 已提交
3914
    esxPrivate *priv = domain->conn->privateData;
M
Martin Kletzander 已提交
3915
    virURIPtr parsedUri = NULL;
3916 3917 3918
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3919
    esxVI_ObjectContent *virtualMachine = NULL;
3920 3921
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3922 3923 3924
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3925
    char *taskInfoErrorMessage = NULL;
3926

E
Eric Blake 已提交
3927 3928
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

M
Matthias Bolte 已提交
3929
    if (priv->vCenter == NULL) {
3930 3931
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration not possible without a vCenter"));
M
Matthias Bolte 已提交
3932
        return -1;
3933 3934 3935
    }

    if (dname != NULL) {
3936 3937
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Renaming domains on migration not supported"));
M
Matthias Bolte 已提交
3938
        return -1;
3939 3940
    }

3941
    if (esxVI_EnsureSession(priv->vCenter) < 0) {
M
Matthias Bolte 已提交
3942
        return -1;
3943 3944
    }

3945
    /* Parse migration URI */
3946
    if (!(parsedUri = virURIParse(uri)))
M
Matthias Bolte 已提交
3947
        return -1;
3948

3949
    if (parsedUri->scheme == NULL || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
3950 3951
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3952
        goto cleanup;
3953 3954
    }

3955
    if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
3956 3957 3958
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration source and destination have to refer to "
                         "the same vCenter"));
3959 3960 3961 3962 3963 3964 3965
        goto cleanup;
    }

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

    if (path_resourcePool == NULL || path_hostSystem == NULL) {
3966 3967
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration URI has to specify resource pool and host system"));
M
Matthias Bolte 已提交
3968
        goto cleanup;
3969 3970
    }

3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983
    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,
3984
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
3985
        goto cleanup;
3986 3987 3988
    }

    /* Validate the purposed migration */
3989
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3990 3991
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
3992
        goto cleanup;
3993 3994 3995 3996 3997 3998 3999 4000
    }

    if (eventList != NULL) {
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
        if (eventList->fullFormattedMessage != NULL) {
4001 4002 4003
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not migrate domain, validation reported a "
                             "problem: %s"), eventList->fullFormattedMessage);
4004
        } else {
4005 4006 4007
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not migrate domain, validation reported a "
                             "problem"));
4008 4009
        }

M
Matthias Bolte 已提交
4010
        goto cleanup;
4011 4012 4013
    }

    /* Perform the purposed migration */
4014 4015
    if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
                             &resourcePool, &hostSystem,
4016 4017 4018
                             esxVI_VirtualMachineMovePriority_DefaultPriority,
                             esxVI_VirtualMachinePowerState_Undefined,
                             &task) < 0 ||
4019
        esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
4020
                                    esxVI_Occurrence_RequiredItem,
4021
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4022
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4023
        goto cleanup;
4024 4025 4026
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4027 4028 4029 4030
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not migrate domain, migration task finished with "
                         "an error: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4031
        goto cleanup;
4032 4033
    }

M
Matthias Bolte 已提交
4034 4035
    result = 0;

4036
  cleanup:
4037
    virURIFree(parsedUri);
4038 4039 4040
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
4041
    VIR_FREE(taskInfoErrorMessage);
4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052

    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 已提交
4053
                       unsigned long flags)
4054
{
E
Eric Blake 已提交
4055 4056
    virCheckFlags(ESX_MIGRATION_FLAGS, NULL);

4057 4058 4059 4060 4061
    return esxDomainLookupByName(dconn, dname);
}



M
Matthias Bolte 已提交
4062 4063 4064 4065
static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)
{
    unsigned long long result = 0;
M
Matthias Bolte 已提交
4066
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
4067 4068 4069 4070 4071
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *resourcePool = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_ResourcePoolResourceUsage *resourcePoolResourceUsage = NULL;

4072
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4073
        return 0;
M
Matthias Bolte 已提交
4074 4075 4076
    }

    /* Get memory usage of resource pool */
4077
    if (esxVI_String_AppendValueToList(&propertyNameList,
M
Matthias Bolte 已提交
4078
                                       "runtime.memory") < 0 ||
4079 4080
        esxVI_LookupObjectContentByType(priv->primary,
                                        priv->primary->computeResource->resourcePool,
4081
                                        "ResourcePool", propertyNameList,
4082 4083
                                        &resourcePool,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4084
        goto cleanup;
M
Matthias Bolte 已提交
4085 4086 4087 4088 4089 4090
    }

    for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.memory")) {
            if (esxVI_ResourcePoolResourceUsage_CastFromAnyType
4091
                  (dynamicProperty->val, &resourcePoolResourceUsage) < 0) {
M
Matthias Bolte 已提交
4092
                goto cleanup;
M
Matthias Bolte 已提交
4093 4094 4095 4096 4097 4098 4099 4100 4101
            }

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

    if (resourcePoolResourceUsage == NULL) {
4102 4103
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not retrieve memory usage of resource pool"));
M
Matthias Bolte 已提交
4104
        goto cleanup;
M
Matthias Bolte 已提交
4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118
    }

    result = resourcePoolResourceUsage->unreservedForVm->value;

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

    return result;
}



4119 4120 4121
static int
esxIsEncrypted(virConnectPtr conn)
{
M
Matthias Bolte 已提交
4122
    esxPrivate *priv = conn->privateData;
4123

4124
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135
        return 1;
    } else {
        return 0;
    }
}



static int
esxIsSecure(virConnectPtr conn)
{
M
Matthias Bolte 已提交
4136
    esxPrivate *priv = conn->privateData;
4137

4138
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4139 4140 4141 4142 4143 4144 4145 4146
        return 1;
    } else {
        return 0;
    }
}



4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163
static int
esxIsAlive(virConnectPtr conn)
{
    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;
}



4164 4165 4166
static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4167
    int result = -1;
M
Matthias Bolte 已提交
4168
    esxPrivate *priv = domain->conn->privateData;
4169 4170 4171 4172
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4173
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4174
        return -1;
4175 4176
    }

4177
    if (esxVI_String_AppendValueToList(&propertyNameList,
4178
                                       "runtime.powerState") < 0 ||
4179
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4180
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4181
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4182
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4183
        goto cleanup;
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201
    }

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

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

    return result;
}



static int
4202
esxDomainIsPersistent(virDomainPtr domain)
4203
{
4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223
    /* 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;
4224 4225
}

M
Matthias Bolte 已提交
4226 4227


4228 4229 4230
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250
    /* 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;
4251
}
4252

M
Matthias Bolte 已提交
4253 4254


4255 4256
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4257
                           unsigned int flags)
4258 4259 4260 4261 4262 4263 4264 4265
{
    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;
4266
    char *taskInfoErrorMessage = NULL;
4267 4268
    virDomainSnapshotPtr snapshot = NULL;

4269 4270
    /* ESX has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
4271

4272
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4273
        return NULL;
4274 4275
    }

4276
    def = virDomainSnapshotDefParseString(xmlDesc, NULL, 0, 0);
4277 4278

    if (def == NULL) {
M
Matthias Bolte 已提交
4279
        return NULL;
4280 4281
    }

4282
    if (def->ndisks) {
4283 4284
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
4285 4286 4287
        return NULL;
    }

4288
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4289
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4290
           priv->parsedUri->autoAnswer) < 0 ||
4291
        esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4292 4293
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
4294
                                    &snapshotTree, NULL,
4295
                                    esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4296
        goto cleanup;
4297 4298 4299
    }

    if (snapshotTree != NULL) {
4300 4301
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Snapshot '%s' already exists"), def->name);
M
Matthias Bolte 已提交
4302
        goto cleanup;
4303 4304
    }

4305
    if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4306 4307 4308
                                  def->name, def->description,
                                  esxVI_Boolean_True,
                                  esxVI_Boolean_False, &task) < 0 ||
4309
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4310
                                    esxVI_Occurrence_RequiredItem,
4311
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4312
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4313
        goto cleanup;
4314 4315 4316
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4317 4318
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4319
        goto cleanup;
4320 4321 4322 4323 4324 4325 4326 4327 4328
    }

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

  cleanup:
    virDomainSnapshotDefFree(def);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4329
    VIR_FREE(taskInfoErrorMessage);
4330 4331 4332 4333 4334 4335 4336

    return snapshot;
}



static char *
4337 4338
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4339 4340 4341 4342 4343 4344 4345 4346 4347
{
    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;

4348 4349
    virCheckFlags(0, NULL);

4350
    memset(&def, 0, sizeof(def));
4351

4352
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4353
        return NULL;
4354 4355
    }

4356
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4357 4358 4359 4360
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4361
        goto cleanup;
4362 4363 4364 4365 4366 4367 4368 4369
    }

    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 已提交
4370
        goto cleanup;
4371 4372 4373 4374 4375 4376 4377
    }

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

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

4378
    xml = virDomainSnapshotDefFormat(uuid_string, &def, flags, 0);
4379 4380 4381 4382 4383 4384 4385 4386 4387 4388

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



static int
4389
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4390
{
M
Matthias Bolte 已提交
4391
    int count;
4392 4393
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4394
    bool recurse;
4395
    bool leaves;
4396

4397
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4398 4399
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4400 4401

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4402
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4403

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

4408 4409 4410 4411
    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)
        return 0;

4412
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4413
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4414
        return -1;
4415 4416
    }

4417 4418
    count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList, recurse,
                                           leaves);
4419 4420 4421

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

M
Matthias Bolte 已提交
4422
    return count;
4423 4424 4425 4426 4427 4428
}



static int
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4429
                           unsigned int flags)
4430
{
M
Matthias Bolte 已提交
4431
    int result;
4432 4433
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4434
    bool recurse;
4435
    bool leaves;
4436 4437

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4438 4439
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4440

4441
    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4442
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4443

4444
    if (names == NULL || nameslen < 0) {
4445
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4446 4447 4448
        return -1;
    }

4449
    if (nameslen == 0 || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)) {
4450 4451 4452
        return 0;
    }

4453
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4454
        return -1;
4455 4456
    }

4457
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4458
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4459
        return -1;
4460 4461
    }

4462
    result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen,
4463
                                        recurse, leaves);
4464 4465 4466 4467 4468 4469 4470 4471

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4472 4473 4474 4475 4476 4477 4478 4479
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;
4480
    bool leaves;
4481 4482

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

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4487
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507

    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,
4508
                                           recurse, leaves);
4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527

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;
4528
    bool leaves;
4529 4530

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4531 4532
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4533 4534

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4535
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4536 4537

    if (names == NULL || nameslen < 0) {
4538
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564
        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,
4565
                                        names, nameslen, recurse, leaves);
4566 4567 4568 4569 4570 4571 4572 4573 4574

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4575 4576
static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4577
                              unsigned int flags)
4578 4579 4580 4581 4582 4583
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    virDomainSnapshotPtr snapshot = NULL;

4584 4585
    virCheckFlags(0, NULL);

4586
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4587
        return NULL;
4588 4589
    }

4590
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4591 4592
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
4593
                                    NULL,
4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613
                                    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;

4614
    virCheckFlags(0, -1);
4615

4616
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4617
        return -1;
4618 4619
    }

4620
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4621 4622
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4623
        return -1;
4624 4625 4626
    }

    if (currentSnapshotTree != NULL) {
M
Matthias Bolte 已提交
4627 4628
        esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
        return 1;
4629 4630
    }

M
Matthias Bolte 已提交
4631
    return 0;
4632 4633 4634 4635
}



E
Eric Blake 已提交
4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659
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) {
4660 4661 4662
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshotTree->name);
E
Eric Blake 已提交
4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675
        goto cleanup;
    }

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



4676 4677 4678 4679 4680
static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
M
Matthias Bolte 已提交
4681
    virDomainSnapshotPtr snapshot = NULL;
4682

4683
    virCheckFlags(0, NULL);
4684

4685
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4686
        return NULL;
4687 4688
    }

4689
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4690 4691
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4692
        return NULL;
4693 4694 4695 4696 4697 4698 4699 4700 4701 4702
    }

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}


4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771
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;
}

4772 4773 4774 4775

static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4776
    int result = -1;
4777 4778 4779 4780 4781
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4782
    char *taskInfoErrorMessage = NULL;
4783

4784
    virCheckFlags(0, -1);
4785

4786
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4787
        return -1;
4788 4789
    }

4790
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4791 4792
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4793
                                    &snapshotTree, NULL,
4794
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4795
        goto cleanup;
4796 4797
    }

4798
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4799
                                    esxVI_Boolean_Undefined, &task) < 0 ||
4800
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4801
                                    esxVI_Occurrence_RequiredItem,
4802
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4803
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4804
        goto cleanup;
4805 4806 4807
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4808 4809 4810
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not revert to snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4811
        goto cleanup;
4812 4813
    }

M
Matthias Bolte 已提交
4814 4815
    result = 0;

4816 4817 4818
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4819
    VIR_FREE(taskInfoErrorMessage);
4820 4821 4822 4823 4824 4825 4826 4827 4828

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4829
    int result = -1;
4830 4831 4832 4833 4834 4835
    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;
4836
    char *taskInfoErrorMessage = NULL;
4837

4838 4839
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4840

4841
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4842
        return -1;
4843 4844 4845 4846 4847 4848
    }

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

4849
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4850 4851
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4852
                                    &snapshotTree, NULL,
4853
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4854
        goto cleanup;
4855 4856
    }

4857 4858 4859 4860 4861 4862 4863
    /* 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;
    }

4864
    if (esxVI_RemoveSnapshot_Task(priv->primary, snapshotTree->snapshot,
4865
                                  removeChildren, &task) < 0 ||
4866
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4867
                                    esxVI_Occurrence_RequiredItem,
4868
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4869
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4870
        goto cleanup;
4871 4872 4873
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4874 4875 4876
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not delete snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4877
        goto cleanup;
4878 4879
    }

M
Matthias Bolte 已提交
4880 4881
    result = 0;

4882 4883 4884
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4885
    VIR_FREE(taskInfoErrorMessage);
4886 4887 4888 4889 4890 4891

    return result;
}



4892
static int
4893
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4894 4895 4896 4897 4898 4899 4900 4901
                             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;
4902
    char *taskInfoErrorMessage = NULL;
4903 4904 4905
    int i;

    virCheckFlags(0, -1);
4906 4907 4908 4909 4910
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
4911 4912 4913 4914 4915 4916 4917

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

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4918
           priv->parsedUri->autoAnswer) < 0 ||
4919 4920 4921 4922 4923 4924
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
        goto cleanup;
    }

    for (i = 0; i < nparams; ++i) {
4925
        if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
4926 4927 4928 4929 4930
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) {
                goto cleanup;
            }

            spec->memoryAllocation->reservation->value =
4931
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4932 4933 4934 4935 4936 4937 4938
        }
    }

    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
4939
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4940
                                    &taskInfoErrorMessage) < 0) {
4941 4942 4943 4944
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4945 4946 4947
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change memory parameters: %s"),
                       taskInfoErrorMessage);
4948 4949 4950 4951 4952 4953 4954 4955 4956
        goto cleanup;
    }

    result = 0;

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4957
    VIR_FREE(taskInfoErrorMessage);
4958 4959 4960 4961 4962 4963 4964

    return result;
}



static int
4965
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994
                             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;
    }

4995 4996 4997 4998
    /* Scale from megabytes to kilobytes */
    if (virTypedParameterAssign(params, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                VIR_TYPED_PARAM_ULLONG,
                                reservation->value * 1024) < 0)
4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011
        goto cleanup;

    *nparams = 1;
    result = 0;

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

    return result;
}

5012 5013 5014 5015 5016 5017 5018 5019
#define MATCH(FLAG) (flags & (FLAG))
static int
esxListAllDomains(virConnectPtr conn,
                  virDomainPtr **domains,
                  unsigned int flags)
{
    int ret = -1;
    esxPrivate *priv = conn->privateData;
5020 5021
    bool needIdentity;
    bool needPowerState;
5022 5023 5024
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    size_t ndoms = 0;
5025
    esxVI_String *propertyNameList = NULL;
5026 5027
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
5028
    esxVI_AutoStartDefaults *autoStartDefaults = NULL;
5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045
    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
     */
5046
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057
         !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)
            goto no_memory;

        ret = 0;
        goto cleanup;
    }

5058
    if (esxVI_EnsureSession(priv->primary) < 0)
5059 5060 5061 5062 5063
        return -1;

    /* check system default autostart value */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
        if (esxVI_LookupAutoStartDefaults(priv->primary,
5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084
                                          &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) {
5085
            goto cleanup;
5086 5087 5088 5089 5090 5091
        }
    }

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

5093 5094 5095
    if (needPowerState) {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "runtime.powerState") < 0) {
5096
            goto cleanup;
5097
        }
5098 5099
    }

5100
    if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111
                                       &virtualMachineList) < 0)
        goto cleanup;

    if (domains) {
        if (VIR_ALLOC_N(doms, 1) < 0)
            goto no_memory;
        ndoms = 1;
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
5112 5113
        if (needIdentity) {
            VIR_FREE(name);
5114

5115 5116 5117 5118 5119
            if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id,
                                                &name, uuid) < 0) {
                goto cleanup;
            }
        }
5120

5121 5122 5123 5124 5125 5126
        if (needPowerState) {
            if (esxVI_GetVirtualMachinePowerState(virtualMachine,
                                                  &powerState) < 0) {
                goto cleanup;
            }
        }
5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137

        /* 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)) {
5138 5139
            esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5140 5141 5142 5143 5144 5145
            if (esxVI_LookupRootSnapshotTreeList(priv->primary, uuid,
                                                 &rootSnapshotTreeList) < 0) {
                goto cleanup;
            }

            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
5146
                   rootSnapshotTreeList != NULL) ||
5147
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
5148
                   rootSnapshotTreeList == NULL)))
5149 5150 5151 5152 5153 5154 5155
                continue;
        }

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

5156 5157 5158 5159 5160 5161
            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;
5162

5163 5164
                        break;
                    }
5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177
                }
            }

            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);
5178

5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197
            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;
        }

5198
        if (VIR_RESIZE_N(doms, ndoms, count, 2) < 0)
5199 5200
            goto no_memory;

5201 5202 5203
        if (!(dom = virGetDomain(conn, name, uuid)))
            goto cleanup;

5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220
        /* 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++) {
5221
            virDomainFree(doms[id]);
5222
        }
5223 5224

        VIR_FREE(doms);
5225
    }
5226

5227
    VIR_FREE(name);
5228 5229
    esxVI_AutoStartDefaults_Free(&autoStartDefaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);
5230 5231
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
5232 5233
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5234 5235 5236 5237 5238 5239 5240
    return ret;

no_memory:
    virReportOOMError();
    goto cleanup;
}
#undef MATCH
5241 5242


5243
static virDriver esxDriver = {
5244 5245
    .no = VIR_DRV_ESX,
    .name = "ESX",
5246 5247 5248 5249 5250 5251 5252 5253 5254 5255
    .open = esxOpen, /* 0.7.0 */
    .close = esxClose, /* 0.7.0 */
    .supports_feature = esxSupportsFeature, /* 0.7.0 */
    .type = esxGetType, /* 0.7.0 */
    .version = esxGetVersion, /* 0.7.0 */
    .getHostname = esxGetHostname, /* 0.7.0 */
    .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
    .getCapabilities = esxGetCapabilities, /* 0.7.1 */
    .listDomains = esxListDomains, /* 0.7.0 */
    .numOfDomains = esxNumberOfDomains, /* 0.7.0 */
5256
    .listAllDomains = esxListAllDomains, /* 0.10.2 */
5257 5258 5259 5260 5261 5262
    .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 */
5263
    .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
5264 5265
    .domainReboot = esxDomainReboot, /* 0.7.0 */
    .domainDestroy = esxDomainDestroy, /* 0.7.0 */
5266
    .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287
    .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 */
    .domainXMLFromNative = esxDomainXMLFromNative, /* 0.7.0 */
    .domainXMLToNative = esxDomainXMLToNative, /* 0.7.2 */
    .listDefinedDomains = esxListDefinedDomains, /* 0.7.0 */
    .numOfDefinedDomains = esxNumberOfDefinedDomains, /* 0.7.0 */
    .domainCreate = esxDomainCreate, /* 0.7.0 */
    .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
    .domainUndefine = esxDomainUndefine, /* 0.7.1 */
5288
    .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
5289 5290 5291 5292
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
5293
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
5294
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
5295
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308
    .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
    .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
    .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
    .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
    .isEncrypted = esxIsEncrypted, /* 0.7.3 */
    .isSecure = esxIsSecure, /* 0.7.3 */
    .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 */
5309 5310
    .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
5311 5312
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
E
Eric Blake 已提交
5313
    .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
5314 5315
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
5316 5317
    .domainSnapshotIsCurrent = esxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = esxDomainSnapshotHasMetadata, /* 0.9.13 */
5318
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
5319
    .isAlive = esxIsAlive, /* 0.9.8 */
5320 5321 5322 5323 5324 5325 5326
};



int
esxRegister(void)
{
5327 5328 5329 5330 5331
    if (virRegisterDriver(&esxDriver) < 0 ||
        esxInterfaceRegister() < 0 ||
        esxNetworkRegister() < 0 ||
        esxStorageRegister() < 0 ||
        esxDeviceRegister() < 0 ||
M
Matthias Bolte 已提交
5332 5333
        esxSecretRegister() < 0 ||
        esxNWFilterRegister() < 0) {
5334 5335
        return -1;
    }
5336 5337 5338

    return 0;
}