esx_driver.c 169.7 KB
Newer Older
1 2

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

#include <config.h>

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

#define VIR_FROM_THIS VIR_FROM_ESX

static int esxDomainGetMaxVcpus(virDomainPtr domain);

55 56 57 58
typedef struct _esxVMX_Data esxVMX_Data;

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



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

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



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

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

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

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

175
            tmp = (char *)STRSKIP(fileName, hostMount->mountInfo->path);
176

177 178 179
            if (tmp == NULL) {
                continue;
            }
180

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

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

190
            tmp = strippedFileName;
191

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

198 199
                ++tmp;
            }
200

201
            if (virAsprintf(&result, "[%s] %s", datastoreName,
202 203 204 205
                            strippedFileName) < 0) {
                virReportOOMError();
                goto cleanup;
            }
206

207 208
            break;
        }
209

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

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

226
            esxVI_ObjectContent_Free(&datastoreList);
227

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

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

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

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

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

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

270
    return result;
271 272 273 274
}



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

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

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

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

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

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

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

333 334
        if (separator != '/') {
            tmp = directoryAndFileName;
335

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

341 342
                ++tmp;
            }
343
        }
344

345 346
        virBufferAddChar(&buffer, separator);
        virBufferAdd(&buffer, directoryAndFileName, -1);
347

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

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

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

    success = true;

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

    VIR_FREE(datastoreName);
376
    VIR_FREE(directoryAndFileName);
377 378
    esxVI_ObjectContent_Free(&datastore);
    esxVI_DatastoreHostMount_Free(&hostMount);
379

380
    return result;
381 382 383 384 385 386 387 388 389 390
}



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

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

412
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
413 414

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

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

    result = 0;

  cleanup:
442
    esxVI_FileInfo_Free(&fileInfo);
443 444 445 446

    return result;
}

447 448


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

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

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

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

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

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

491
                    edxLongModeBit = parsedHostCpuIdInfo.edx[29];
492 493 494 495 496 497

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

                    break;
                }
            }

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

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

    return priv->supportsLongMode;
}



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

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

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

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

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

    result = 0;

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

    return result;
}


573
static virCapsPtr
574
esxCapsInit(esxPrivate *priv)
575
{
576
    esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
577 578 579
    virCapsPtr caps = NULL;
    virCapsGuestPtr guest = NULL;

580 581 582 583 584
    if (supportsLongMode == esxVI_Boolean_Undefined) {
        return NULL;
    }

    if (supportsLongMode == esxVI_Boolean_True) {
585
        caps = virCapabilitiesNew(VIR_ARCH_X86_64, 1, 1);
586
    } else {
587
        caps = virCapabilitiesNew(VIR_ARCH_I686, 1, 1);
588
    }
589 590

    if (caps == NULL) {
591
        virReportOOMError();
592 593 594
        return NULL;
    }

595
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
596

597

598 599 600 601
    if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0) {
        goto failure;
    }

602
    /* i686 */
603 604 605
    guest = virCapabilitiesAddGuest(caps, "hvm",
                                    VIR_ARCH_I686,
                                    NULL, NULL, 0,
606
                                    NULL);
607 608 609 610 611 612 613 614 615 616

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

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

617 618
    /* x86_64 */
    if (supportsLongMode == esxVI_Boolean_True) {
619 620 621
        guest = virCapabilitiesAddGuest(caps, "hvm",
                                        VIR_ARCH_X86_64,
                                        NULL, NULL,
622 623 624 625 626 627 628 629 630 631 632 633
                                        0, NULL);

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

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

634 635 636
    return caps;

  failure:
637
    virObjectUnref(caps);
638 639 640 641 642 643

    return NULL;
}



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

    if (vCenterIpAddress == NULL || *vCenterIpAddress != NULL) {
664
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
665 666 667
        return -1;
    }

668
    if (esxUtil_ResolveHostname(conn->uri->server, ipAddress, NI_MAXHOST) < 0) {
669 670 671
        return -1;
    }

672
    if (conn->uri->user != NULL) {
673
        if (VIR_STRDUP(username, conn->uri->user) < 0)
674 675
            goto cleanup;
    } else {
676
        username = virAuthGetUsername(conn, auth, "esx", "root", conn->uri->server);
677 678

        if (username == NULL) {
679
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
680 681 682 683
            goto cleanup;
        }
    }

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

M
Matthias Bolte 已提交
686
    if (unescapedPassword == NULL) {
687
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
688 689 690
        goto cleanup;
    }

M
Matthias Bolte 已提交
691 692 693 694 695 696
    password = esxUtil_EscapeForXml(unescapedPassword);

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

697
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
698
                    conn->uri->server, conn->uri->port) < 0) {
699 700 701 702 703 704
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->host) < 0 ||
        esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
705
                              priv->parsedUri) < 0 ||
706
        esxVI_Context_LookupManagedObjects(priv->host) < 0) {
707 708 709 710 711
        goto cleanup;
    }

    if (expectedProductVersion == esxVI_ProductVersion_ESX) {
        if (priv->host->productVersion != esxVI_ProductVersion_ESX35 &&
M
Matthias Bolte 已提交
712 713
            priv->host->productVersion != esxVI_ProductVersion_ESX40 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX41 &&
P
Patrice LACHANCE 已提交
714 715
            priv->host->productVersion != esxVI_ProductVersion_ESX4x &&
            priv->host->productVersion != esxVI_ProductVersion_ESX50 &&
M
Martin Kletzander 已提交
716
            priv->host->productVersion != esxVI_ProductVersion_ESX51 &&
P
Patrice LACHANCE 已提交
717
            priv->host->productVersion != esxVI_ProductVersion_ESX5x) {
718 719 720
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s is neither an ESX 3.5, 4.x nor 5.x host"),
                           conn->uri->server);
721 722 723 724
            goto cleanup;
        }
    } else { /* GSX */
        if (priv->host->productVersion != esxVI_ProductVersion_GSX20) {
725 726
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s isn't a GSX 2.0 host"), conn->uri->server);
727 728 729 730 731 732 733 734
            goto cleanup;
        }
    }

    /* Query the host for maintenance mode and vCenter IP address */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "runtime.inMaintenanceMode\0"
                                           "summary.managementServerIp\0") < 0 ||
735 736
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
737 738 739 740 741 742 743 744 745 746 747
        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) {
748
        VIR_WARN("The server is in maintenance mode");
749 750
    }

751 752
    if (VIR_STRDUP(*vCenterIpAddress, *vCenterIpAddress) < 0)
        goto cleanup;
753 754 755 756 757

    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
758 759
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
760 761 762 763 764 765 766 767 768 769
    VIR_FREE(url);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



static int
770 771
esxConnectToVCenter(esxPrivate *priv,
                    virConnectPtr conn,
772 773
                    virConnectAuthPtr auth,
                    const char *hostname,
774
                    const char *hostSystemIpAddress)
775 776 777 778
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
779
    char *unescapedPassword = NULL;
780 781 782
    char *password = NULL;
    char *url = NULL;

783
    if (hostSystemIpAddress == NULL &&
784
        (priv->parsedUri->path == NULL || STREQ(priv->parsedUri->path, "/"))) {
785 786
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Path has to specify the datacenter and compute resource"));
787 788 789
        return -1;
    }

790 791 792 793
    if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST) < 0) {
        return -1;
    }

794
    if (conn->uri->user != NULL) {
795
        if (VIR_STRDUP(username, conn->uri->user) < 0) {
796 797 798
            goto cleanup;
        }
    } else {
799
        username = virAuthGetUsername(conn, auth, "esx", "administrator", hostname);
800 801

        if (username == NULL) {
802
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
803 804 805 806
            goto cleanup;
        }
    }

807
    unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, hostname);
808

M
Matthias Bolte 已提交
809
    if (unescapedPassword == NULL) {
810
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
811 812 813
        goto cleanup;
    }

M
Matthias Bolte 已提交
814 815 816 817 818 819
    password = esxUtil_EscapeForXml(unescapedPassword);

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

820
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
821
                    hostname, conn->uri->port) < 0) {
822 823 824 825 826 827
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
        esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
828
                              password, priv->parsedUri) < 0) {
829 830 831 832
        goto cleanup;
    }

    if (priv->vCenter->productVersion != esxVI_ProductVersion_VPX25 &&
M
Matthias Bolte 已提交
833 834
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX40 &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX41 &&
P
Patrice LACHANCE 已提交
835 836
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX4x &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX50 &&
M
Martin Kletzander 已提交
837
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX51 &&
P
Patrice LACHANCE 已提交
838
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX5x) {
839 840 841
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s is neither a vCenter 2.5, 4.x nor 5.x server"),
                       hostname);
842 843 844
        goto cleanup;
    }

845
    if (hostSystemIpAddress != NULL) {
846 847
        if (esxVI_Context_LookupManagedObjectsByHostSystemIp
              (priv->vCenter, hostSystemIpAddress) < 0) {
848 849 850
            goto cleanup;
        }
    } else {
851 852
        if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter,
                                                     priv->parsedUri->path) < 0) {
853 854 855 856
            goto cleanup;
        }
    }

857 858 859 860
    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
861 862
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
863 864 865 866 867 868 869
    VIR_FREE(url);

    return result;
}



870
/*
871 872
 * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
 *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
873
 *
874 875
 * If no port is specified the default port is set dependent on the scheme and
 * transport parameter:
876 877
 * - vpx+http  80
 * - vpx+https 443
878
 * - esx+http  80
879
 * - esx+https 443
880 881 882
 * - gsx+http  8222
 * - gsx+https 8333
 *
883 884 885
 * 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
886 887
 * can be omitted. As datacenters and computeresources can be organized in
 * folders those have to be included in <path>.
888
 *
889 890
 * Optional query parameters:
 * - transport={http|https}
891
 * - vcenter={<vcenter>|*}             only useful for an esx:// connection
892 893
 * - no_verify={0|1}
 * - auto_answer={0|1}
M
Matthias Bolte 已提交
894
 * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
895
 *
896 897 898
 * If no transport parameter is specified https is used.
 *
 * The vcenter parameter is only necessary for migration, because the vCenter
899
 * server is in charge to initiate a migration between two ESX hosts. The
900
 * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
901 902
 * 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.
903 904
 *
 * If the no_verify parameter is set to 1, this disables libcurl client checks
905
 * of the server's certificate. The default value it 0.
906 907 908 909
 *
 * 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 已提交
910 911 912 913
 *
 * 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.
914 915
 */
static virDrvOpenStatus
916 917
esxConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
               unsigned int flags)
918
{
M
Matthias Bolte 已提交
919
    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
920
    char *plus;
921
    esxPrivate *priv = NULL;
922
    char *potentialVCenterIpAddress = NULL;
M
Matthias Bolte 已提交
923
    char vCenterIpAddress[NI_MAXHOST] = "";
924

E
Eric Blake 已提交
925 926
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

927 928
    /* Decline if the URI is NULL or the scheme is NULL */
    if (conn->uri == NULL || conn->uri->scheme == NULL) {
929 930 931
        return VIR_DRV_OPEN_DECLINED;
    }

932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
    /* 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;
        }

949 950 951
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Transport '%s' in URI scheme is not supported, try again "
                         "without the transport part"), plus + 1);
952 953 954
        return VIR_DRV_OPEN_ERROR;
    }

955 956 957 958 959 960
    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);
    }

961 962
    /* Require server part */
    if (conn->uri->server == NULL) {
963 964
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("URI is missing the server part"));
965 966 967 968 969
        return VIR_DRV_OPEN_ERROR;
    }

    /* Require auth */
    if (auth == NULL || auth->cb == NULL) {
970 971
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Missing or invalid auth pointer"));
972
        return VIR_DRV_OPEN_ERROR;
973 974 975 976
    }

    /* Allocate per-connection private data */
    if (VIR_ALLOC(priv) < 0) {
977
        virReportOOMError();
M
Matthias Bolte 已提交
978
        goto cleanup;
979 980
    }

981
    if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0) {
982 983 984
        goto cleanup;
    }

M
Matthias Bolte 已提交
985 986
    priv->maxVcpus = -1;
    priv->supportsVMotion = esxVI_Boolean_Undefined;
987
    priv->supportsLongMode = esxVI_Boolean_Undefined;
988 989
    priv->usedCpuTimeCounterId = -1;

M
Matthias Bolte 已提交
990 991 992 993 994 995 996
    /*
     * 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) {
997 998
        if (STRCASEEQ(conn->uri->scheme, "vpx") ||
            STRCASEEQ(conn->uri->scheme, "esx")) {
999
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
1000 1001 1002 1003 1004
                conn->uri->port = 443;
            } else {
                conn->uri->port = 80;
            }
        } else { /* GSX */
1005
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
1006 1007 1008 1009
                conn->uri->port = 8333;
            } else {
                conn->uri->port = 8222;
            }
1010
        }
M
Matthias Bolte 已提交
1011
    }
1012

1013 1014 1015
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
1016
        if (esxConnectToHost(priv, conn, auth,
1017
                             &potentialVCenterIpAddress) < 0) {
M
Matthias Bolte 已提交
1018
            goto cleanup;
1019
        }
1020

1021
        /* Connect to vCenter */
1022 1023
        if (priv->parsedUri->vCenter != NULL) {
            if (STREQ(priv->parsedUri->vCenter, "*")) {
1024
                if (potentialVCenterIpAddress == NULL) {
1025 1026
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("This host is not managed by a vCenter"));
M
Matthias Bolte 已提交
1027
                    goto cleanup;
1028 1029
                }

1030 1031
                if (virStrcpyStatic(vCenterIpAddress,
                                    potentialVCenterIpAddress) == NULL) {
1032 1033 1034
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("vCenter IP address %s too big for destination"),
                                   potentialVCenterIpAddress);
1035 1036 1037
                    goto cleanup;
                }
            } else {
1038
                if (esxUtil_ResolveHostname(priv->parsedUri->vCenter,
1039 1040 1041
                                            vCenterIpAddress, NI_MAXHOST) < 0) {
                    goto cleanup;
                }
1042

1043 1044
                if (potentialVCenterIpAddress != NULL &&
                    STRNEQ(vCenterIpAddress, potentialVCenterIpAddress)) {
1045 1046 1047 1048 1049 1050
                    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 已提交
1051
                    goto cleanup;
1052 1053
                }
            }
1054

1055
            if (esxConnectToVCenter(priv, conn, auth,
1056
                                    vCenterIpAddress,
1057
                                    priv->host->ipAddress) < 0) {
1058 1059
                goto cleanup;
            }
1060 1061
        }

1062 1063 1064
        priv->primary = priv->host;
    } else { /* VPX */
        /* Connect to vCenter */
1065
        if (esxConnectToVCenter(priv, conn, auth,
1066 1067
                                conn->uri->server,
                                NULL) < 0) {
M
Matthias Bolte 已提交
1068
            goto cleanup;
1069 1070
        }

1071
        priv->primary = priv->vCenter;
1072 1073
    }

M
Matthias Bolte 已提交
1074
    /* Setup capabilities */
1075
    priv->caps = esxCapsInit(priv);
1076

M
Matthias Bolte 已提交
1077
    if (priv->caps == NULL) {
M
Matthias Bolte 已提交
1078
        goto cleanup;
1079 1080
    }

1081
    if (!(priv->xmlopt = virVMXDomainXMLConfInit()))
1082 1083
        goto cleanup;

1084 1085
    conn->privateData = priv;
    priv = NULL;
M
Matthias Bolte 已提交
1086
    result = VIR_DRV_OPEN_SUCCESS;
1087

M
Matthias Bolte 已提交
1088
  cleanup:
1089
    esxFreePrivate(&priv);
1090
    VIR_FREE(potentialVCenterIpAddress);
1091

M
Matthias Bolte 已提交
1092
    return result;
1093 1094 1095 1096 1097
}



static int
1098
esxConnectClose(virConnectPtr conn)
1099
{
M
Matthias Bolte 已提交
1100
    esxPrivate *priv = conn->privateData;
E
Eric Blake 已提交
1101
    int result = 0;
1102

1103 1104 1105 1106 1107 1108
    if (priv->host != NULL) {
        if (esxVI_EnsureSession(priv->host) < 0 ||
            esxVI_Logout(priv->host) < 0) {
            result = -1;
        }
    }
1109

M
Matthias Bolte 已提交
1110
    if (priv->vCenter != NULL) {
E
Eric Blake 已提交
1111 1112 1113 1114
        if (esxVI_EnsureSession(priv->vCenter) < 0 ||
            esxVI_Logout(priv->vCenter) < 0) {
            result = -1;
        }
1115 1116
    }

1117
    esxFreePrivate(&priv);
1118 1119 1120

    conn->privateData = NULL;

E
Eric Blake 已提交
1121
    return result;
1122 1123 1124 1125 1126
}



static esxVI_Boolean
1127
esxSupportsVMotion(esxPrivate *priv)
1128 1129 1130 1131
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

M
Matthias Bolte 已提交
1132 1133
    if (priv->supportsVMotion != esxVI_Boolean_Undefined) {
        return priv->supportsVMotion;
1134 1135
    }

1136
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1137
        return esxVI_Boolean_Undefined;
1138 1139
    }

1140
    if (esxVI_String_AppendValueToList(&propertyNameList,
1141
                                       "capability.vmotionSupported") < 0 ||
1142
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1143 1144
                                         &hostSystem) < 0 ||
        esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
1145 1146 1147
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1148 1149 1150
    }

  cleanup:
M
Matthias Bolte 已提交
1151 1152 1153 1154
    /*
     * 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.
     */
1155 1156 1157
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
1158
    return priv->supportsVMotion;
1159 1160 1161 1162 1163
}



static int
1164
esxConnectSupportsFeature(virConnectPtr conn, int feature)
1165
{
M
Matthias Bolte 已提交
1166
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1167
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1168 1169 1170

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1171
        supportsVMotion = esxSupportsVMotion(priv);
1172

M
Matthias Bolte 已提交
1173
        if (supportsVMotion == esxVI_Boolean_Undefined) {
1174 1175 1176
            return -1;
        }

M
Matthias Bolte 已提交
1177 1178 1179
        /* Migration is only possible via a vCenter and if VMotion is enabled */
        return priv->vCenter != NULL &&
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1180 1181 1182 1183 1184 1185 1186 1187 1188

      default:
        return 0;
    }
}



static const char *
1189
esxConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
1190 1191 1192 1193 1194 1195 1196
{
    return "ESX";
}



static int
1197
esxConnectGetVersion(virConnectPtr conn, unsigned long *version)
1198
{
M
Matthias Bolte 已提交
1199
    esxPrivate *priv = conn->privateData;
1200

1201
    if (virParseVersionString(priv->primary->service->about->version,
1202
                              version, false) < 0) {
1203 1204 1205
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse version number from '%s'"),
                       priv->primary->service->about->version);
1206

1207
        return -1;
1208 1209 1210 1211 1212 1213 1214 1215
    }

    return 0;
}



static char *
1216
esxConnectGetHostname(virConnectPtr conn)
1217
{
M
Matthias Bolte 已提交
1218
    esxPrivate *priv = conn->privateData;
1219 1220 1221 1222 1223 1224 1225
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1226
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1227
        return NULL;
1228 1229 1230
    }

    if (esxVI_String_AppendValueListToList
1231
          (&propertyNameList,
1232 1233
           "config.network.dnsConfig.hostName\0"
           "config.network.dnsConfig.domainName\0") < 0 ||
1234 1235
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1236
        goto cleanup;
1237 1238 1239 1240 1241 1242
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1243
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1244
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1245
                goto cleanup;
1246 1247 1248 1249 1250
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1251
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1252
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1253
                goto cleanup;
1254 1255 1256 1257 1258 1259 1260 1261
            }

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

M
Matthias Bolte 已提交
1262
    if (hostName == NULL || strlen(hostName) < 1) {
1263 1264
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1265
        goto cleanup;
1266 1267
    }

M
Matthias Bolte 已提交
1268
    if (domainName == NULL || strlen(domainName) < 1) {
1269
        if (VIR_STRDUP(complete, hostName) < 0)
M
Matthias Bolte 已提交
1270
            goto cleanup;
1271 1272
    } else {
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0) {
1273
            virReportOOMError();
M
Matthias Bolte 已提交
1274
            goto cleanup;
1275
        }
1276 1277 1278
    }

  cleanup:
M
Matthias Bolte 已提交
1279 1280
    /*
     * If we goto cleanup in case of an error then complete is still NULL,
1281
     * either VIR_STRDUP returned -1 or virAsprintf failed. When virAsprintf
M
Matthias Bolte 已提交
1282 1283
     * fails it guarantees setting complete to NULL
     */
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1295
    int result = -1;
M
Matthias Bolte 已提交
1296
    esxPrivate *priv = conn->privateData;
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
    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;

1308
    memset(nodeinfo, 0, sizeof(*nodeinfo));
1309

1310
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1311
        return -1;
1312 1313
    }

1314
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1315 1316 1317 1318 1319 1320 1321
                                           "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 ||
1322 1323
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1324
        goto cleanup;
1325 1326 1327 1328 1329
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1330
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1331
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1332
                goto cleanup;
1333 1334 1335 1336 1337
            }

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

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

            cpuInfo_numCpuPackages = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuThreads")) {
1354
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1355
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1356
                goto cleanup;
1357 1358 1359 1360
            }

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1361
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1362
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1363
                goto cleanup;
1364 1365 1366 1367 1368
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1369
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1370
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1371
                goto cleanup;
1372 1373 1374 1375 1376
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1377
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1378
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1379
                goto cleanup;
1380 1381 1382 1383 1384 1385
            }

            ptr = dynamicProperty->val->string;

            /* Strip the string to fit more relevant information in 32 chars */
            while (*ptr != '\0') {
M
Matthias Bolte 已提交
1386 1387
                if (STRPREFIX(ptr, "  ")) {
                    memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1388
                    continue;
1389
                } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
M
Matthias Bolte 已提交
1390
                    memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1391
                    continue;
1392 1393 1394
                } else if (STRPREFIX(ptr, "(TM)")) {
                    memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
                    continue;
1395 1396 1397 1398 1399
                }

                ++ptr;
            }

C
Chris Lalancette 已提交
1400 1401 1402
            if (virStrncpy(nodeinfo->model, dynamicProperty->val->string,
                           sizeof(nodeinfo->model) - 1,
                           sizeof(nodeinfo->model)) == NULL) {
1403 1404 1405
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("CPU Model %s too long for destination"),
                               dynamicProperty->val->string);
M
Matthias Bolte 已提交
1406
                goto cleanup;
C
Chris Lalancette 已提交
1407
            }
1408 1409 1410 1411 1412 1413 1414
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1415
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1416 1417 1418 1419 1420 1421 1422 1423 1424
    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 已提交
1425 1426
    result = 0;

1427 1428 1429 1430 1431 1432 1433 1434 1435
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1436
static char *
1437
esxConnectGetCapabilities(virConnectPtr conn)
1438
{
M
Matthias Bolte 已提交
1439
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1440
    char *xml = virCapabilitiesFormatXML(priv->caps);
1441 1442

    if (xml == NULL) {
1443
        virReportOOMError();
1444 1445 1446 1447 1448 1449 1450 1451
        return NULL;
    }

    return xml;
}



1452
static int
1453
esxConnectListDomains(virConnectPtr conn, int *ids, int maxids)
1454
{
M
Matthias Bolte 已提交
1455
    bool success = false;
M
Matthias Bolte 已提交
1456
    esxPrivate *priv = conn->privateData;
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

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

1467
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1468
        return -1;
1469 1470
    }

1471
    if (esxVI_String_AppendValueToList(&propertyNameList,
1472
                                       "runtime.powerState") < 0 ||
1473 1474
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1475
        goto cleanup;
1476 1477 1478 1479
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1480
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1481
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1482
            goto cleanup;
1483 1484 1485 1486 1487 1488 1489 1490 1491
        }

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1492 1493 1494
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to parse positive integer from '%s'"),
                           virtualMachine->obj->value);
M
Matthias Bolte 已提交
1495
            goto cleanup;
1496 1497 1498 1499 1500 1501 1502 1503 1504
        }

        count++;

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

M
Matthias Bolte 已提交
1505 1506
    success = true;

1507 1508 1509 1510
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1511
    return success ? count : -1;
1512 1513 1514 1515 1516
}



static int
1517
esxConnectNumOfDomains(virConnectPtr conn)
1518
{
M
Matthias Bolte 已提交
1519
    esxPrivate *priv = conn->privateData;
1520

1521
    if (esxVI_EnsureSession(priv->primary) < 0) {
1522 1523 1524
        return -1;
    }

1525
    return esxVI_LookupNumberOfDomainsByPowerState
1526
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1527 1528 1529 1530 1531 1532 1533
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1534
    esxPrivate *priv = conn->privateData;
1535 1536 1537 1538
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1539 1540 1541
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1542 1543
    virDomainPtr domain = NULL;

1544
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1545
        return NULL;
1546 1547
    }

1548
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1549
                                           "configStatus\0"
1550 1551
                                           "name\0"
                                           "runtime.powerState\0"
1552
                                           "config.uuid\0") < 0 ||
1553 1554
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1555
        goto cleanup;
1556 1557 1558 1559
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1560
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1561
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1562
            goto cleanup;
1563 1564 1565 1566 1567 1568 1569
        }

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

M
Matthias Bolte 已提交
1570
        VIR_FREE(name_candidate);
1571

1572
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1573 1574
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1575
            goto cleanup;
1576 1577
        }

M
Matthias Bolte 已提交
1578
        if (id != id_candidate) {
1579 1580 1581
            continue;
        }

M
Matthias Bolte 已提交
1582
        domain = virGetDomain(conn, name_candidate, uuid_candidate);
1583 1584

        if (domain == NULL) {
M
Matthias Bolte 已提交
1585
            goto cleanup;
1586 1587 1588 1589 1590 1591 1592 1593
        }

        domain->id = id;

        break;
    }

    if (domain == NULL) {
1594
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1595 1596 1597 1598 1599
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1600
    VIR_FREE(name_candidate);
1601 1602 1603 1604 1605 1606 1607 1608 1609

    return domain;
}



static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
M
Matthias Bolte 已提交
1610
    esxPrivate *priv = conn->privateData;
1611 1612 1613
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1614 1615
    int id = -1;
    char *name = NULL;
1616 1617
    virDomainPtr domain = NULL;

1618
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1619
        return NULL;
1620 1621
    }

1622
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1623
                                           "name\0"
1624
                                           "runtime.powerState\0") < 0 ||
1625
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1626
                                         &virtualMachine,
M
Matthias Bolte 已提交
1627
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1628 1629
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1630
        goto cleanup;
1631 1632
    }

1633
    domain = virGetDomain(conn, name, uuid);
1634 1635

    if (domain == NULL) {
M
Matthias Bolte 已提交
1636
        goto cleanup;
1637
    }
1638

1639 1640 1641 1642 1643
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1644 1645 1646 1647
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1648 1649
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1650 1651 1652 1653 1654 1655 1656 1657 1658

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1659
    esxPrivate *priv = conn->privateData;
1660 1661 1662
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1663 1664
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1665 1666
    virDomainPtr domain = NULL;

1667
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1668
        return NULL;
1669 1670
    }

1671
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1672
                                           "configStatus\0"
1673
                                           "runtime.powerState\0"
1674
                                           "config.uuid\0") < 0 ||
1675
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1676 1677
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1678
        goto cleanup;
1679 1680
    }

1681
    if (virtualMachine == NULL) {
1682
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1683
        goto cleanup;
1684
    }
1685

M
Matthias Bolte 已提交
1686 1687 1688
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1689
    }
1690

1691
    domain = virGetDomain(conn, name, uuid);
1692

1693
    if (domain == NULL) {
M
Matthias Bolte 已提交
1694
        goto cleanup;
1695 1696
    }

1697 1698 1699 1700 1701
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1702 1703 1704 1705
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1706
    esxVI_ObjectContent_Free(&virtualMachine);
1707 1708 1709 1710 1711 1712 1713 1714 1715

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1716
    int result = -1;
M
Matthias Bolte 已提交
1717
    esxPrivate *priv = domain->conn->privateData;
1718 1719 1720 1721 1722
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1723
    char *taskInfoErrorMessage = NULL;
1724

1725
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1726
        return -1;
1727 1728
    }

1729
    if (esxVI_String_AppendValueToList(&propertyNameList,
1730
                                       "runtime.powerState") < 0 ||
1731
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1732
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1733
           priv->parsedUri->autoAnswer) < 0 ||
1734
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1735
        goto cleanup;
1736 1737 1738
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1739 1740
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1741
        goto cleanup;
1742 1743
    }

1744 1745
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1746
                                    esxVI_Occurrence_RequiredItem,
1747
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1748
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1749
        goto cleanup;
1750 1751 1752
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1753 1754
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1755
        goto cleanup;
1756 1757
    }

M
Matthias Bolte 已提交
1758 1759
    result = 0;

1760 1761 1762 1763
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1764
    VIR_FREE(taskInfoErrorMessage);
1765 1766 1767 1768 1769 1770 1771 1772 1773

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1774
    int result = -1;
M
Matthias Bolte 已提交
1775
    esxPrivate *priv = domain->conn->privateData;
1776 1777 1778 1779 1780
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1781
    char *taskInfoErrorMessage = NULL;
1782

1783
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1784
        return -1;
1785 1786
    }

1787
    if (esxVI_String_AppendValueToList(&propertyNameList,
1788
                                       "runtime.powerState") < 0 ||
1789
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1790
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1791
           priv->parsedUri->autoAnswer) < 0 ||
1792
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1793
        goto cleanup;
1794 1795 1796
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1797
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1798
        goto cleanup;
1799 1800
    }

1801
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1802
                             &task) < 0 ||
1803
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1804
                                    esxVI_Occurrence_RequiredItem,
1805
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1806
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1807
        goto cleanup;
1808 1809 1810
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1811 1812
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1813
        goto cleanup;
1814 1815
    }

M
Matthias Bolte 已提交
1816 1817
    result = 0;

1818 1819 1820 1821
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1822
    VIR_FREE(taskInfoErrorMessage);
1823 1824 1825 1826 1827 1828 1829

    return result;
}



static int
1830
esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
1831
{
M
Matthias Bolte 已提交
1832
    int result = -1;
M
Matthias Bolte 已提交
1833
    esxPrivate *priv = domain->conn->privateData;
1834 1835 1836 1837
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1838 1839
    virCheckFlags(0, -1);

1840
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1841
        return -1;
1842 1843
    }

1844
    if (esxVI_String_AppendValueToList(&propertyNameList,
1845
                                       "runtime.powerState") < 0 ||
1846
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1847
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1848
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1849
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1850
        goto cleanup;
1851 1852 1853
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1854 1855
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1856
        goto cleanup;
1857 1858
    }

1859
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1860
        goto cleanup;
1861 1862
    }

M
Matthias Bolte 已提交
1863 1864
    result = 0;

1865 1866 1867 1868 1869 1870 1871 1872
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


1873 1874 1875 1876 1877 1878
static int
esxDomainShutdown(virDomainPtr domain)
{
    return esxDomainShutdownFlags(domain, 0);
}

1879 1880

static int
E
Eric Blake 已提交
1881
esxDomainReboot(virDomainPtr domain, unsigned int flags)
1882
{
M
Matthias Bolte 已提交
1883
    int result = -1;
M
Matthias Bolte 已提交
1884
    esxPrivate *priv = domain->conn->privateData;
1885 1886 1887 1888
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

E
Eric Blake 已提交
1889 1890
    virCheckFlags(0, -1);

1891
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1892
        return -1;
1893 1894
    }

1895
    if (esxVI_String_AppendValueToList(&propertyNameList,
1896
                                       "runtime.powerState") < 0 ||
1897
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1898
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1899
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1900
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1901
        goto cleanup;
1902 1903 1904
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1905 1906
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1907
        goto cleanup;
1908 1909
    }

1910
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1911
        goto cleanup;
1912 1913
    }

M
Matthias Bolte 已提交
1914 1915
    result = 0;

1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
1926 1927
esxDomainDestroyFlags(virDomainPtr domain,
                      unsigned int flags)
1928
{
M
Matthias Bolte 已提交
1929
    int result = -1;
M
Matthias Bolte 已提交
1930
    esxPrivate *priv = domain->conn->privateData;
1931
    esxVI_Context *ctx = NULL;
1932 1933 1934 1935 1936
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1937
    char *taskInfoErrorMessage = NULL;
1938

1939 1940
    virCheckFlags(0, -1);

1941 1942 1943 1944 1945 1946
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1947
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
1948
        return -1;
1949 1950
    }

1951
    if (esxVI_String_AppendValueToList(&propertyNameList,
1952
                                       "runtime.powerState") < 0 ||
1953
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1954
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1955
           priv->parsedUri->autoAnswer) < 0 ||
1956
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1957
        goto cleanup;
1958 1959 1960
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1961 1962
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1963
        goto cleanup;
1964 1965
    }

1966
    if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1967 1968
        esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
1969
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1970
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1971
        goto cleanup;
1972 1973 1974
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1975 1976
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1977
        goto cleanup;
1978 1979
    }

1980
    domain->id = -1;
M
Matthias Bolte 已提交
1981 1982
    result = 0;

1983 1984 1985 1986
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1987
    VIR_FREE(taskInfoErrorMessage);
1988 1989 1990 1991 1992

    return result;
}


1993 1994 1995 1996 1997 1998
static int
esxDomainDestroy(virDomainPtr dom)
{
    return esxDomainDestroyFlags(dom, 0);
}

1999 2000

static char *
2001
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
2002
{
2003
    char *osType;
2004

2005
    ignore_value(VIR_STRDUP(osType, "hvm"));
2006
    return osType;
2007 2008 2009 2010
}



2011
static unsigned long long
2012 2013
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
2014
    esxPrivate *priv = domain->conn->privateData;
2015 2016 2017 2018 2019
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

2020
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2021
        return 0;
2022 2023
    }

2024
    if (esxVI_String_AppendValueToList(&propertyNameList,
2025
                                       "config.hardware.memoryMB") < 0 ||
2026
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2027
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2028
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2029
        goto cleanup;
2030 2031 2032 2033 2034
    }

    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2035
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2036
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2037
                goto cleanup;
2038 2039 2040
            }

            if (dynamicProperty->val->int32 < 0) {
2041 2042 2043
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Got invalid memory size %d"),
                               dynamicProperty->val->int32);
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
            } 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 已提交
2066
    int result = -1;
M
Matthias Bolte 已提交
2067
    esxPrivate *priv = domain->conn->privateData;
2068
    esxVI_String *propertyNameList = NULL;
2069
    esxVI_ObjectContent *virtualMachine = NULL;
2070
    esxVI_VirtualMachinePowerState powerState;
2071 2072 2073
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2074
    char *taskInfoErrorMessage = NULL;
2075

2076
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2077
        return -1;
2078 2079
    }

2080 2081 2082 2083
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2084
           priv->parsedUri->autoAnswer) < 0 ||
2085 2086 2087 2088 2089
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2090 2091
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
2092 2093 2094 2095
        goto cleanup;
    }

    if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
2096
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
2097
        goto cleanup;
2098 2099
    }

2100
    /* max-memory must be a multiple of 4096 kilobyte */
2101
    spec->memoryMB->value =
2102
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2103

2104
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2105
                              &task) < 0 ||
2106
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2107
                                    esxVI_Occurrence_RequiredItem,
2108
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2109
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2110
        goto cleanup;
2111 2112 2113
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2114 2115 2116
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set max-memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2117
        goto cleanup;
2118 2119
    }

M
Matthias Bolte 已提交
2120 2121
    result = 0;

2122
  cleanup:
2123
    esxVI_String_Free(&propertyNameList);
2124 2125 2126
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2127
    VIR_FREE(taskInfoErrorMessage);
2128 2129 2130 2131 2132 2133 2134 2135 2136

    return result;
}



static int
esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2137
    int result = -1;
M
Matthias Bolte 已提交
2138
    esxPrivate *priv = domain->conn->privateData;
2139 2140 2141 2142
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2143
    char *taskInfoErrorMessage = NULL;
2144

2145
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2146
        return -1;
2147 2148
    }

2149
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2150
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2151
           priv->parsedUri->autoAnswer) < 0 ||
2152 2153 2154
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
        esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
M
Matthias Bolte 已提交
2155
        goto cleanup;
2156 2157 2158
    }

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

2161
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2162
                              &task) < 0 ||
2163
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2164
                                    esxVI_Occurrence_RequiredItem,
2165
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2166
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2167
        goto cleanup;
2168 2169 2170
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2171 2172 2173
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2174
        goto cleanup;
2175 2176
    }

M
Matthias Bolte 已提交
2177 2178
    result = 0;

2179 2180 2181 2182
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2183
    VIR_FREE(taskInfoErrorMessage);
2184 2185 2186 2187 2188 2189

    return result;
}



2190 2191 2192 2193 2194 2195 2196 2197 2198
/*
 * 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

2199 2200 2201
static int
esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
M
Matthias Bolte 已提交
2202
    int result = -1;
M
Matthias Bolte 已提交
2203
    esxPrivate *priv = domain->conn->privateData;
2204 2205 2206 2207 2208
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int64_t memory_limit = -1;
2209
#if ESX_QUERY_FOR_USED_CPU_TIME
2210 2211 2212 2213 2214 2215 2216
    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;
2217 2218
    esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
    esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2219 2220 2221
    esxVI_PerfEntityMetric *perfEntityMetric = NULL;
    esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
    esxVI_Long *value = NULL;
2222
#endif
2223

2224
    memset(info, 0, sizeof(*info));
M
Matthias Bolte 已提交
2225

2226
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2227
        return -1;
2228 2229
    }

2230
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2231 2232 2233 2234
                                           "runtime.powerState\0"
                                           "config.hardware.memoryMB\0"
                                           "config.hardware.numCPU\0"
                                           "config.memoryAllocation.limit\0") < 0 ||
2235
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2236
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2237
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2238
        goto cleanup;
2239 2240 2241 2242 2243 2244 2245 2246
    }

    info->state = VIR_DOMAIN_NOSTATE;

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

2251 2252
            info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                            (powerState);
2253
        } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2254
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2255
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2256
                goto cleanup;
2257 2258 2259 2260
            }

            info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
        } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2261
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2262
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2263
                goto cleanup;
2264 2265 2266 2267 2268
            }

            info->nrVirtCpu = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "config.memoryAllocation.limit")) {
2269
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2270
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
2271
                goto cleanup;
2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286
            }

            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;

2287
#if ESX_QUERY_FOR_USED_CPU_TIME
2288
    /* Verify the cached 'used CPU time' performance counter ID */
2289 2290 2291 2292 2293 2294
    /* 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;
            }
2295

2296
            counterId->value = priv->usedCpuTimeCounterId;
2297

2298 2299 2300
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                goto cleanup;
            }
2301

2302 2303 2304 2305
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2306

2307 2308 2309 2310 2311
            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);
2312

2313 2314 2315 2316 2317
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2318 2319
        }

2320 2321 2322 2323 2324 2325 2326 2327 2328 2329
        /*
         * 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;
            }
2330

2331 2332 2333 2334
            for (perfMetricId = perfMetricIdList; perfMetricId != NULL;
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2335

2336
                counterId = NULL;
2337

2338 2339 2340 2341 2342
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2343

2344 2345
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2346
                goto cleanup;
2347 2348
            }

2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365
            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;
                }
2366 2367
            }

2368
            if (priv->usedCpuTimeCounterId < 0) {
2369
                VIR_WARN("Could not find 'used CPU time' performance counter");
2370
            }
2371 2372
        }

2373 2374 2375 2376 2377 2378
        /*
         * 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);
2379

2380 2381 2382 2383 2384 2385
            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;
            }
2386

2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
            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;
            }
2397

2398 2399 2400
            for (perfEntityMetricBase = perfEntityMetricBaseList;
                 perfEntityMetricBase != NULL;
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2401
                VIR_DEBUG("perfEntityMetric ...");
2402

2403 2404
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2405

2406
                if (perfEntityMetric == NULL) {
2407 2408 2409
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetricBase->_type));
2410
                    goto cleanup;
2411
                }
2412

2413 2414
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2415

2416
                if (perfMetricIntSeries == NULL) {
2417 2418 2419
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetric->value->_type));
2420
                    goto cleanup;
2421
                }
2422

2423 2424
                for (; perfMetricIntSeries != NULL;
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2425
                    VIR_DEBUG("perfMetricIntSeries ...");
2426

2427 2428 2429 2430 2431
                    for (value = perfMetricIntSeries->value;
                         value != NULL;
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2432 2433 2434
                }
            }

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

2437
            /*
E
Eric Blake 已提交
2438
             * FIXME: Cannot map between relative used-cpu-time and absolute
2439 2440 2441
             *        info->cpuTime
             */
        }
2442
    }
2443
#endif
2444

M
Matthias Bolte 已提交
2445 2446
    result = 0;

2447
  cleanup:
2448
#if ESX_QUERY_FOR_USED_CPU_TIME
2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
    /*
     * 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;
        }
    }
2461
#endif
2462

2463 2464
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2465
#if ESX_QUERY_FOR_USED_CPU_TIME
2466 2467 2468 2469
    esxVI_PerfMetricId_Free(&perfMetricIdList);
    esxVI_Int_Free(&counterIdList);
    esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
    esxVI_PerfQuerySpec_Free(&querySpec);
2470
    esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2471
#endif
2472 2473 2474 2475 2476 2477

    return result;
}



2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
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;
}



2521
static int
2522 2523
esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                       unsigned int flags)
2524
{
M
Matthias Bolte 已提交
2525
    int result = -1;
M
Matthias Bolte 已提交
2526
    esxPrivate *priv = domain->conn->privateData;
M
Matthias Bolte 已提交
2527
    int maxVcpus;
2528 2529 2530 2531
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2532
    char *taskInfoErrorMessage = NULL;
2533

2534
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2535
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2536 2537 2538
        return -1;
    }

2539
    if (nvcpus < 1) {
2540 2541
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2542
        return -1;
2543 2544
    }

2545
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2546
        return -1;
2547 2548
    }

M
Matthias Bolte 已提交
2549
    maxVcpus = esxDomainGetMaxVcpus(domain);
2550

M
Matthias Bolte 已提交
2551
    if (maxVcpus < 0) {
M
Matthias Bolte 已提交
2552
        return -1;
2553 2554
    }

M
Matthias Bolte 已提交
2555
    if (nvcpus > maxVcpus) {
2556 2557 2558 2559
        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 已提交
2560
        return -1;
2561 2562
    }

2563
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2564
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2565
           priv->parsedUri->autoAnswer) < 0 ||
2566 2567
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_Int_Alloc(&spec->numCPUs) < 0) {
M
Matthias Bolte 已提交
2568
        goto cleanup;
2569 2570 2571 2572
    }

    spec->numCPUs->value = nvcpus;

2573
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2574
                              &task) < 0 ||
2575
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2576
                                    esxVI_Occurrence_RequiredItem,
2577
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2578
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2579
        goto cleanup;
2580 2581 2582
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2583 2584 2585
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2586
        goto cleanup;
2587 2588
    }

M
Matthias Bolte 已提交
2589 2590
    result = 0;

2591 2592 2593 2594
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2595
    VIR_FREE(taskInfoErrorMessage);
2596 2597 2598 2599 2600

    return result;
}


M
Matthias Bolte 已提交
2601

2602 2603 2604
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
2605
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2606 2607
}

2608

M
Matthias Bolte 已提交
2609

2610
static int
2611
esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2612
{
M
Matthias Bolte 已提交
2613
    esxPrivate *priv = domain->conn->privateData;
2614 2615 2616 2617
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

2618
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2619
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2620 2621 2622
        return -1;
    }

M
Matthias Bolte 已提交
2623 2624
    if (priv->maxVcpus > 0) {
        return priv->maxVcpus;
2625 2626
    }

M
Matthias Bolte 已提交
2627 2628
    priv->maxVcpus = -1;

2629
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2630
        return -1;
2631 2632
    }

2633
    if (esxVI_String_AppendValueToList(&propertyNameList,
2634
                                       "capability.maxSupportedVcpus") < 0 ||
2635 2636
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
2637
        goto cleanup;
2638 2639 2640 2641 2642
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2643
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2644
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2645
                goto cleanup;
2646 2647
            }

M
Matthias Bolte 已提交
2648
            priv->maxVcpus = dynamicProperty->val->int32;
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

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

M
Matthias Bolte 已提交
2659
    return priv->maxVcpus;
2660 2661
}

M
Matthias Bolte 已提交
2662 2663


2664 2665 2666
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
2667
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2668 2669
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2670

M
Matthias Bolte 已提交
2671 2672


2673
static char *
2674
esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2675
{
M
Matthias Bolte 已提交
2676
    esxPrivate *priv = domain->conn->privateData;
2677 2678
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2679 2680
    esxVI_VirtualMachinePowerState powerState;
    int id;
2681
    char *vmPathName = NULL;
2682
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2683
    char *directoryName = NULL;
2684
    char *directoryAndFileName = NULL;
2685
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2686 2687
    char *url = NULL;
    char *vmx = NULL;
2688
    virVMXContext ctx;
2689
    esxVMX_Data data;
2690 2691 2692
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2693 2694
    /* Flags checked by virDomainDefFormat */

2695
    memset(&data, 0, sizeof(data));
2696

2697
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2698
        return NULL;
2699 2700
    }

2701 2702 2703
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "config.files.vmPathName\0"
                                           "runtime.powerState\0") < 0 ||
2704
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2705
                                         propertyNameList, &virtualMachine,
2706
                                         esxVI_Occurrence_RequiredItem) < 0 ||
2707 2708
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2709 2710
        esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
                             &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2711
        goto cleanup;
2712 2713
    }

2714
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2715
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2716
        goto cleanup;
2717 2718
    }

2719
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2720
                      domain->conn->uri->server, domain->conn->uri->port);
2721
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2722
    virBufferAddLit(&buffer, "?dcPath=");
2723
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
2724 2725 2726 2727
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
2728
        virReportOOMError();
M
Matthias Bolte 已提交
2729
        goto cleanup;
2730 2731
    }

2732 2733
    url = virBufferContentAndReset(&buffer);

2734
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx, 0, NULL) < 0) {
M
Matthias Bolte 已提交
2735
        goto cleanup;
2736 2737
    }

2738
    data.ctx = priv->primary;
2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752

    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;
        }
    }
2753 2754 2755 2756 2757 2758

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

2759
    def = virVMXParseConfig(&ctx, priv->xmlopt, vmx);
2760 2761

    if (def != NULL) {
2762 2763 2764 2765
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
            def->id = id;
        }

2766
        xml = virDomainDefFormat(def, flags);
2767 2768 2769
    }

  cleanup:
M
Matthias Bolte 已提交
2770 2771 2772 2773
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

2774 2775
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2776
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2777
    VIR_FREE(directoryName);
2778
    VIR_FREE(directoryAndFileName);
2779
    VIR_FREE(url);
2780
    VIR_FREE(data.datastorePathWithoutFileName);
2781
    VIR_FREE(vmx);
2782
    virDomainDefFree(def);
2783 2784 2785 2786 2787 2788 2789

    return xml;
}



static char *
2790 2791 2792
esxConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                              const char *nativeConfig,
                              unsigned int flags)
2793
{
M
Matthias Bolte 已提交
2794
    esxPrivate *priv = conn->privateData;
2795
    virVMXContext ctx;
2796
    esxVMX_Data data;
2797 2798 2799
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2800 2801
    virCheckFlags(0, NULL);

2802
    memset(&data, 0, sizeof(data));
2803

2804
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2805 2806
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
2807
        return NULL;
2808 2809
    }

2810
    data.ctx = priv->primary;
2811
    data.datastorePathWithoutFileName = (char *)"[?] ?";
2812 2813 2814 2815 2816 2817

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

2818
    def = virVMXParseConfig(&ctx, priv->xmlopt, nativeConfig);
2819 2820

    if (def != NULL) {
2821
        xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
2822 2823 2824 2825 2826 2827 2828 2829 2830
    }

    virDomainDefFree(def);

    return xml;
}



M
Matthias Bolte 已提交
2831
static char *
2832 2833 2834
esxConnectDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                            const char *domainXml,
                            unsigned int flags)
M
Matthias Bolte 已提交
2835
{
M
Matthias Bolte 已提交
2836
    esxPrivate *priv = conn->privateData;
2837 2838
    int virtualHW_version;
    virVMXContext ctx;
2839
    esxVMX_Data data;
M
Matthias Bolte 已提交
2840 2841 2842
    virDomainDefPtr def = NULL;
    char *vmx = NULL;

E
Eric Blake 已提交
2843 2844
    virCheckFlags(0, NULL);

2845
    memset(&data, 0, sizeof(data));
2846

M
Matthias Bolte 已提交
2847
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2848 2849
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
M
Matthias Bolte 已提交
2850 2851 2852
        return NULL;
    }

2853 2854 2855 2856 2857 2858 2859
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        return NULL;
    }

2860 2861
    def = virDomainDefParseString(domainXml, priv->caps, priv->xmlopt,
                                  1 << VIR_DOMAIN_VIRT_VMWARE, 0);
M
Matthias Bolte 已提交
2862 2863 2864 2865 2866

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

2867
    data.ctx = priv->primary;
2868
    data.datastorePathWithoutFileName = NULL;
2869 2870 2871 2872 2873 2874

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

2875
    vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
M
Matthias Bolte 已提交
2876 2877 2878 2879 2880 2881 2882 2883

    virDomainDefFree(def);

    return vmx;
}



2884
static int
2885
esxConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
2886
{
M
Matthias Bolte 已提交
2887
    bool success = false;
M
Matthias Bolte 已提交
2888
    esxPrivate *priv = conn->privateData;
2889 2890 2891 2892 2893
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;
2894
    int i;
2895 2896 2897 2898 2899

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

2900
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2901
        return -1;
2902 2903
    }

2904
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2905 2906
                                           "name\0"
                                           "runtime.powerState\0") < 0 ||
2907 2908
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
2909
        goto cleanup;
2910 2911 2912 2913
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
2914
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2915
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
2916
            goto cleanup;
2917 2918 2919 2920 2921 2922
        }

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2923
        names[count] = NULL;
2924

2925 2926 2927
        if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
                                            NULL) < 0) {
            goto cleanup;
2928 2929
        }

2930 2931
        ++count;

2932 2933 2934 2935 2936
        if (count >= maxnames) {
            break;
        }
    }

M
Matthias Bolte 已提交
2937
    success = true;
2938

M
Matthias Bolte 已提交
2939 2940 2941 2942 2943
  cleanup:
    if (! success) {
        for (i = 0; i < count; ++i) {
            VIR_FREE(names[i]);
        }
2944

M
Matthias Bolte 已提交
2945
        count = -1;
2946 2947
    }

M
Matthias Bolte 已提交
2948 2949
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2950

M
Matthias Bolte 已提交
2951
    return count;
2952 2953 2954 2955 2956
}



static int
2957
esxConnectNumOfDefinedDomains(virConnectPtr conn)
2958
{
M
Matthias Bolte 已提交
2959
    esxPrivate *priv = conn->privateData;
2960

2961
    if (esxVI_EnsureSession(priv->primary) < 0) {
2962 2963 2964
        return -1;
    }

2965
    return esxVI_LookupNumberOfDomainsByPowerState
2966
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
2967 2968 2969 2970 2971
}



static int
2972
esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
2973
{
M
Matthias Bolte 已提交
2974
    int result = -1;
M
Matthias Bolte 已提交
2975
    esxPrivate *priv = domain->conn->privateData;
2976 2977 2978
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
2979
    int id = -1;
2980 2981
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2982
    char *taskInfoErrorMessage = NULL;
2983

2984 2985
    virCheckFlags(0, -1);

2986
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2987
        return -1;
2988 2989
    }

2990
    if (esxVI_String_AppendValueToList(&propertyNameList,
2991
                                       "runtime.powerState") < 0 ||
2992
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2993
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2994
           priv->parsedUri->autoAnswer) < 0 ||
2995 2996
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
M
Matthias Bolte 已提交
2997
        goto cleanup;
2998 2999 3000
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3001 3002
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
M
Matthias Bolte 已提交
3003
        goto cleanup;
3004 3005
    }

3006
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
3007
                             &task) < 0 ||
3008
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3009
                                    esxVI_Occurrence_RequiredItem,
3010
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3011
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3012
        goto cleanup;
3013 3014 3015
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3016 3017
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3018
        goto cleanup;
3019 3020
    }

3021
    domain->id = id;
M
Matthias Bolte 已提交
3022 3023
    result = 0;

3024 3025 3026 3027
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
3028
    VIR_FREE(taskInfoErrorMessage);
3029 3030 3031 3032

    return result;
}

3033 3034


3035 3036 3037 3038 3039
static int
esxDomainCreate(virDomainPtr domain)
{
    return esxDomainCreateWithFlags(domain, 0);
}
3040

3041 3042


M
Matthias Bolte 已提交
3043
static virDomainPtr
3044
esxDomainDefineXML(virConnectPtr conn, const char *xml)
M
Matthias Bolte 已提交
3045
{
M
Matthias Bolte 已提交
3046
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3047 3048
    virDomainDefPtr def = NULL;
    char *vmx = NULL;
3049 3050
    int i;
    virDomainDiskDefPtr disk = NULL;
M
Matthias Bolte 已提交
3051
    esxVI_ObjectContent *virtualMachine = NULL;
3052 3053
    int virtualHW_version;
    virVMXContext ctx;
3054
    esxVMX_Data data;
M
Matthias Bolte 已提交
3055 3056
    char *datastoreName = NULL;
    char *directoryName = NULL;
3057
    char *escapedName = NULL;
M
Matthias Bolte 已提交
3058 3059 3060 3061 3062 3063 3064 3065
    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;
3066
    char *taskInfoErrorMessage = NULL;
M
Matthias Bolte 已提交
3067 3068
    virDomainPtr domain = NULL;

3069
    memset(&data, 0, sizeof(data));
3070

3071
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3072
        return NULL;
M
Matthias Bolte 已提交
3073 3074 3075
    }

    /* Parse domain XML */
3076 3077
    def = virDomainDefParseString(xml, priv->caps, priv->xmlopt,
                                  1 << VIR_DOMAIN_VIRT_VMWARE,
M
Matthias Bolte 已提交
3078 3079 3080
                                  VIR_DOMAIN_XML_INACTIVE);

    if (def == NULL) {
M
Matthias Bolte 已提交
3081
        return NULL;
M
Matthias Bolte 已提交
3082 3083 3084
    }

    /* Check if an existing domain should be edited */
3085
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3086
                                         &virtualMachine,
M
Matthias Bolte 已提交
3087
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3088
        goto cleanup;
M
Matthias Bolte 已提交
3089 3090
    }

3091 3092 3093 3094 3095 3096 3097
    if (virtualMachine == NULL &&
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

M
Matthias Bolte 已提交
3098 3099
    if (virtualMachine != NULL) {
        /* FIXME */
3100 3101 3102
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain already exists, editing existing domains is not "
                         "supported yet"));
M
Matthias Bolte 已提交
3103
        goto cleanup;
M
Matthias Bolte 已提交
3104 3105 3106
    }

    /* Build VMX from domain XML */
3107 3108 3109 3110 3111 3112 3113
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        goto cleanup;
    }

3114
    data.ctx = priv->primary;
3115
    data.datastorePathWithoutFileName = NULL;
3116 3117 3118 3119 3120 3121

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

3122
    vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
M
Matthias Bolte 已提交
3123 3124

    if (vmx == NULL) {
M
Matthias Bolte 已提交
3125
        goto cleanup;
M
Matthias Bolte 已提交
3126 3127
    }

3128 3129 3130 3131 3132 3133 3134
    /*
     * 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 已提交
3135
    if (def->ndisks < 1) {
3136 3137 3138
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any disks, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3139
        goto cleanup;
3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150
    }

    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) {
3151 3152 3153
        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 已提交
3154
        goto cleanup;
M
Matthias Bolte 已提交
3155 3156
    }

3157
    if (disk->src == NULL) {
3158 3159 3160
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("First file-based harddisk has no source, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3161
        goto cleanup;
M
Matthias Bolte 已提交
3162 3163
    }

3164
    if (esxUtil_ParseDatastorePath(disk->src, &datastoreName, &directoryName,
3165
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3166
        goto cleanup;
M
Matthias Bolte 已提交
3167 3168
    }

3169
    if (! virFileHasSuffix(disk->src, ".vmdk")) {
3170 3171 3172
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting source '%s' of first file-based harddisk to "
                         "be a VMDK image"), disk->src);
M
Matthias Bolte 已提交
3173
        goto cleanup;
M
Matthias Bolte 已提交
3174 3175
    }

3176
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3177 3178 3179 3180 3181 3182 3183
                      conn->uri->server, conn->uri->port);

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

3184 3185 3186 3187 3188 3189 3190
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

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

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3191
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3192
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
M
Matthias Bolte 已提交
3193 3194 3195 3196
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
3197
        virReportOOMError();
M
Matthias Bolte 已提交
3198
        goto cleanup;
M
Matthias Bolte 已提交
3199 3200 3201 3202
    }

    url = virBufferContentAndReset(&buffer);

3203 3204 3205 3206 3207 3208
    /* Check, if VMX file already exists */
    /* FIXME */

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

3209
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0) {
3210 3211 3212 3213
        goto cleanup;
    }

    /* Register the domain */
M
Matthias Bolte 已提交
3214 3215
    if (directoryName != NULL) {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s/%s.vmx", datastoreName,
3216
                        directoryName, escapedName) < 0) {
3217
            virReportOOMError();
M
Matthias Bolte 已提交
3218
            goto cleanup;
M
Matthias Bolte 已提交
3219 3220 3221
        }
    } else {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s.vmx", datastoreName,
3222
                        escapedName) < 0) {
3223
            virReportOOMError();
M
Matthias Bolte 已提交
3224
            goto cleanup;
M
Matthias Bolte 已提交
3225 3226 3227
        }
    }

3228
    if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
M
Matthias Bolte 已提交
3229
                              datastoreRelatedPath, NULL, esxVI_Boolean_False,
3230 3231 3232 3233
                              priv->primary->computeResource->resourcePool,
                              priv->primary->hostSystem->_reference,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3234
                                    esxVI_Occurrence_OptionalItem,
3235
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3236
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3237
        goto cleanup;
M
Matthias Bolte 已提交
3238 3239 3240
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3241 3242
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3243
        goto cleanup;
M
Matthias Bolte 已提交
3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254
    }

    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 已提交
3255 3256 3257 3258
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

M
Matthias Bolte 已提交
3259 3260 3261 3262
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3263
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3264 3265 3266 3267 3268 3269 3270
    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);
3271
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3272 3273 3274 3275 3276 3277

    return domain;
}



3278
static int
3279 3280
esxDomainUndefineFlags(virDomainPtr domain,
                       unsigned int flags)
3281
{
M
Matthias Bolte 已提交
3282
    int result = -1;
M
Matthias Bolte 已提交
3283
    esxPrivate *priv = domain->conn->privateData;
3284
    esxVI_Context *ctx = NULL;
3285 3286 3287 3288
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3289 3290 3291 3292
    /* 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);
3293

3294 3295 3296 3297 3298 3299
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3300
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
3301
        return -1;
3302 3303
    }

3304
    if (esxVI_String_AppendValueToList(&propertyNameList,
3305
                                       "runtime.powerState") < 0 ||
3306 3307
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3308
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3309
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3310
        goto cleanup;
3311 3312 3313 3314
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3315 3316
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3317
        goto cleanup;
3318 3319
    }

3320
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
3321
        goto cleanup;
3322 3323
    }

M
Matthias Bolte 已提交
3324 3325
    result = 0;

3326 3327 3328 3329 3330 3331 3332 3333
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


3334 3335 3336 3337 3338
static int
esxDomainUndefine(virDomainPtr domain)
{
    return esxDomainUndefineFlags(domain, 0);
}
3339

3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419
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;
3420
    bool newPowerInfo_isAppended = false;
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 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458

    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)) {
3459 3460 3461
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("Cannot enable general autostart option "
                                     "without affecting other domains"));
3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477
                    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 ||
3478
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0) {
3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489
        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";

3490 3491 3492 3493 3494 3495 3496
    if (esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
                                              newPowerInfo) < 0) {
        goto cleanup;
    }

    newPowerInfo_isAppended = true;

3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
    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);

3518 3519 3520 3521
    if (!newPowerInfo_isAppended) {
        esxVI_AutoStartPowerInfo_Free(&newPowerInfo);
    }

3522 3523 3524 3525 3526
    return result;
}



3527 3528 3529 3530 3531 3532 3533 3534 3535 3536
/*
 * 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:
 *
3537
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3538
 *
3539
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3540 3541
 *
 *
3542
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3543
 *
3544 3545
 *   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
3546 3547 3548 3549
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3550
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3551 3552 3553 3554 3555 3556
 *
 *   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'.
 */
3557
static char *
3558
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3559
{
3560
    char *type;
3561

3562
    if (VIR_STRDUP(type, "allocation") < 0)
3563
        return NULL;
3564

3565 3566 3567
    if (nparams != NULL) {
        *nparams = 3; /* reservation, limit, shares */
    }
3568 3569 3570 3571 3572 3573 3574

    return type;
}



static int
3575 3576 3577
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int *nparams,
                                     unsigned int flags)
3578
{
M
Matthias Bolte 已提交
3579
    int result = -1;
M
Matthias Bolte 已提交
3580
    esxPrivate *priv = domain->conn->privateData;
3581 3582 3583 3584 3585 3586 3587
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    unsigned int mask = 0;
    int i = 0;

3588 3589
    virCheckFlags(0, -1);

3590
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3591
        return -1;
3592 3593
    }

3594
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3595 3596 3597
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3598
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3599
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3600
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3601
        goto cleanup;
3602 3603 3604
    }

    for (dynamicProperty = virtualMachine->propSet;
3605
         dynamicProperty != NULL && mask != 7 && i < 3 && i < *nparams;
3606 3607
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
M
Matthias Bolte 已提交
3608
            ! (mask & (1 << 0))) {
3609
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3610
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3611
                goto cleanup;
3612
            }
3613 3614 3615 3616 3617
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_RESERVATION,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3618 3619 3620 3621
            mask |= 1 << 0;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.limit") &&
M
Matthias Bolte 已提交
3622
                   ! (mask & (1 << 1))) {
3623
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3624
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3625
                goto cleanup;
3626
            }
3627 3628 3629 3630 3631
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_LIMIT,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3632 3633 3634 3635
            mask |= 1 << 1;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.shares") &&
M
Matthias Bolte 已提交
3636
                   ! (mask & (1 << 2))) {
3637 3638 3639 3640
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_SHARES,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
                goto cleanup;
3641
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3642
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3643
                goto cleanup;
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663
            }

            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:
3664 3665 3666
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Shares level has unknown value %d"),
                               (int)sharesInfo->level);
M
Matthias Bolte 已提交
3667
                goto cleanup;
3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
            }

            esxVI_SharesInfo_Free(&sharesInfo);

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

    *nparams = i;
M
Matthias Bolte 已提交
3680
    result = 0;
3681 3682 3683 3684 3685 3686 3687 3688

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

    return result;
}

3689 3690 3691 3692 3693 3694
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3695 3696 3697


static int
3698 3699 3700
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3701
{
M
Matthias Bolte 已提交
3702
    int result = -1;
M
Matthias Bolte 已提交
3703
    esxPrivate *priv = domain->conn->privateData;
3704 3705 3706 3707 3708
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3709
    char *taskInfoErrorMessage = NULL;
3710 3711
    int i;

3712
    virCheckFlags(0, -1);
3713 3714 3715 3716 3717 3718 3719 3720 3721
    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;
3722

3723
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3724
        return -1;
3725 3726
    }

3727
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3728
          (priv->primary, domain->uuid, NULL, &virtualMachine,
3729
           priv->parsedUri->autoAnswer) < 0 ||
3730 3731
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
M
Matthias Bolte 已提交
3732
        goto cleanup;
3733 3734 3735
    }

    for (i = 0; i < nparams; ++i) {
3736
        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_RESERVATION)) {
3737
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0) {
M
Matthias Bolte 已提交
3738
                goto cleanup;
3739 3740 3741
            }

            if (params[i].value.l < 0) {
3742 3743 3744
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Could not set reservation to %lld MHz, expecting "
                                 "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3745
                goto cleanup;
3746 3747 3748
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
3749
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_LIMIT)) {
3750
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0) {
M
Matthias Bolte 已提交
3751
                goto cleanup;
3752 3753 3754
            }

            if (params[i].value.l < -1) {
3755 3756 3757 3758
                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 已提交
3759
                goto cleanup;
3760 3761 3762
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
3763
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_SHARES)) {
3764 3765
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3766
                goto cleanup;
3767 3768 3769 3770
            }

            spec->cpuAllocation->shares = sharesInfo;

3771
            if (params[i].value.i >= 0) {
3772
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3773
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3774
            } else {
3775
                switch (params[i].value.i) {
3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793
                  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:
3794 3795 3796 3797
                    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 已提交
3798
                    goto cleanup;
3799 3800 3801 3802 3803
                }
            }
        }
    }

3804
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3805
                              &task) < 0 ||
3806
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3807
                                    esxVI_Occurrence_RequiredItem,
3808
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3809
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3810
        goto cleanup;
3811 3812 3813
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3814 3815 3816
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change scheduler parameters: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3817
        goto cleanup;
3818 3819
    }

M
Matthias Bolte 已提交
3820 3821
    result = 0;

3822 3823 3824 3825
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3826
    VIR_FREE(taskInfoErrorMessage);
3827 3828 3829 3830

    return result;
}

3831 3832 3833 3834 3835 3836
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3837

E
Eric Blake 已提交
3838 3839 3840 3841 3842 3843
/* 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)
3844 3845 3846 3847 3848

static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3849 3850
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
E
Eric Blake 已提交
3851
                        unsigned long flags,
3852 3853 3854
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3855
    esxPrivate *priv = dconn->privateData;
3856

E
Eric Blake 已提交
3857 3858
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3859
    if (uri_in == NULL) {
3860 3861 3862 3863
        if (virAsprintf(uri_out, "vpxmigr://%s/%s/%s",
                        priv->vCenter->ipAddress,
                        priv->vCenter->computeResource->resourcePool->value,
                        priv->vCenter->hostSystem->_reference->value) < 0) {
3864
            virReportOOMError();
3865
            return -1;
3866 3867 3868
        }
    }

3869
    return 0;
3870 3871 3872 3873 3874 3875 3876 3877 3878
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
E
Eric Blake 已提交
3879
                        unsigned long flags,
3880 3881 3882
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3883
    int result = -1;
M
Matthias Bolte 已提交
3884
    esxPrivate *priv = domain->conn->privateData;
M
Martin Kletzander 已提交
3885
    virURIPtr parsedUri = NULL;
3886 3887 3888
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3889
    esxVI_ObjectContent *virtualMachine = NULL;
3890 3891
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3892 3893 3894
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3895
    char *taskInfoErrorMessage = NULL;
3896

E
Eric Blake 已提交
3897 3898
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

M
Matthias Bolte 已提交
3899
    if (priv->vCenter == NULL) {
3900 3901
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration not possible without a vCenter"));
M
Matthias Bolte 已提交
3902
        return -1;
3903 3904 3905
    }

    if (dname != NULL) {
3906 3907
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Renaming domains on migration not supported"));
M
Matthias Bolte 已提交
3908
        return -1;
3909 3910
    }

3911
    if (esxVI_EnsureSession(priv->vCenter) < 0) {
M
Matthias Bolte 已提交
3912
        return -1;
3913 3914
    }

3915
    /* Parse migration URI */
3916
    if (!(parsedUri = virURIParse(uri)))
M
Matthias Bolte 已提交
3917
        return -1;
3918

3919
    if (parsedUri->scheme == NULL || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
3920 3921
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3922
        goto cleanup;
3923 3924
    }

3925
    if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
3926 3927 3928
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration source and destination have to refer to "
                         "the same vCenter"));
3929 3930 3931 3932 3933 3934 3935
        goto cleanup;
    }

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

    if (path_resourcePool == NULL || path_hostSystem == NULL) {
3936 3937
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration URI has to specify resource pool and host system"));
M
Matthias Bolte 已提交
3938
        goto cleanup;
3939 3940
    }

3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953
    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,
3954
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
3955
        goto cleanup;
3956 3957 3958
    }

    /* Validate the purposed migration */
3959
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3960 3961
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
3962
        goto cleanup;
3963 3964 3965 3966 3967 3968 3969 3970
    }

    if (eventList != NULL) {
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
        if (eventList->fullFormattedMessage != NULL) {
3971 3972 3973
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not migrate domain, validation reported a "
                             "problem: %s"), eventList->fullFormattedMessage);
3974
        } else {
3975 3976 3977
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not migrate domain, validation reported a "
                             "problem"));
3978 3979
        }

M
Matthias Bolte 已提交
3980
        goto cleanup;
3981 3982 3983
    }

    /* Perform the purposed migration */
3984 3985
    if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
                             &resourcePool, &hostSystem,
3986 3987 3988
                             esxVI_VirtualMachineMovePriority_DefaultPriority,
                             esxVI_VirtualMachinePowerState_Undefined,
                             &task) < 0 ||
3989
        esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
3990
                                    esxVI_Occurrence_RequiredItem,
3991
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3992
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3993
        goto cleanup;
3994 3995 3996
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3997 3998 3999 4000
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not migrate domain, migration task finished with "
                         "an error: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4001
        goto cleanup;
4002 4003
    }

M
Matthias Bolte 已提交
4004 4005
    result = 0;

4006
  cleanup:
4007
    virURIFree(parsedUri);
4008 4009 4010
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
4011
    VIR_FREE(taskInfoErrorMessage);
4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022

    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 已提交
4023
                       unsigned long flags)
4024
{
E
Eric Blake 已提交
4025 4026
    virCheckFlags(ESX_MIGRATION_FLAGS, NULL);

4027 4028 4029 4030 4031
    return esxDomainLookupByName(dconn, dname);
}



M
Matthias Bolte 已提交
4032 4033 4034 4035
static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)
{
    unsigned long long result = 0;
M
Matthias Bolte 已提交
4036
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
4037 4038 4039 4040 4041
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *resourcePool = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_ResourcePoolResourceUsage *resourcePoolResourceUsage = NULL;

4042
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4043
        return 0;
M
Matthias Bolte 已提交
4044 4045 4046
    }

    /* Get memory usage of resource pool */
4047
    if (esxVI_String_AppendValueToList(&propertyNameList,
M
Matthias Bolte 已提交
4048
                                       "runtime.memory") < 0 ||
4049 4050
        esxVI_LookupObjectContentByType(priv->primary,
                                        priv->primary->computeResource->resourcePool,
4051
                                        "ResourcePool", propertyNameList,
4052 4053
                                        &resourcePool,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4054
        goto cleanup;
M
Matthias Bolte 已提交
4055 4056 4057 4058 4059 4060
    }

    for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.memory")) {
            if (esxVI_ResourcePoolResourceUsage_CastFromAnyType
4061
                  (dynamicProperty->val, &resourcePoolResourceUsage) < 0) {
M
Matthias Bolte 已提交
4062
                goto cleanup;
M
Matthias Bolte 已提交
4063 4064 4065 4066 4067 4068 4069 4070 4071
            }

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

    if (resourcePoolResourceUsage == NULL) {
4072 4073
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not retrieve memory usage of resource pool"));
M
Matthias Bolte 已提交
4074
        goto cleanup;
M
Matthias Bolte 已提交
4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
    }

    result = resourcePoolResourceUsage->unreservedForVm->value;

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

    return result;
}



4089
static int
4090
esxConnectIsEncrypted(virConnectPtr conn)
4091
{
M
Matthias Bolte 已提交
4092
    esxPrivate *priv = conn->privateData;
4093

4094
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4095 4096 4097 4098 4099 4100 4101 4102 4103
        return 1;
    } else {
        return 0;
    }
}



static int
4104
esxConnectIsSecure(virConnectPtr conn)
4105
{
M
Matthias Bolte 已提交
4106
    esxPrivate *priv = conn->privateData;
4107

4108
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4109 4110 4111 4112 4113 4114 4115 4116
        return 1;
    } else {
        return 0;
    }
}



4117
static int
4118
esxConnectIsAlive(virConnectPtr conn)
4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133
{
    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;
}



4134 4135 4136
static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4137
    int result = -1;
M
Matthias Bolte 已提交
4138
    esxPrivate *priv = domain->conn->privateData;
4139 4140 4141 4142
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4143
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4144
        return -1;
4145 4146
    }

4147
    if (esxVI_String_AppendValueToList(&propertyNameList,
4148
                                       "runtime.powerState") < 0 ||
4149
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4150
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4151
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4152
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4153
        goto cleanup;
4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171
    }

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

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

    return result;
}



static int
4172
esxDomainIsPersistent(virDomainPtr domain)
4173
{
4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193
    /* 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;
4194 4195
}

M
Matthias Bolte 已提交
4196 4197


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

M
Matthias Bolte 已提交
4223 4224


4225 4226
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4227
                           unsigned int flags)
4228 4229 4230 4231 4232 4233 4234 4235
{
    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;
4236
    char *taskInfoErrorMessage = NULL;
4237 4238
    virDomainSnapshotPtr snapshot = NULL;

4239 4240
    /* ESX has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
4241

4242
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4243
        return NULL;
4244 4245
    }

4246
    def = virDomainSnapshotDefParseString(xmlDesc, priv->caps,
4247
                                          priv->xmlopt, 0, 0);
4248 4249

    if (def == NULL) {
M
Matthias Bolte 已提交
4250
        return NULL;
4251 4252
    }

4253
    if (def->ndisks) {
4254 4255
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
4256 4257 4258
        return NULL;
    }

4259
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4260
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4261
           priv->parsedUri->autoAnswer) < 0 ||
4262
        esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4263 4264
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
4265
                                    &snapshotTree, NULL,
4266
                                    esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4267
        goto cleanup;
4268 4269 4270
    }

    if (snapshotTree != NULL) {
4271 4272
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Snapshot '%s' already exists"), def->name);
M
Matthias Bolte 已提交
4273
        goto cleanup;
4274 4275
    }

4276
    if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4277 4278 4279
                                  def->name, def->description,
                                  esxVI_Boolean_True,
                                  esxVI_Boolean_False, &task) < 0 ||
4280
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4281
                                    esxVI_Occurrence_RequiredItem,
4282
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4283
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4284
        goto cleanup;
4285 4286 4287
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4288 4289
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4290
        goto cleanup;
4291 4292 4293 4294 4295 4296 4297 4298 4299
    }

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

  cleanup:
    virDomainSnapshotDefFree(def);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4300
    VIR_FREE(taskInfoErrorMessage);
4301 4302 4303 4304 4305 4306 4307

    return snapshot;
}



static char *
4308 4309
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4310 4311 4312 4313 4314 4315 4316 4317 4318
{
    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;

4319 4320
    virCheckFlags(0, NULL);

4321
    memset(&def, 0, sizeof(def));
4322

4323
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4324
        return NULL;
4325 4326
    }

4327
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4328 4329 4330 4331
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4332
        goto cleanup;
4333 4334 4335 4336 4337 4338 4339 4340
    }

    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 已提交
4341
        goto cleanup;
4342 4343 4344 4345 4346 4347 4348
    }

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

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

4349
    xml = virDomainSnapshotDefFormat(uuid_string, &def, flags, 0);
4350 4351 4352 4353 4354 4355 4356 4357 4358 4359

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



static int
4360
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4361
{
M
Matthias Bolte 已提交
4362
    int count;
4363 4364
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4365
    bool recurse;
4366
    bool leaves;
4367

4368
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4369 4370
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4371 4372

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4373
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4374

4375
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4376
        return -1;
4377 4378
    }

4379 4380 4381 4382
    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)
        return 0;

4383
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4384
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4385
        return -1;
4386 4387
    }

4388 4389
    count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList, recurse,
                                           leaves);
4390 4391 4392

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

M
Matthias Bolte 已提交
4393
    return count;
4394 4395 4396 4397 4398 4399
}



static int
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4400
                           unsigned int flags)
4401
{
M
Matthias Bolte 已提交
4402
    int result;
4403 4404
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4405
    bool recurse;
4406
    bool leaves;
4407 4408

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4409 4410
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4411

4412
    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4413
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4414

4415
    if (names == NULL || nameslen < 0) {
4416
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4417 4418 4419
        return -1;
    }

4420
    if (nameslen == 0 || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)) {
4421 4422 4423
        return 0;
    }

4424
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4425
        return -1;
4426 4427
    }

4428
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4429
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4430
        return -1;
4431 4432
    }

4433
    result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen,
4434
                                        recurse, leaves);
4435 4436 4437 4438 4439 4440 4441 4442

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4443 4444 4445 4446 4447 4448 4449 4450
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;
4451
    bool leaves;
4452 4453

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4454 4455
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4456 4457

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4458
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478

    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,
4479
                                           recurse, leaves);
4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498

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;
4499
    bool leaves;
4500 4501

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4502 4503
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4504 4505

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4506
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4507 4508

    if (names == NULL || nameslen < 0) {
4509
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
        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,
4536
                                        names, nameslen, recurse, leaves);
4537 4538 4539 4540 4541 4542 4543 4544 4545

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4546 4547
static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4548
                              unsigned int flags)
4549 4550 4551 4552 4553 4554
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    virDomainSnapshotPtr snapshot = NULL;

4555 4556
    virCheckFlags(0, NULL);

4557
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4558
        return NULL;
4559 4560
    }

4561
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4562 4563
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
4564
                                    NULL,
4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584
                                    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;

4585
    virCheckFlags(0, -1);
4586

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

4591
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4592 4593
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4594
        return -1;
4595 4596 4597
    }

    if (currentSnapshotTree != NULL) {
M
Matthias Bolte 已提交
4598 4599
        esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
        return 1;
4600 4601
    }

M
Matthias Bolte 已提交
4602
    return 0;
4603 4604 4605 4606
}



E
Eric Blake 已提交
4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630
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) {
4631 4632 4633
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshotTree->name);
E
Eric Blake 已提交
4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646
        goto cleanup;
    }

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



4647 4648 4649 4650 4651
static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
M
Matthias Bolte 已提交
4652
    virDomainSnapshotPtr snapshot = NULL;
4653

4654
    virCheckFlags(0, NULL);
4655

4656
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4657
        return NULL;
4658 4659
    }

4660
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4661 4662
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4663
        return NULL;
4664 4665 4666 4667 4668 4669 4670 4671 4672 4673
    }

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}


4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742
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;
}

4743 4744 4745 4746

static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4747
    int result = -1;
4748 4749 4750 4751 4752
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4753
    char *taskInfoErrorMessage = NULL;
4754

4755
    virCheckFlags(0, -1);
4756

4757
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4758
        return -1;
4759 4760
    }

4761
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4762 4763
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4764
                                    &snapshotTree, NULL,
4765
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4766
        goto cleanup;
4767 4768
    }

4769
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4770
                                    esxVI_Boolean_Undefined, &task) < 0 ||
4771
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4772
                                    esxVI_Occurrence_RequiredItem,
4773
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4774
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4775
        goto cleanup;
4776 4777 4778
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4779 4780 4781
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not revert to snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4782
        goto cleanup;
4783 4784
    }

M
Matthias Bolte 已提交
4785 4786
    result = 0;

4787 4788 4789
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4790
    VIR_FREE(taskInfoErrorMessage);
4791 4792 4793 4794 4795 4796 4797 4798 4799

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4800
    int result = -1;
4801 4802 4803 4804 4805 4806
    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;
4807
    char *taskInfoErrorMessage = NULL;
4808

4809 4810
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4811

4812
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4813
        return -1;
4814 4815 4816 4817 4818 4819
    }

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

4820
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4821 4822
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4823
                                    &snapshotTree, NULL,
4824
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4825
        goto cleanup;
4826 4827
    }

4828 4829 4830 4831 4832 4833 4834
    /* 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;
    }

4835
    if (esxVI_RemoveSnapshot_Task(priv->primary, snapshotTree->snapshot,
4836
                                  removeChildren, &task) < 0 ||
4837
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4838
                                    esxVI_Occurrence_RequiredItem,
4839
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4840
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4841
        goto cleanup;
4842 4843 4844
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4845 4846 4847
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not delete snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4848
        goto cleanup;
4849 4850
    }

M
Matthias Bolte 已提交
4851 4852
    result = 0;

4853 4854 4855
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4856
    VIR_FREE(taskInfoErrorMessage);
4857 4858 4859 4860 4861 4862

    return result;
}



4863
static int
4864
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4865 4866 4867 4868 4869 4870 4871 4872
                             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;
4873
    char *taskInfoErrorMessage = NULL;
4874 4875 4876
    int i;

    virCheckFlags(0, -1);
4877 4878 4879 4880 4881
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
4882 4883 4884 4885 4886 4887 4888

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

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4889
           priv->parsedUri->autoAnswer) < 0 ||
4890 4891 4892 4893 4894 4895
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
        goto cleanup;
    }

    for (i = 0; i < nparams; ++i) {
4896
        if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
4897 4898 4899 4900 4901
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) {
                goto cleanup;
            }

            spec->memoryAllocation->reservation->value =
4902
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4903 4904 4905 4906 4907 4908 4909
        }
    }

    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
4910
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4911
                                    &taskInfoErrorMessage) < 0) {
4912 4913 4914 4915
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4916 4917 4918
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change memory parameters: %s"),
                       taskInfoErrorMessage);
4919 4920 4921 4922 4923 4924 4925 4926 4927
        goto cleanup;
    }

    result = 0;

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4928
    VIR_FREE(taskInfoErrorMessage);
4929 4930 4931 4932 4933 4934 4935

    return result;
}



static int
4936
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965
                             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;
    }

4966 4967 4968 4969
    /* Scale from megabytes to kilobytes */
    if (virTypedParameterAssign(params, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                VIR_TYPED_PARAM_ULLONG,
                                reservation->value * 1024) < 0)
4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982
        goto cleanup;

    *nparams = 1;
    result = 0;

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

    return result;
}

4983 4984
#define MATCH(FLAG) (flags & (FLAG))
static int
4985 4986 4987
esxConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
                         unsigned int flags)
4988 4989 4990
{
    int ret = -1;
    esxPrivate *priv = conn->privateData;
4991 4992
    bool needIdentity;
    bool needPowerState;
4993 4994 4995
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    size_t ndoms = 0;
4996
    esxVI_String *propertyNameList = NULL;
4997 4998
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
4999
    esxVI_AutoStartDefaults *autoStartDefaults = NULL;
5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016
    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
     */
5017
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028
         !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;
    }

5029
    if (esxVI_EnsureSession(priv->primary) < 0)
5030 5031 5032 5033 5034
        return -1;

    /* check system default autostart value */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
        if (esxVI_LookupAutoStartDefaults(priv->primary,
5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055
                                          &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) {
5056
            goto cleanup;
5057 5058 5059 5060 5061 5062
        }
    }

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

5064 5065 5066
    if (needPowerState) {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "runtime.powerState") < 0) {
5067
            goto cleanup;
5068
        }
5069 5070
    }

5071
    if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082
                                       &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) {
5083 5084
        if (needIdentity) {
            VIR_FREE(name);
5085

5086 5087 5088 5089 5090
            if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id,
                                                &name, uuid) < 0) {
                goto cleanup;
            }
        }
5091

5092 5093 5094 5095 5096 5097
        if (needPowerState) {
            if (esxVI_GetVirtualMachinePowerState(virtualMachine,
                                                  &powerState) < 0) {
                goto cleanup;
            }
        }
5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108

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

5111 5112 5113 5114 5115 5116
            if (esxVI_LookupRootSnapshotTreeList(priv->primary, uuid,
                                                 &rootSnapshotTreeList) < 0) {
                goto cleanup;
            }

            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
5117
                   rootSnapshotTreeList != NULL) ||
5118
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
5119
                   rootSnapshotTreeList == NULL)))
5120 5121 5122 5123 5124 5125 5126
                continue;
        }

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

5127 5128 5129 5130 5131 5132
            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;
5133

5134 5135
                        break;
                    }
5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148
                }
            }

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

5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
            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;
        }

5169
        if (VIR_RESIZE_N(doms, ndoms, count, 2) < 0)
5170 5171
            goto no_memory;

5172 5173 5174
        if (!(dom = virGetDomain(conn, name, uuid)))
            goto cleanup;

5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191
        /* 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++) {
5192
            virDomainFree(doms[id]);
5193
        }
5194 5195

        VIR_FREE(doms);
5196
    }
5197

5198
    VIR_FREE(name);
5199 5200
    esxVI_AutoStartDefaults_Free(&autoStartDefaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);
5201 5202
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
5203 5204
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5205 5206 5207 5208 5209 5210 5211
    return ret;

no_memory:
    virReportOOMError();
    goto cleanup;
}
#undef MATCH
5212 5213


5214
static virDriver esxDriver = {
5215 5216
    .no = VIR_DRV_ESX,
    .name = "ESX",
5217 5218 5219 5220 5221 5222
    .connectOpen = esxConnectOpen, /* 0.7.0 */
    .connectClose = esxConnectClose, /* 0.7.0 */
    .connectSupportsFeature = esxConnectSupportsFeature, /* 0.7.0 */
    .connectGetType = esxConnectGetType, /* 0.7.0 */
    .connectGetVersion = esxConnectGetVersion, /* 0.7.0 */
    .connectGetHostname = esxConnectGetHostname, /* 0.7.0 */
5223
    .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
5224 5225 5226 5227
    .connectGetCapabilities = esxConnectGetCapabilities, /* 0.7.1 */
    .connectListDomains = esxConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = esxConnectNumOfDomains, /* 0.7.0 */
    .connectListAllDomains = esxConnectListAllDomains, /* 0.10.2 */
5228 5229 5230 5231 5232 5233
    .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 */
5234
    .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
5235 5236
    .domainReboot = esxDomainReboot, /* 0.7.0 */
    .domainDestroy = esxDomainDestroy, /* 0.7.0 */
5237
    .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250
    .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 */
5251 5252 5253 5254
    .connectDomainXMLFromNative = esxConnectDomainXMLFromNative, /* 0.7.0 */
    .connectDomainXMLToNative = esxConnectDomainXMLToNative, /* 0.7.2 */
    .connectListDefinedDomains = esxConnectListDefinedDomains, /* 0.7.0 */
    .connectNumOfDefinedDomains = esxConnectNumOfDefinedDomains, /* 0.7.0 */
5255 5256 5257 5258
    .domainCreate = esxDomainCreate, /* 0.7.0 */
    .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
    .domainUndefine = esxDomainUndefine, /* 0.7.1 */
5259
    .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
5260 5261 5262 5263
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
5264
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
5265
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
5266
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
5267 5268 5269 5270
    .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
    .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
    .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
    .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
5271 5272
    .connectIsEncrypted = esxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = esxConnectIsSecure, /* 0.7.3 */
5273 5274 5275 5276 5277 5278 5279
    .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 */
5280 5281
    .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
5282 5283
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
E
Eric Blake 已提交
5284
    .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
5285 5286
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
5287 5288
    .domainSnapshotIsCurrent = esxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = esxDomainSnapshotHasMetadata, /* 0.9.13 */
5289
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
5290
    .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */
5291 5292 5293 5294 5295 5296 5297
};



int
esxRegister(void)
{
5298 5299 5300 5301 5302
    if (virRegisterDriver(&esxDriver) < 0 ||
        esxInterfaceRegister() < 0 ||
        esxNetworkRegister() < 0 ||
        esxStorageRegister() < 0 ||
        esxDeviceRegister() < 0 ||
M
Matthias Bolte 已提交
5303 5304
        esxSecretRegister() < 0 ||
        esxNWFilterRegister() < 0) {
5305 5306
        return -1;
    }
5307 5308 5309

    return 0;
}