esx_driver.c 171.2 KB
Newer Older
1
/*
2
 * esx_driver.c: core driver functions for managing VMware ESX hosts
3
 *
4
 * Copyright (C) 2010-2015 Red Hat, Inc.
5
 * Copyright (C) 2009-2014 Matthias Bolte <matthias.bolte@googlemail.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 * 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
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
21 22 23 24 25 26
 *
 */

#include <config.h>

#include "internal.h"
27
#include "virdomainobjlist.h"
28
#include "snapshot_conf.h"
29
#include "virauth.h"
30
#include "viralloc.h"
31
#include "virfile.h"
32
#include "virlog.h"
33
#include "viruuid.h"
34
#include "vmx.h"
35
#include "virtypedparam.h"
36
#include "esx_driver.h"
37 38 39 40
#include "esx_interface_driver.h"
#include "esx_network_driver.h"
#include "esx_storage_driver.h"
#include "esx_private.h"
41 42 43
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
44
#include "esx_stream.h"
45
#include "virstring.h"
46
#include "viruri.h"
47 48 49

#define VIR_FROM_THIS VIR_FROM_ESX

50 51
VIR_LOG_INIT("esx.esx_driver");

52 53
static int esxDomainGetMaxVcpus(virDomainPtr domain);

54 55 56 57
typedef struct _esxVMX_Data esxVMX_Data;

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



63 64 65
static void
esxFreePrivate(esxPrivate **priv)
{
66
    if (!priv || !(*priv))
67 68 69 70 71
        return;

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



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

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

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

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

171
            tmp = (char *)STRSKIP(fileName, hostMount->mountInfo->path);
172

173
            if (!tmp)
174
                continue;
175

176
            /* Found a match. Strip leading separators */
177
            while (*tmp == '/' || *tmp == '\\')
178
                ++tmp;
179

180
            if (VIR_STRDUP(strippedFileName, tmp) < 0)
181
                goto cleanup;
182

183
            tmp = strippedFileName;
184

185 186
            /* Convert \ to / */
            while (*tmp != '\0') {
187
                if (*tmp == '\\')
188
                    *tmp = '/';
189

190 191
                ++tmp;
            }
192

193
            if (virAsprintf(&result, "[%s] %s", datastoreName,
194
                            strippedFileName) < 0)
195
                goto cleanup;
196

197 198
            break;
        }
199

200
        /* Fallback to direct datastore name match */
201
        if (!result && STRPREFIX(fileName, "/vmfs/volumes/")) {
202
            if (VIR_STRDUP(copyOfFileName, fileName) < 0)
203
                goto cleanup;
204

205
            /* Expected format: '/vmfs/volumes/<datastore>/<path>' */
206 207 208
            if (!(tmp = STRSKIP(copyOfFileName, "/vmfs/volumes/")) ||
                !(datastoreName = strtok_r(tmp, "/", &saveptr))    ||
                !(directoryAndFileName = strtok_r(NULL, "", &saveptr))) {
209 210 211
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("File name '%s' doesn't have expected format "
                                 "'/vmfs/volumes/<datastore>/<path>'"), fileName);
212 213
                goto cleanup;
            }
214

215
            esxVI_ObjectContent_Free(&datastoreList);
216

217 218 219 220 221
            if (esxVI_LookupDatastoreByName(data->ctx, datastoreName,
                                            NULL, &datastoreList,
                                            esxVI_Occurrence_OptionalItem) < 0) {
                goto cleanup;
            }
222

223
            if (!datastoreList) {
224 225 226
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("File name '%s' refers to non-existing datastore '%s'"),
                               fileName, datastoreName);
227 228
                goto cleanup;
            }
229

230
            if (virAsprintf(&result, "[%s] %s", datastoreName,
231
                            directoryAndFileName) < 0)
232
                goto cleanup;
233 234
        }

235
        /* If it's an absolute path outside of a datastore just use it as is */
236
        if (!result && *fileName == '/') {
237
            /* FIXME: need to deal with Windows paths here too */
238
            if (VIR_STRDUP(result, fileName) < 0)
239 240 241
                goto cleanup;
        }

242
        if (!result) {
243 244
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not handle file name '%s'"), fileName);
245
            goto cleanup;
246
        }
247
    }
248

249
 cleanup:
250 251 252 253 254
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&datastoreList);
    esxVI_DatastoreHostMount_Free(&hostMount);
    VIR_FREE(strippedFileName);
    VIR_FREE(copyOfFileName);
255

256
    return result;
257 258 259 260
}



261
/*
E
Eric Blake 已提交
262
 * This function does the inverse of esxParseVMXFileName. It takes a file name
263 264
 * in datastore path format or in absolute format and converts it to a file
 * name that can be used in a .vmx file.
265 266 267 268 269
 *
 * 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
270
 * datastore and its mount path. Finally concatenate the mount path, directory
E
Eric Blake 已提交
271
 * and file name to an absolute path and return it. Detect the separator type
272 273
 * based on the mount path.
 */
274
static char *
275
esxFormatVMXFileName(const char *fileName, void *opaque)
276 277
{
    bool success = false;
278
    char *result = NULL;
279
    esxVMX_Data *data = opaque;
280
    char *datastoreName = NULL;
281
    char *directoryAndFileName = NULL;
282 283 284 285 286
    esxVI_ObjectContent *datastore = NULL;
    esxVI_DatastoreHostMount *hostMount = NULL;
    char separator = '/';
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *tmp;
287
    size_t length;
288

289 290 291 292 293 294
    if (*fileName == '[') {
        /* Parse datastore path and lookup datastore */
        if (esxUtil_ParseDatastorePath(fileName, &datastoreName, NULL,
                                       &directoryAndFileName) < 0) {
            goto cleanup;
        }
295

296 297 298
        if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
                                        esxVI_Occurrence_RequiredItem) < 0 ||
            esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
299 300
                                           &hostMount,
                                           esxVI_Occurrence_RequiredItem) < 0) {
301 302
            goto cleanup;
        }
303

304
        /* Detect separator type */
305
        if (strchr(hostMount->mountInfo->path, '\\'))
306
            separator = '\\';
307

308 309
        /* Strip trailing separators */
        length = strlen(hostMount->mountInfo->path);
310

311
        while (length > 0 && hostMount->mountInfo->path[length - 1] == separator)
312
            --length;
313

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

317 318
        if (separator != '/') {
            tmp = directoryAndFileName;
319

320
            while (*tmp != '\0') {
321
                if (*tmp == '/')
322
                    *tmp = separator;
323

324 325
                ++tmp;
            }
326
        }
327

328 329
        virBufferAddChar(&buffer, separator);
        virBufferAdd(&buffer, directoryAndFileName, -1);
330

331
        if (virBufferCheckError(&buffer) < 0)
332 333 334 335 336
            goto cleanup;

        result = virBufferContentAndReset(&buffer);
    } else if (*fileName == '/') {
        /* FIXME: need to deal with Windows paths here too */
337
        if (VIR_STRDUP(result, fileName) < 0)
338 339
            goto cleanup;
    } else {
340 341
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not handle file name '%s'"), fileName);
342 343 344 345 346 347 348
        goto cleanup;
    }

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

    success = true;

349
 cleanup:
350
    if (! success) {
351
        virBufferFreeAndReset(&buffer);
352
        VIR_FREE(result);
353 354 355
    }

    VIR_FREE(datastoreName);
356
    VIR_FREE(directoryAndFileName);
357 358
    esxVI_ObjectContent_Free(&datastore);
    esxVI_DatastoreHostMount_Free(&hostMount);
359

360
    return result;
361 362 363 364 365 366 367 368 369 370
}



static int
esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model,
                                 void *opaque)
{
    int result = -1;
    esxVMX_Data *data = opaque;
371
    esxVI_FileInfo *fileInfo = NULL;
372
    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
373
    const char *src = virDomainDiskGetSource(def);
374 375 376

    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK ||
        def->bus != VIR_DOMAIN_DISK_BUS_SCSI ||
E
Eric Blake 已提交
377
        virDomainDiskGetType(def) != VIR_STORAGE_TYPE_FILE ||
378
        !src || !STRPREFIX(src, "[")) {
379 380 381 382 383 384 385
        /*
         * This isn't a file-based SCSI disk device with a datastore related
         * source path => do nothing.
         */
        return 0;
    }

386
    if (esxVI_LookupFileInfoByDatastorePath(data->ctx, src,
387
                                            false, &fileInfo,
388
                                            esxVI_Occurrence_RequiredItem) < 0) {
389 390 391
        goto cleanup;
    }

392
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
393

394
    if (!vmDiskFileInfo || !vmDiskFileInfo->controllerType) {
395
        virReportError(VIR_ERR_INTERNAL_ERROR,
396
                       _("Could not lookup controller model for '%s'"), src);
397 398 399 400 401
        goto cleanup;
    }

    if (STRCASEEQ(vmDiskFileInfo->controllerType,
                  "VirtualBusLogicController")) {
402
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
403 404
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicController")) {
405
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
406 407
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicSASController")) {
408
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068;
409 410
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "ParaVirtualSCSIController")) {
411
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI;
412
    } else {
413 414
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Found unexpected controller model '%s' for disk '%s'"),
415
                       vmDiskFileInfo->controllerType, src);
416 417 418 419 420
        goto cleanup;
    }

    result = 0;

421
 cleanup:
422
    esxVI_FileInfo_Free(&fileInfo);
423 424 425 426

    return result;
}

427 428


429
static esxVI_Boolean
430
esxSupportsLongMode(esxPrivate *priv)
431 432 433 434 435 436
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL;
    esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL;
437
    esxVI_ParsedHostCpuIdInfo parsedHostCpuIdInfo;
438 439
    char edxLongModeBit = '?';

440
    if (priv->supportsLongMode != esxVI_Boolean_Undefined)
441 442
        return priv->supportsLongMode;

443
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
444
        return esxVI_Boolean_Undefined;
445

446
    if (esxVI_String_AppendValueToList(&propertyNameList,
447
                                       "hardware.cpuFeature") < 0 ||
448 449
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
450
        goto cleanup;
451 452
    }

453
    for (dynamicProperty = hostSystem->propSet; dynamicProperty;
454 455 456
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuFeature")) {
            if (esxVI_HostCpuIdInfo_CastListFromAnyType
457
                  (dynamicProperty->val, &hostCpuIdInfoList) < 0) {
M
Matthias Bolte 已提交
458
                goto cleanup;
459 460
            }

461
            for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo;
462 463
                 hostCpuIdInfo = hostCpuIdInfo->_next) {
                if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */
464 465
                    if (esxVI_ParseHostCpuIdInfo(&parsedHostCpuIdInfo,
                                                 hostCpuIdInfo) < 0) {
M
Matthias Bolte 已提交
466
                        goto cleanup;
467 468
                    }

469
                    edxLongModeBit = parsedHostCpuIdInfo.edx[29];
470 471 472 473 474 475

                    if (edxLongModeBit == '1') {
                        priv->supportsLongMode = esxVI_Boolean_True;
                    } else if (edxLongModeBit == '0') {
                        priv->supportsLongMode = esxVI_Boolean_False;
                    } else {
476 477 478 479 480
                        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 已提交
481
                        goto cleanup;
482 483 484 485 486 487 488 489 490 491 492 493
                    }

                    break;
                }
            }

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

494
 cleanup:
M
Matthias Bolte 已提交
495 496 497 498
    /*
     * 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.
     */
499 500 501 502 503 504 505 506 507
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);
    esxVI_HostCpuIdInfo_Free(&hostCpuIdInfoList);

    return priv->supportsLongMode;
}



508 509 510 511 512 513
static int
esxLookupHostSystemBiosUuid(esxPrivate *priv, unsigned char *uuid)
{
    int result = -1;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
514
    char *uuid_string = NULL;
515

516
    if (esxVI_EnsureSession(priv->primary) < 0)
517 518 519 520
        return -1;

    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "hardware.systemInfo.uuid") < 0 ||
521
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
522 523 524
                                         &hostSystem) < 0 ||
        esxVI_GetStringValue(hostSystem, "hardware.systemInfo.uuid",
                             &uuid_string, esxVI_Occurrence_RequiredItem) < 0) {
525 526 527
        goto cleanup;
    }

528 529 530
    if (strlen(uuid_string) > 0) {
        if (virUUIDParse(uuid_string, uuid) < 0) {
            VIR_WARN("Could not parse host UUID from string '%s'", uuid_string);
531

532 533
            /* HostSystem has an invalid UUID, ignore it */
            memset(uuid, 0, VIR_UUID_BUFLEN);
534
        }
535 536 537
    } else {
        /* HostSystem has an empty UUID */
        memset(uuid, 0, VIR_UUID_BUFLEN);
538 539 540 541
    }

    result = 0;

542
 cleanup:
543 544 545 546 547 548 549
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}


550
static virCapsPtr
551
esxCapsInit(esxPrivate *priv)
552
{
553
    esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
554 555 556
    virCapsPtr caps = NULL;
    virCapsGuestPtr guest = NULL;

557
    if (supportsLongMode == esxVI_Boolean_Undefined)
558 559 560
        return NULL;

    if (supportsLongMode == esxVI_Boolean_True) {
561
        caps = virCapabilitiesNew(VIR_ARCH_X86_64, true, true);
562
    } else {
563
        caps = virCapabilitiesNew(VIR_ARCH_I686, true, true);
564
    }
565

566
    if (!caps)
567 568
        return NULL;

569
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
570

571

572
    if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0)
573 574
        goto failure;

575
    /* i686 */
576
    guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
577 578
                                    VIR_ARCH_I686,
                                    NULL, NULL, 0,
579
                                    NULL);
580

581
    if (!guest)
582 583
        goto failure;

584
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VMWARE, NULL, NULL, 0, NULL))
585 586
        goto failure;

587 588
    /* x86_64 */
    if (supportsLongMode == esxVI_Boolean_True) {
589
        guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
590 591
                                        VIR_ARCH_X86_64,
                                        NULL, NULL,
592 593
                                        0, NULL);

594
        if (!guest)
595 596
            goto failure;

597
        if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VMWARE, NULL, NULL, 0, NULL))
598 599 600
            goto failure;
    }

601 602
    return caps;

603
 failure:
604
    virObjectUnref(caps);
605 606 607 608 609 610

    return NULL;
}



611
static int
612 613
esxConnectToHost(esxPrivate *priv,
                 virConnectPtr conn,
614
                 virConnectAuthPtr auth,
615
                 char **vCenterIPAddress)
616 617 618 619 620 621 622 623 624
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
    char *password = NULL;
    char *url = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;
625 626 627
    esxVI_ProductLine expectedProductLine = STRCASEEQ(conn->uri->scheme, "esx")
        ? esxVI_ProductLine_ESX
        : esxVI_ProductLine_GSX;
628

629
    if (!vCenterIPAddress || *vCenterIPAddress) {
630
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
631 632 633
        return -1;
    }

634
    if (esxUtil_ResolveHostname(conn->uri->server, ipAddress, NI_MAXHOST) < 0)
635 636
        return -1;

637
    if (conn->uri->user) {
638
        if (VIR_STRDUP(username, conn->uri->user) < 0)
639 640
            goto cleanup;
    } else {
641
        username = virAuthGetUsername(conn, auth, "esx", "root", conn->uri->server);
642

643
        if (!username) {
644
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
645 646 647 648
            goto cleanup;
        }
    }

649
    password = virAuthGetPassword(conn, auth, "esx", username, conn->uri->server);
650

651
    if (!password) {
652
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
653 654 655
        goto cleanup;
    }

656
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
657
                    conn->uri->server, conn->uri->port) < 0)
658 659 660 661
        goto cleanup;

    if (esxVI_Context_Alloc(&priv->host) < 0 ||
        esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
662
                              priv->parsedUri) < 0 ||
663
        esxVI_Context_LookupManagedObjects(priv->host) < 0) {
664 665 666
        goto cleanup;
    }

667 668 669 670 671 672 673
    if (priv->host->productLine != expectedProductLine) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting '%s' to be a %s host but found a %s host"),
                       conn->uri->server,
                       esxVI_ProductLineToDisplayName(expectedProductLine),
                       esxVI_ProductLineToDisplayName(priv->host->productLine));
        goto cleanup;
674 675 676 677 678 679
    }

    /* Query the host for maintenance mode and vCenter IP address */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "runtime.inMaintenanceMode\0"
                                           "summary.managementServerIp\0") < 0 ||
680 681
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
682 683 684 685
        esxVI_GetBoolean(hostSystem, "runtime.inMaintenanceMode",
                         &inMaintenanceMode,
                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetStringValue(hostSystem, "summary.managementServerIp",
686
                             vCenterIPAddress,
687 688 689 690 691
                             esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

    /* Warn if host is in maintenance mode */
692
    if (inMaintenanceMode == esxVI_Boolean_True)
693
        VIR_WARN("The server is in maintenance mode");
694

695
    if (VIR_STRDUP(*vCenterIPAddress, *vCenterIPAddress) < 0)
696
        goto cleanup;
697 698 699

    result = 0;

700
 cleanup:
701
    VIR_FREE(username);
M
Matthias Bolte 已提交
702
    VIR_FREE(password);
703 704 705 706 707 708 709 710 711 712
    VIR_FREE(url);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



static int
713 714
esxConnectToVCenter(esxPrivate *priv,
                    virConnectPtr conn,
715 716
                    virConnectAuthPtr auth,
                    const char *hostname,
717
                    const char *hostSystemIPAddress)
718 719 720 721 722 723 724
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
    char *password = NULL;
    char *url = NULL;

725
    if (!hostSystemIPAddress &&
726
        (!priv->parsedUri->path || STREQ(priv->parsedUri->path, "/"))) {
727 728
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Path has to specify the datacenter and compute resource"));
729 730 731
        return -1;
    }

732
    if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST) < 0)
733 734
        return -1;

735
    if (conn->uri->user) {
736
        if (VIR_STRDUP(username, conn->uri->user) < 0)
737 738
            goto cleanup;
    } else {
739
        username = virAuthGetUsername(conn, auth, "esx", "administrator", hostname);
740

741
        if (!username) {
742
            virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
743 744 745 746
            goto cleanup;
        }
    }

747
    password = virAuthGetPassword(conn, auth, "esx", username, hostname);
748

749
    if (!password) {
750
        virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
751 752 753
        goto cleanup;
    }

754
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
755
                    hostname, conn->uri->port) < 0)
756 757 758 759
        goto cleanup;

    if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
        esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
760
                              password, priv->parsedUri) < 0) {
761 762 763
        goto cleanup;
    }

764
    if (priv->vCenter->productLine != esxVI_ProductLine_VPX) {
765
        virReportError(VIR_ERR_INTERNAL_ERROR,
766 767 768 769
                       _("Expecting '%s' to be a %s host but found a %s host"),
                       hostname,
                       esxVI_ProductLineToDisplayName(esxVI_ProductLine_VPX),
                       esxVI_ProductLineToDisplayName(priv->vCenter->productLine));
770 771 772
        goto cleanup;
    }

773
    if (hostSystemIPAddress) {
774
        if (esxVI_Context_LookupManagedObjectsByHostSystemIp
775
              (priv->vCenter, hostSystemIPAddress) < 0) {
776 777 778
            goto cleanup;
        }
    } else {
779 780
        if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter,
                                                     priv->parsedUri->path) < 0) {
781 782 783 784
            goto cleanup;
        }
    }

785 786
    result = 0;

787
 cleanup:
788
    VIR_FREE(username);
M
Matthias Bolte 已提交
789
    VIR_FREE(password);
790 791 792 793 794 795 796
    VIR_FREE(url);

    return result;
}



797
/*
798 799
 * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
 *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
800
 *
801 802
 * If no port is specified the default port is set dependent on the scheme and
 * transport parameter:
803 804
 * - vpx+http  80
 * - vpx+https 443
805
 * - esx+http  80
806
 * - esx+https 443
807 808 809
 * - gsx+http  8222
 * - gsx+https 8333
 *
810 811 812
 * 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
813 814
 * can be omitted. As datacenters and computeresources can be organized in
 * folders those have to be included in <path>.
815
 *
816 817
 * Optional query parameters:
 * - transport={http|https}
818
 * - vcenter={<vcenter>|*}             only useful for an esx:// connection
819 820
 * - no_verify={0|1}
 * - auto_answer={0|1}
M
Matthias Bolte 已提交
821
 * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
822
 *
823 824 825
 * If no transport parameter is specified https is used.
 *
 * The vcenter parameter is only necessary for migration, because the vCenter
826
 * server is in charge to initiate a migration between two ESX hosts. The
827
 * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
828 829
 * 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.
830 831
 *
 * If the no_verify parameter is set to 1, this disables libcurl client checks
832
 * of the server's certificate. The default value is 0.
833 834 835
 *
 * 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
836
 * questions will be reported as errors. The default value is 0.
M
Matthias Bolte 已提交
837 838 839 840
 *
 * 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.
841 842
 */
static virDrvOpenStatus
843
esxConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
844
               virConfPtr conf ATTRIBUTE_UNUSED,
845
               unsigned int flags)
846
{
M
Matthias Bolte 已提交
847
    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
848
    char *plus;
849
    esxPrivate *priv = NULL;
850 851
    char *potentialVCenterIPAddress = NULL;
    char vCenterIPAddress[NI_MAXHOST] = "";
852

E
Eric Blake 已提交
853 854
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

855
    /* Decline if the URI is NULL or the scheme is NULL */
856
    if (!conn->uri || !conn->uri->scheme)
857 858
        return VIR_DRV_OPEN_DECLINED;

859 860 861
    /* Decline if the scheme is not one of {vpx|esx|gsx} */
    plus = strchr(conn->uri->scheme, '+');

862
    if (!plus) {
863 864 865 866 867 868 869 870 871 872 873 874 875
        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;
        }

876 877 878
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Transport '%s' in URI scheme is not supported, try again "
                         "without the transport part"), plus + 1);
879 880 881
        return VIR_DRV_OPEN_ERROR;
    }

882
    if (STRCASENEQ(conn->uri->scheme, "vpx") &&
883
        conn->uri->path && STRNEQ(conn->uri->path, "/")) {
884 885 886 887
        VIR_WARN("Ignoring unexpected path '%s' for non-vpx scheme '%s'",
                 conn->uri->path, conn->uri->scheme);
    }

888
    /* Require server part */
889
    if (!conn->uri->server) {
890 891
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("URI is missing the server part"));
892 893 894 895
        return VIR_DRV_OPEN_ERROR;
    }

    /* Require auth */
896
    if (!auth || !auth->cb) {
897 898
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Missing or invalid auth pointer"));
899
        return VIR_DRV_OPEN_ERROR;
900 901 902
    }

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

906
    if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0)
907 908
        goto cleanup;

M
Matthias Bolte 已提交
909 910
    priv->maxVcpus = -1;
    priv->supportsVMotion = esxVI_Boolean_Undefined;
911
    priv->supportsLongMode = esxVI_Boolean_Undefined;
912
    priv->supportsScreenshot = esxVI_Boolean_Undefined;
913 914
    priv->usedCpuTimeCounterId = -1;

M
Matthias Bolte 已提交
915 916 917 918 919 920 921
    /*
     * 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) {
922 923
        if (STRCASEEQ(conn->uri->scheme, "vpx") ||
            STRCASEEQ(conn->uri->scheme, "esx")) {
924
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
925 926 927 928 929
                conn->uri->port = 443;
            } else {
                conn->uri->port = 80;
            }
        } else { /* GSX */
930
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
931 932 933 934
                conn->uri->port = 8333;
            } else {
                conn->uri->port = 8222;
            }
935
        }
M
Matthias Bolte 已提交
936
    }
937

938 939 940
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
941
        if (esxConnectToHost(priv, conn, auth,
942
                             &potentialVCenterIPAddress) < 0) {
M
Matthias Bolte 已提交
943
            goto cleanup;
944
        }
945

946
        /* Connect to vCenter */
947
        if (priv->parsedUri->vCenter) {
948
            if (STREQ(priv->parsedUri->vCenter, "*")) {
949
                if (!potentialVCenterIPAddress) {
950 951
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("This host is not managed by a vCenter"));
M
Matthias Bolte 已提交
952
                    goto cleanup;
953 954
                }

955 956
                if (!virStrcpyStatic(vCenterIPAddress,
                                     potentialVCenterIPAddress)) {
957 958
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("vCenter IP address %s too big for destination"),
959
                                   potentialVCenterIPAddress);
960 961 962
                    goto cleanup;
                }
            } else {
963
                if (esxUtil_ResolveHostname(priv->parsedUri->vCenter,
964
                                            vCenterIPAddress, NI_MAXHOST) < 0) {
965 966
                    goto cleanup;
                }
967

968 969
                if (potentialVCenterIPAddress &&
                    STRNEQ(vCenterIPAddress, potentialVCenterIPAddress)) {
970 971
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("This host is managed by a vCenter with IP "
N
Nitesh Konkar 已提交
972
                                     "address %s, but a mismatching vCenter '%s' "
973
                                     "(%s) has been specified"),
974 975
                                   potentialVCenterIPAddress, priv->parsedUri->vCenter,
                                   vCenterIPAddress);
M
Matthias Bolte 已提交
976
                    goto cleanup;
977 978
                }
            }
979

980
            if (esxConnectToVCenter(priv, conn, auth,
981
                                    vCenterIPAddress,
982
                                    priv->host->ipAddress) < 0) {
983 984
                goto cleanup;
            }
985 986
        }

987 988 989
        priv->primary = priv->host;
    } else { /* VPX */
        /* Connect to vCenter */
990
        if (esxConnectToVCenter(priv, conn, auth,
991 992
                                conn->uri->server,
                                NULL) < 0) {
M
Matthias Bolte 已提交
993
            goto cleanup;
994 995
        }

996
        priv->primary = priv->vCenter;
997 998
    }

M
Matthias Bolte 已提交
999
    /* Setup capabilities */
1000
    priv->caps = esxCapsInit(priv);
1001

1002
    if (!priv->caps)
M
Matthias Bolte 已提交
1003
        goto cleanup;
1004

1005
    if (!(priv->xmlopt = virVMXDomainXMLConfInit()))
1006 1007
        goto cleanup;

1008 1009
    conn->privateData = priv;
    priv = NULL;
M
Matthias Bolte 已提交
1010
    result = VIR_DRV_OPEN_SUCCESS;
1011

1012
 cleanup:
1013
    esxFreePrivate(&priv);
1014
    VIR_FREE(potentialVCenterIPAddress);
1015

M
Matthias Bolte 已提交
1016
    return result;
1017 1018 1019 1020 1021
}



static int
1022
esxConnectClose(virConnectPtr conn)
1023
{
M
Matthias Bolte 已提交
1024
    esxPrivate *priv = conn->privateData;
E
Eric Blake 已提交
1025
    int result = 0;
1026

1027
    if (priv->host) {
1028 1029 1030 1031 1032
        if (esxVI_EnsureSession(priv->host) < 0 ||
            esxVI_Logout(priv->host) < 0) {
            result = -1;
        }
    }
1033

1034
    if (priv->vCenter) {
E
Eric Blake 已提交
1035 1036 1037 1038
        if (esxVI_EnsureSession(priv->vCenter) < 0 ||
            esxVI_Logout(priv->vCenter) < 0) {
            result = -1;
        }
1039 1040
    }

1041
    esxFreePrivate(&priv);
1042 1043 1044

    conn->privateData = NULL;

E
Eric Blake 已提交
1045
    return result;
1046 1047 1048 1049 1050
}



static esxVI_Boolean
1051
esxSupportsVMotion(esxPrivate *priv)
1052 1053 1054 1055
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

1056
    if (priv->supportsVMotion != esxVI_Boolean_Undefined)
M
Matthias Bolte 已提交
1057
        return priv->supportsVMotion;
1058

1059
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1060
        return esxVI_Boolean_Undefined;
1061

1062
    if (esxVI_String_AppendValueToList(&propertyNameList,
1063
                                       "capability.vmotionSupported") < 0 ||
1064
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1065 1066
                                         &hostSystem) < 0 ||
        esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
1067 1068 1069
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1070 1071
    }

1072
 cleanup:
M
Matthias Bolte 已提交
1073 1074 1075 1076
    /*
     * 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.
     */
1077 1078 1079
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
1080
    return priv->supportsVMotion;
1081 1082 1083 1084
}



1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
static esxVI_Boolean
esxSupportsScreenshot(esxPrivate *priv)
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

    if (priv->supportsScreenshot != esxVI_Boolean_Undefined)
        return priv->supportsScreenshot;

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

    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "capability.screenshotSupported") < 0 ||
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0 ||
        esxVI_GetBoolean(hostSystem, "capability.screenshotSupported",
                         &priv->supportsScreenshot,
                         esxVI_Occurrence_RequiredItem) < 0)
        goto cleanup;

 cleanup:
    /*
     * If we goto cleanup in case of an error then priv->supportsScreenshot is
     * still esxVI_Boolean_Undefined, therefore we don't need to set it.
     */
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return priv->supportsScreenshot;
}



1119
static int
1120
esxConnectSupportsFeature(virConnectPtr conn, int feature)
1121
{
M
Matthias Bolte 已提交
1122
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1123
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1124 1125 1126

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1127
        supportsVMotion = esxSupportsVMotion(priv);
1128

1129
        if (supportsVMotion == esxVI_Boolean_Undefined)
1130 1131
            return -1;

M
Matthias Bolte 已提交
1132
        /* Migration is only possible via a vCenter and if VMotion is enabled */
1133
        return priv->vCenter &&
M
Matthias Bolte 已提交
1134
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1135 1136 1137 1138 1139 1140 1141 1142 1143

      default:
        return 0;
    }
}



static const char *
1144
esxConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
1145 1146 1147 1148 1149 1150 1151
{
    return "ESX";
}



static int
1152
esxConnectGetVersion(virConnectPtr conn, unsigned long *version)
1153
{
M
Matthias Bolte 已提交
1154
    esxPrivate *priv = conn->privateData;
1155

1156
    *version = priv->primary->productVersion;
1157 1158 1159 1160 1161 1162 1163

    return 0;
}



static char *
1164
esxConnectGetHostname(virConnectPtr conn)
1165
{
M
Matthias Bolte 已提交
1166
    esxPrivate *priv = conn->privateData;
1167 1168 1169 1170 1171 1172 1173
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1174
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1175
        return NULL;
1176 1177

    if (esxVI_String_AppendValueListToList
1178
          (&propertyNameList,
1179 1180
           "config.network.dnsConfig.hostName\0"
           "config.network.dnsConfig.domainName\0") < 0 ||
1181 1182
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1183
        goto cleanup;
1184 1185
    }

1186
    for (dynamicProperty = hostSystem->propSet; dynamicProperty;
1187 1188 1189
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1190
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1191
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1192
                goto cleanup;
1193 1194 1195 1196 1197
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1198
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1199
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1200
                goto cleanup;
1201 1202 1203 1204 1205 1206 1207 1208
            }

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

1209
    if (!hostName || strlen(hostName) < 1) {
1210 1211
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1212
        goto cleanup;
1213 1214
    }

1215
    if (!domainName || strlen(domainName) < 1) {
1216
        if (VIR_STRDUP(complete, hostName) < 0)
M
Matthias Bolte 已提交
1217
            goto cleanup;
1218
    } else {
1219
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0)
M
Matthias Bolte 已提交
1220
            goto cleanup;
1221 1222
    }

1223
 cleanup:
M
Matthias Bolte 已提交
1224 1225
    /*
     * If we goto cleanup in case of an error then complete is still NULL,
1226
     * either VIR_STRDUP returned -1 or virAsprintf failed. When virAsprintf
M
Matthias Bolte 已提交
1227 1228
     * fails it guarantees setting complete to NULL
     */
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1240
    int result = -1;
M
Matthias Bolte 已提交
1241
    esxPrivate *priv = conn->privateData;
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
    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;

1253
    memset(nodeinfo, 0, sizeof(*nodeinfo));
1254

1255
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1256
        return -1;
1257

1258
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1259 1260 1261 1262 1263 1264 1265
                                           "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 ||
1266 1267
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1268
        goto cleanup;
1269 1270
    }

1271
    for (dynamicProperty = hostSystem->propSet; dynamicProperty;
1272 1273
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1274
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1275
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1276
                goto cleanup;
1277 1278 1279 1280 1281
            }

            cpuInfo_hz = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuCores")) {
1282
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1283
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1284
                goto cleanup;
1285 1286 1287 1288 1289
            }

            cpuInfo_numCpuCores = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuPackages")) {
1290
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1291
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1292
                goto cleanup;
1293 1294 1295 1296 1297
            }

            cpuInfo_numCpuPackages = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuThreads")) {
1298
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1299
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1300
                goto cleanup;
1301 1302 1303 1304
            }

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1305
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1306
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1307
                goto cleanup;
1308 1309 1310 1311 1312
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1313
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1314
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1315
                goto cleanup;
1316 1317 1318 1319 1320
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1321
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1322
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1323
                goto cleanup;
1324 1325 1326 1327 1328 1329
            }

            ptr = dynamicProperty->val->string;

            /* Strip the string to fit more relevant information in 32 chars */
            while (*ptr != '\0') {
M
Matthias Bolte 已提交
1330 1331
                if (STRPREFIX(ptr, "  ")) {
                    memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1332
                    continue;
1333
                } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
M
Matthias Bolte 已提交
1334
                    memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1335
                    continue;
1336 1337 1338
                } else if (STRPREFIX(ptr, "(TM)")) {
                    memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
                    continue;
1339 1340 1341 1342 1343
                }

                ++ptr;
            }

1344 1345 1346
            if (!virStrncpy(nodeinfo->model, dynamicProperty->val->string,
                            sizeof(nodeinfo->model) - 1,
                            sizeof(nodeinfo->model))) {
1347 1348 1349
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("CPU Model %s too long for destination"),
                               dynamicProperty->val->string);
M
Matthias Bolte 已提交
1350
                goto cleanup;
C
Chris Lalancette 已提交
1351
            }
1352 1353 1354 1355 1356 1357 1358
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1359
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1360 1361 1362 1363 1364 1365 1366 1367 1368
    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 已提交
1369 1370
    result = 0;

1371
 cleanup:
1372 1373 1374 1375 1376 1377 1378 1379
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1380
static char *
1381
esxConnectGetCapabilities(virConnectPtr conn)
1382
{
M
Matthias Bolte 已提交
1383
    esxPrivate *priv = conn->privateData;
1384

1385
    return virCapabilitiesFormatXML(priv->caps);
1386 1387 1388 1389
}



1390
static int
1391
esxConnectListDomains(virConnectPtr conn, int *ids, int maxids)
1392
{
M
Matthias Bolte 已提交
1393
    bool success = false;
M
Matthias Bolte 已提交
1394
    esxPrivate *priv = conn->privateData;
1395 1396 1397 1398 1399 1400
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

1401
    if (maxids == 0)
1402 1403
        return 0;

1404
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1405
        return -1;
1406

1407
    if (esxVI_String_AppendValueToList(&propertyNameList,
1408
                                       "runtime.powerState") < 0 ||
1409 1410
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1411
        goto cleanup;
1412 1413
    }

1414
    for (virtualMachine = virtualMachineList; virtualMachine;
1415
         virtualMachine = virtualMachine->_next) {
1416
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1417
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1418
            goto cleanup;
1419 1420
        }

1421
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn)
1422 1423 1424 1425 1426
            continue;

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1427 1428 1429
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to parse positive integer from '%s'"),
                           virtualMachine->obj->value);
M
Matthias Bolte 已提交
1430
            goto cleanup;
1431 1432 1433 1434
        }

        count++;

1435
        if (count >= maxids)
1436 1437 1438
            break;
    }

M
Matthias Bolte 已提交
1439 1440
    success = true;

1441
 cleanup:
1442 1443 1444
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1445
    return success ? count : -1;
1446 1447 1448 1449 1450
}



static int
1451
esxConnectNumOfDomains(virConnectPtr conn)
1452
{
M
Matthias Bolte 已提交
1453
    esxPrivate *priv = conn->privateData;
1454

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

1458
    return esxVI_LookupNumberOfDomainsByPowerState
1459
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1460 1461 1462 1463 1464 1465 1466
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1467
    esxPrivate *priv = conn->privateData;
1468 1469 1470 1471
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1472 1473 1474
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1475 1476
    virDomainPtr domain = NULL;

1477
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1478
        return NULL;
1479

1480
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1481
                                           "configStatus\0"
1482 1483
                                           "name\0"
                                           "runtime.powerState\0"
1484
                                           "config.uuid\0") < 0 ||
1485 1486
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1487
        goto cleanup;
1488 1489
    }

1490
    for (virtualMachine = virtualMachineList; virtualMachine;
1491
         virtualMachine = virtualMachine->_next) {
1492
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1493
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1494
            goto cleanup;
1495 1496 1497
        }

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

M
Matthias Bolte 已提交
1501
        VIR_FREE(name_candidate);
1502

1503
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1504 1505
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1506
            goto cleanup;
1507 1508
        }

1509
        if (id != id_candidate)
1510 1511
            continue;

1512
        domain = virGetDomain(conn, name_candidate, uuid_candidate, id);
1513

1514
        if (!domain)
M
Matthias Bolte 已提交
1515
            goto cleanup;
1516 1517 1518 1519

        break;
    }

1520
    if (!domain)
1521
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1522

1523
 cleanup:
1524 1525
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1526
    VIR_FREE(name_candidate);
1527 1528 1529 1530 1531 1532 1533 1534 1535

    return domain;
}



static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
M
Matthias Bolte 已提交
1536
    esxPrivate *priv = conn->privateData;
1537 1538 1539
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1540 1541
    int id = -1;
    char *name = NULL;
1542 1543
    virDomainPtr domain = NULL;

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

1547
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1548
                                           "name\0"
1549
                                           "runtime.powerState\0") < 0 ||
1550
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1551
                                         &virtualMachine,
M
Matthias Bolte 已提交
1552
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1553 1554
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1555
        goto cleanup;
1556 1557
    }

1558
    /* Only running/suspended virtual machines have an ID != -1 */
1559 1560 1561 1562
    if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
        id = -1;

    domain = virGetDomain(conn, name, uuid, id);
1563

1564
 cleanup:
1565
    esxVI_String_Free(&propertyNameList);
1566 1567
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1568 1569 1570 1571 1572 1573 1574 1575 1576

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1577
    esxPrivate *priv = conn->privateData;
1578 1579 1580
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1581 1582
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1583 1584
    virDomainPtr domain = NULL;

1585
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1586
        return NULL;
1587

1588
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1589
                                           "configStatus\0"
1590
                                           "runtime.powerState\0"
1591
                                           "config.uuid\0") < 0 ||
1592
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1593 1594
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1595
        goto cleanup;
1596 1597
    }

1598
    if (!virtualMachine) {
1599
        virReportError(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1600
        goto cleanup;
1601
    }
1602

M
Matthias Bolte 已提交
1603 1604 1605
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1606
    }
1607

1608
    /* Only running/suspended virtual machines have an ID != -1 */
1609 1610 1611 1612
    if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
        id = -1;

    domain = virGetDomain(conn, name, uuid, id);
1613

1614
 cleanup:
1615
    esxVI_String_Free(&propertyNameList);
1616
    esxVI_ObjectContent_Free(&virtualMachine);
1617 1618 1619 1620 1621 1622 1623 1624 1625

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1626
    int result = -1;
M
Matthias Bolte 已提交
1627
    esxPrivate *priv = domain->conn->privateData;
1628 1629 1630 1631 1632
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1633
    char *taskInfoErrorMessage = NULL;
1634

1635
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1636
        return -1;
1637

1638
    if (esxVI_String_AppendValueToList(&propertyNameList,
1639
                                       "runtime.powerState") < 0 ||
1640
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1641
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1642
           priv->parsedUri->autoAnswer) < 0 ||
1643
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1644
        goto cleanup;
1645 1646 1647
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1648 1649
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1650
        goto cleanup;
1651 1652
    }

1653 1654
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1655
                                    esxVI_Occurrence_RequiredItem,
1656
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1657
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1658
        goto cleanup;
1659 1660 1661
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1662 1663
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1664
        goto cleanup;
1665 1666
    }

M
Matthias Bolte 已提交
1667 1668
    result = 0;

1669
 cleanup:
1670 1671 1672
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1673
    VIR_FREE(taskInfoErrorMessage);
1674 1675 1676 1677 1678 1679 1680 1681 1682

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1683
    int result = -1;
M
Matthias Bolte 已提交
1684
    esxPrivate *priv = domain->conn->privateData;
1685 1686 1687 1688 1689
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1690
    char *taskInfoErrorMessage = NULL;
1691

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

1695
    if (esxVI_String_AppendValueToList(&propertyNameList,
1696
                                       "runtime.powerState") < 0 ||
1697
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1698
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1699
           priv->parsedUri->autoAnswer) < 0 ||
1700
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1701
        goto cleanup;
1702 1703 1704
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1705
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1706
        goto cleanup;
1707 1708
    }

1709
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1710
                             &task) < 0 ||
1711
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1712
                                    esxVI_Occurrence_RequiredItem,
1713
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1714
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1715
        goto cleanup;
1716 1717 1718
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1719 1720
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1721
        goto cleanup;
1722 1723
    }

M
Matthias Bolte 已提交
1724 1725
    result = 0;

1726
 cleanup:
1727 1728 1729
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1730
    VIR_FREE(taskInfoErrorMessage);
1731 1732 1733 1734 1735 1736 1737

    return result;
}



static int
1738
esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
1739
{
M
Matthias Bolte 已提交
1740
    int result = -1;
M
Matthias Bolte 已提交
1741
    esxPrivate *priv = domain->conn->privateData;
1742 1743 1744 1745
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1746 1747
    virCheckFlags(0, -1);

1748
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1749
        return -1;
1750

1751
    if (esxVI_String_AppendValueToList(&propertyNameList,
1752
                                       "runtime.powerState") < 0 ||
1753
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1754
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1755
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1756
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1757
        goto cleanup;
1758 1759 1760
    }

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

1766
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0)
M
Matthias Bolte 已提交
1767
        goto cleanup;
1768

M
Matthias Bolte 已提交
1769 1770
    result = 0;

1771
 cleanup:
1772 1773 1774 1775 1776 1777 1778
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


1779 1780 1781 1782 1783 1784
static int
esxDomainShutdown(virDomainPtr domain)
{
    return esxDomainShutdownFlags(domain, 0);
}

1785 1786

static int
E
Eric Blake 已提交
1787
esxDomainReboot(virDomainPtr domain, unsigned int flags)
1788
{
M
Matthias Bolte 已提交
1789
    int result = -1;
M
Matthias Bolte 已提交
1790
    esxPrivate *priv = domain->conn->privateData;
1791 1792 1793 1794
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

E
Eric Blake 已提交
1795 1796
    virCheckFlags(0, -1);

1797
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1798
        return -1;
1799

1800
    if (esxVI_String_AppendValueToList(&propertyNameList,
1801
                                       "runtime.powerState") < 0 ||
1802
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1803
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1804
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1805
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1806
        goto cleanup;
1807 1808 1809
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1810 1811
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1812
        goto cleanup;
1813 1814
    }

1815
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0)
M
Matthias Bolte 已提交
1816
        goto cleanup;
1817

M
Matthias Bolte 已提交
1818 1819
    result = 0;

1820
 cleanup:
1821 1822 1823 1824 1825 1826 1827 1828 1829
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
1830 1831
esxDomainDestroyFlags(virDomainPtr domain,
                      unsigned int flags)
1832
{
M
Matthias Bolte 已提交
1833
    int result = -1;
M
Matthias Bolte 已提交
1834
    esxPrivate *priv = domain->conn->privateData;
1835
    esxVI_Context *ctx = NULL;
1836 1837 1838 1839 1840
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1841
    char *taskInfoErrorMessage = NULL;
1842

1843 1844
    virCheckFlags(0, -1);

1845
    if (priv->vCenter) {
1846 1847 1848 1849 1850
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1851
    if (esxVI_EnsureSession(ctx) < 0)
M
Matthias Bolte 已提交
1852
        return -1;
1853

1854
    if (esxVI_String_AppendValueToList(&propertyNameList,
1855
                                       "runtime.powerState") < 0 ||
1856
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1857
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1858
           priv->parsedUri->autoAnswer) < 0 ||
1859
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1860
        goto cleanup;
1861 1862 1863
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1864 1865
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
M
Matthias Bolte 已提交
1866
        goto cleanup;
1867 1868
    }

1869
    if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1870 1871
        esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
1872
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1873
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1874
        goto cleanup;
1875 1876 1877
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1878 1879
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
1880
        goto cleanup;
1881 1882
    }

1883
    domain->id = -1;
M
Matthias Bolte 已提交
1884 1885
    result = 0;

1886
 cleanup:
1887 1888 1889
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1890
    VIR_FREE(taskInfoErrorMessage);
1891 1892 1893 1894 1895

    return result;
}


1896 1897 1898 1899 1900 1901
static int
esxDomainDestroy(virDomainPtr dom)
{
    return esxDomainDestroyFlags(dom, 0);
}

1902 1903

static char *
1904
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
1905
{
1906
    char *osType;
1907

1908
    ignore_value(VIR_STRDUP(osType, "hvm"));
1909
    return osType;
1910 1911 1912 1913
}



1914
static unsigned long long
1915 1916
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1917
    esxPrivate *priv = domain->conn->privateData;
1918 1919 1920 1921 1922
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

1923
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1924
        return 0;
1925

1926
    if (esxVI_String_AppendValueToList(&propertyNameList,
1927
                                       "config.hardware.memoryMB") < 0 ||
1928
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1929
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1930
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
1931
        goto cleanup;
1932 1933
    }

1934
    for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
1935 1936
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
1937
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1938
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1939
                goto cleanup;
1940 1941 1942
            }

            if (dynamicProperty->val->int32 < 0) {
1943 1944 1945
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Got invalid memory size %d"),
                               dynamicProperty->val->int32);
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
            } else {
                memoryMB = dynamicProperty->val->int32;
            }

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

1956
 cleanup:
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
    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 已提交
1968
    int result = -1;
M
Matthias Bolte 已提交
1969
    esxPrivate *priv = domain->conn->privateData;
1970
    esxVI_String *propertyNameList = NULL;
1971
    esxVI_ObjectContent *virtualMachine = NULL;
1972
    esxVI_VirtualMachinePowerState powerState;
1973 1974 1975
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1976
    char *taskInfoErrorMessage = NULL;
1977

1978
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
1979
        return -1;
1980

1981 1982 1983 1984
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1985
           priv->parsedUri->autoAnswer) < 0 ||
1986 1987 1988 1989 1990
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
1991 1992
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
1993 1994 1995 1996
        goto cleanup;
    }

    if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
1997
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
1998
        goto cleanup;
1999 2000
    }

2001
    /* max-memory must be a multiple of 4096 kilobyte */
2002
    spec->memoryMB->value =
2003
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2004

2005
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2006
                              &task) < 0 ||
2007
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2008
                                    esxVI_Occurrence_RequiredItem,
2009
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2010
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2011
        goto cleanup;
2012 2013 2014
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2015 2016 2017
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set max-memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2018
        goto cleanup;
2019 2020
    }

M
Matthias Bolte 已提交
2021 2022
    result = 0;

2023
 cleanup:
2024
    esxVI_String_Free(&propertyNameList);
2025 2026 2027
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2028
    VIR_FREE(taskInfoErrorMessage);
2029 2030 2031 2032 2033 2034 2035 2036 2037

    return result;
}



static int
esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2038
    int result = -1;
M
Matthias Bolte 已提交
2039
    esxPrivate *priv = domain->conn->privateData;
2040 2041 2042 2043
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2044
    char *taskInfoErrorMessage = NULL;
2045

2046
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2047
        return -1;
2048

2049
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2050
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2051
           priv->parsedUri->autoAnswer) < 0 ||
2052 2053 2054
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
        esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
M
Matthias Bolte 已提交
2055
        goto cleanup;
2056 2057 2058
    }

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

2061
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2062
                              &task) < 0 ||
2063
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2064
                                    esxVI_Occurrence_RequiredItem,
2065
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2066
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2067
        goto cleanup;
2068 2069 2070
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2071 2072 2073
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set memory to %lu kilobytes: %s"), memory,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2074
        goto cleanup;
2075 2076
    }

M
Matthias Bolte 已提交
2077 2078
    result = 0;

2079
 cleanup:
2080 2081 2082
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2083
    VIR_FREE(taskInfoErrorMessage);
2084 2085 2086 2087 2088 2089

    return result;
}



2090 2091 2092 2093 2094 2095 2096 2097 2098
/*
 * 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

2099 2100 2101
static int
esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
M
Matthias Bolte 已提交
2102
    int result = -1;
M
Matthias Bolte 已提交
2103
    esxPrivate *priv = domain->conn->privateData;
2104 2105 2106 2107 2108
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int64_t memory_limit = -1;
2109
#if ESX_QUERY_FOR_USED_CPU_TIME
2110 2111 2112 2113 2114 2115 2116
    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;
2117 2118
    esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
    esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2119 2120 2121
    esxVI_PerfEntityMetric *perfEntityMetric = NULL;
    esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
    esxVI_Long *value = NULL;
2122
#endif
2123

2124
    memset(info, 0, sizeof(*info));
M
Matthias Bolte 已提交
2125

2126
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2127
        return -1;
2128

2129
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2130 2131 2132 2133
                                           "runtime.powerState\0"
                                           "config.hardware.memoryMB\0"
                                           "config.hardware.numCPU\0"
                                           "config.memoryAllocation.limit\0") < 0 ||
2134
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2135
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2136
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2137
        goto cleanup;
2138 2139 2140 2141
    }

    info->state = VIR_DOMAIN_NOSTATE;

2142
    for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2143 2144 2145
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.powerState")) {
            if (esxVI_VirtualMachinePowerState_CastFromAnyType
2146
                  (dynamicProperty->val, &powerState) < 0) {
M
Matthias Bolte 已提交
2147
                goto cleanup;
2148 2149
            }

2150 2151
            info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                            (powerState);
2152
        } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2153
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2154
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2155
                goto cleanup;
2156 2157 2158 2159
            }

            info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
        } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2160
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2161
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2162
                goto cleanup;
2163 2164 2165 2166 2167
            }

            info->nrVirtCpu = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "config.memoryAllocation.limit")) {
2168
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2169
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
2170
                goto cleanup;
2171 2172 2173 2174
            }

            memory_limit = dynamicProperty->val->int64;

2175
            if (memory_limit > 0)
2176 2177 2178 2179 2180 2181 2182 2183 2184
                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;

2185
#if ESX_QUERY_FOR_USED_CPU_TIME
2186
    /* Verify the cached 'used CPU time' performance counter ID */
2187
    /* FIXME: Currently no host for a vpx:// connection */
2188
    if (priv->host) {
2189
        if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
2190
            if (esxVI_Int_Alloc(&counterId) < 0)
2191
                goto cleanup;
2192

2193
            counterId->value = priv->usedCpuTimeCounterId;
2194

2195
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0)
2196
                goto cleanup;
2197

2198 2199 2200 2201
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2202

2203 2204 2205 2206 2207
            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);
2208

2209 2210 2211 2212 2213
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2214 2215
        }

2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
        /*
         * 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;
            }
2226

2227
            for (perfMetricId = perfMetricIdList; perfMetricId;
2228 2229 2230
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2231

2232
                counterId = NULL;
2233

2234 2235 2236 2237 2238
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2239

2240 2241
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2242
                goto cleanup;
2243 2244
            }

2245
            for (perfCounterInfo = perfCounterInfoList; perfCounterInfo;
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
                 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;
                }
2262 2263
            }

2264
            if (priv->usedCpuTimeCounterId < 0)
2265
                VIR_WARN("Could not find 'used CPU time' performance counter");
2266 2267
        }

2268 2269 2270 2271 2272 2273
        /*
         * 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);
2274

2275 2276 2277 2278 2279 2280
            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;
            }
2281

2282 2283 2284 2285 2286 2287 2288 2289 2290 2291
            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;
            }
2292

2293
            for (perfEntityMetricBase = perfEntityMetricBaseList;
2294
                 perfEntityMetricBase;
2295
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2296
                VIR_DEBUG("perfEntityMetric ...");
2297

2298 2299
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2300

2301
                if (!perfEntityMetric) {
2302 2303 2304
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetricBase->_type));
2305
                    goto cleanup;
2306
                }
2307

2308 2309
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2310

2311
                if (!perfMetricIntSeries) {
2312 2313 2314
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("QueryPerf returned object with unexpected type '%s'"),
                                   esxVI_Type_ToString(perfEntityMetric->value->_type));
2315
                    goto cleanup;
2316
                }
2317

2318
                for (; perfMetricIntSeries;
2319
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2320
                    VIR_DEBUG("perfMetricIntSeries ...");
2321

2322
                    for (value = perfMetricIntSeries->value;
2323
                         value;
2324 2325 2326
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2327 2328 2329
                }
            }

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

2332
            /*
E
Eric Blake 已提交
2333
             * FIXME: Cannot map between relative used-cpu-time and absolute
2334 2335 2336
             *        info->cpuTime
             */
        }
2337
    }
2338
#endif
2339

M
Matthias Bolte 已提交
2340 2341
    result = 0;

2342
 cleanup:
2343
#if ESX_QUERY_FOR_USED_CPU_TIME
2344 2345 2346 2347
    /*
     * Remove values owned by data structures to prevent them from being freed
     * by the call to esxVI_PerfQuerySpec_Free().
     */
2348
    if (querySpec) {
2349 2350 2351
        querySpec->entity = NULL;
        querySpec->format = NULL;

2352
        if (querySpec->metricId)
2353 2354
            querySpec->metricId->instance = NULL;
    }
2355
#endif
2356

2357 2358
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2359
#if ESX_QUERY_FOR_USED_CPU_TIME
2360 2361 2362 2363
    esxVI_PerfMetricId_Free(&perfMetricIdList);
    esxVI_Int_Free(&counterIdList);
    esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
    esxVI_PerfQuerySpec_Free(&querySpec);
2364
    esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2365
#endif
2366 2367 2368 2369 2370 2371

    return result;
}



2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385
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);

2386
    if (esxVI_EnsureSession(priv->primary) < 0)
2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
        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;

2405
 cleanup:
2406 2407 2408 2409 2410 2411 2412 2413
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
}



2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
static char *
esxDomainScreenshot(virDomainPtr domain, virStreamPtr stream,
                    unsigned int screen, unsigned int flags)
{
    char *mimeType = NULL;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_Boolean supportsScreenshot = esxVI_Boolean_Undefined;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *url = NULL;

    virCheckFlags(0, NULL);

    if (screen != 0) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Screen cannot be selected"));
        return NULL;
    }

    supportsScreenshot = esxSupportsScreenshot(priv);

    if (supportsScreenshot == esxVI_Boolean_Undefined)
        return NULL;

    if (supportsScreenshot != esxVI_Boolean_True) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Screenshot feature is unsupported"));
        return NULL;
    }

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

    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;

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered on"));
        goto cleanup;
    }

    /* Build URL */
    virBufferAsprintf(&buffer, "%s://%s:%d/screen?id=", priv->parsedUri->transport,
                      domain->conn->uri->server, domain->conn->uri->port);
    virBufferURIEncodeString(&buffer, virtualMachine->obj->value);

    if (virBufferCheckError(&buffer))
        goto cleanup;

    url = virBufferContentAndReset(&buffer);

    if (VIR_STRDUP(mimeType, "image/png") < 0)
        goto cleanup;

    if (esxStreamOpenDownload(stream, priv, url, 0, 0) < 0) {
        VIR_FREE(mimeType);
        goto cleanup;
    }

 cleanup:
    virBufferFreeAndReset(&buffer);

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

    return mimeType;
}



2492
static int
2493 2494
esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                       unsigned int flags)
2495
{
M
Matthias Bolte 已提交
2496
    int result = -1;
M
Matthias Bolte 已提交
2497
    esxPrivate *priv = domain->conn->privateData;
M
Matthias Bolte 已提交
2498
    int maxVcpus;
2499 2500 2501 2502
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2503
    char *taskInfoErrorMessage = NULL;
2504

2505
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2506
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2507 2508 2509
        return -1;
    }

2510
    if (nvcpus < 1) {
2511 2512
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2513
        return -1;
2514 2515
    }

2516
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2517
        return -1;
2518

M
Matthias Bolte 已提交
2519
    maxVcpus = esxDomainGetMaxVcpus(domain);
2520

2521
    if (maxVcpus < 0)
M
Matthias Bolte 已提交
2522
        return -1;
2523

M
Matthias Bolte 已提交
2524
    if (nvcpus > maxVcpus) {
2525 2526 2527 2528
        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 已提交
2529
        return -1;
2530 2531
    }

2532
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2533
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2534
           priv->parsedUri->autoAnswer) < 0 ||
2535 2536
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_Int_Alloc(&spec->numCPUs) < 0) {
M
Matthias Bolte 已提交
2537
        goto cleanup;
2538 2539 2540 2541
    }

    spec->numCPUs->value = nvcpus;

2542
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2543
                              &task) < 0 ||
2544
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2545
                                    esxVI_Occurrence_RequiredItem,
2546
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2547
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2548
        goto cleanup;
2549 2550 2551
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2552 2553 2554
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2555
        goto cleanup;
2556 2557
    }

M
Matthias Bolte 已提交
2558 2559
    result = 0;

2560
 cleanup:
2561 2562 2563
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2564
    VIR_FREE(taskInfoErrorMessage);
2565 2566 2567 2568 2569

    return result;
}


M
Matthias Bolte 已提交
2570

2571 2572 2573
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
2574
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2575 2576
}

2577

M
Matthias Bolte 已提交
2578

2579
static int
2580
esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2581
{
M
Matthias Bolte 已提交
2582
    esxPrivate *priv = domain->conn->privateData;
2583 2584 2585 2586
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

2587
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2588
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2589 2590 2591
        return -1;
    }

2592
    if (priv->maxVcpus > 0)
M
Matthias Bolte 已提交
2593
        return priv->maxVcpus;
2594

M
Matthias Bolte 已提交
2595 2596
    priv->maxVcpus = -1;

2597
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2598
        return -1;
2599

2600
    if (esxVI_String_AppendValueToList(&propertyNameList,
2601
                                       "capability.maxSupportedVcpus") < 0 ||
2602 2603
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
2604
        goto cleanup;
2605 2606
    }

2607
    for (dynamicProperty = hostSystem->propSet; dynamicProperty;
2608 2609
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2610
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2611
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2612
                goto cleanup;
2613 2614
            }

M
Matthias Bolte 已提交
2615
            priv->maxVcpus = dynamicProperty->val->int32;
2616 2617 2618 2619 2620 2621
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

2622
 cleanup:
2623 2624 2625
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
2626
    return priv->maxVcpus;
2627 2628
}

M
Matthias Bolte 已提交
2629 2630


2631 2632 2633
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
2634
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2635 2636
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2637

M
Matthias Bolte 已提交
2638 2639


2640
static char *
2641
esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2642
{
M
Matthias Bolte 已提交
2643
    esxPrivate *priv = domain->conn->privateData;
2644 2645
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2646 2647
    esxVI_VirtualMachinePowerState powerState;
    int id;
2648
    char *moref = NULL;
2649
    char *vmPathName = NULL;
2650
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2651
    char *directoryName = NULL;
2652
    char *directoryAndFileName = NULL;
2653
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2654 2655
    char *url = NULL;
    char *vmx = NULL;
2656
    virVMXContext ctx;
2657
    esxVMX_Data data;
2658 2659 2660
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2661 2662
    /* Flags checked by virDomainDefFormat */

2663
    memset(&data, 0, sizeof(data));
2664

2665
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2666
        return NULL;
2667

2668 2669 2670
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "config.files.vmPathName\0"
                                           "runtime.powerState\0") < 0 ||
2671
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2672
                                         propertyNameList, &virtualMachine,
2673
                                         esxVI_Occurrence_RequiredItem) < 0 ||
2674
        esxVI_GetVirtualMachineMORef(virtualMachine, &moref) < 0 ||
2675 2676
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2677 2678
        esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
                             &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2679
        goto cleanup;
2680 2681
    }

2682
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2683
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2684
        goto cleanup;
2685 2686
    }

2687
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2688
                      domain->conn->uri->server, domain->conn->uri->port);
2689
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2690
    virBufferAddLit(&buffer, "?dcPath=");
2691
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
2692 2693 2694
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

2695
    if (virBufferCheckError(&buffer) < 0)
M
Matthias Bolte 已提交
2696
        goto cleanup;
2697

2698 2699
    url = virBufferContentAndReset(&buffer);

2700
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx, 0, NULL) < 0)
M
Matthias Bolte 已提交
2701
        goto cleanup;
2702

2703
    data.ctx = priv->primary;
2704

2705
    if (!directoryName) {
2706
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s]",
2707
                        datastoreName) < 0)
2708 2709 2710
            goto cleanup;
    } else {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s] %s",
2711
                        datastoreName, directoryName) < 0)
2712 2713
            goto cleanup;
    }
2714 2715 2716 2717 2718

    ctx.opaque = &data;
    ctx.parseFileName = esxParseVMXFileName;
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;
2719
    ctx.datacenterPath = priv->primary->datacenterPath;
2720
    ctx.moref = moref;
2721

2722
    def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, vmx);
2723

2724
    if (def) {
2725
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff)
2726 2727
            def->id = id;

2728
        xml = virDomainDefFormat(def, priv->caps,
2729
                                 virDomainDefFormatConvertXMLFlags(flags));
2730 2731
    }

2732
 cleanup:
2733
    if (!url)
M
Matthias Bolte 已提交
2734 2735
        virBufferFreeAndReset(&buffer);

2736 2737
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2738
    VIR_FREE(moref);
2739
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2740
    VIR_FREE(directoryName);
2741
    VIR_FREE(directoryAndFileName);
2742
    VIR_FREE(url);
2743
    VIR_FREE(data.datastorePathWithoutFileName);
2744
    VIR_FREE(vmx);
2745
    virDomainDefFree(def);
2746 2747 2748 2749 2750 2751 2752

    return xml;
}



static char *
2753 2754 2755
esxConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                              const char *nativeConfig,
                              unsigned int flags)
2756
{
M
Matthias Bolte 已提交
2757
    esxPrivate *priv = conn->privateData;
2758
    virVMXContext ctx;
2759
    esxVMX_Data data;
2760 2761 2762
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2763 2764
    virCheckFlags(0, NULL);

2765
    memset(&data, 0, sizeof(data));
2766

2767
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2768 2769
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
2770
        return NULL;
2771 2772
    }

2773
    data.ctx = priv->primary;
2774
    data.datastorePathWithoutFileName = (char *)"[?] ?";
2775 2776 2777 2778 2779

    ctx.opaque = &data;
    ctx.parseFileName = esxParseVMXFileName;
    ctx.formatFileName = NULL;
    ctx.autodetectSCSIControllerModel = NULL;
2780
    ctx.datacenterPath = NULL;
2781
    ctx.moref = NULL;
2782

2783
    def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, nativeConfig);
2784

2785
    if (def)
2786 2787
        xml = virDomainDefFormat(def, priv->caps,
                                 VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2788 2789 2790 2791 2792 2793 2794 2795

    virDomainDefFree(def);

    return xml;
}



M
Matthias Bolte 已提交
2796
static char *
2797 2798 2799
esxConnectDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                            const char *domainXml,
                            unsigned int flags)
M
Matthias Bolte 已提交
2800
{
M
Matthias Bolte 已提交
2801
    esxPrivate *priv = conn->privateData;
2802 2803
    int virtualHW_version;
    virVMXContext ctx;
2804
    esxVMX_Data data;
M
Matthias Bolte 已提交
2805 2806 2807
    virDomainDefPtr def = NULL;
    char *vmx = NULL;

E
Eric Blake 已提交
2808 2809
    virCheckFlags(0, NULL);

2810
    memset(&data, 0, sizeof(data));
2811

M
Matthias Bolte 已提交
2812
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2813 2814
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unsupported config format '%s'"), nativeFormat);
M
Matthias Bolte 已提交
2815 2816 2817
        return NULL;
    }

2818
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
2819
                          (priv->primary->productLine, priv->primary->productVersion);
2820

2821
    if (virtualHW_version < 0)
2822 2823
        return NULL;

2824
    def = virDomainDefParseString(domainXml, priv->caps, priv->xmlopt,
2825
                                  NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE);
M
Matthias Bolte 已提交
2826

2827
    if (!def)
M
Matthias Bolte 已提交
2828 2829
        return NULL;

2830
    data.ctx = priv->primary;
2831
    data.datastorePathWithoutFileName = NULL;
2832 2833 2834 2835 2836

    ctx.opaque = &data;
    ctx.parseFileName = NULL;
    ctx.formatFileName = esxFormatVMXFileName;
    ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
2837
    ctx.datacenterPath = NULL;
2838
    ctx.moref = NULL;
2839

2840
    vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
M
Matthias Bolte 已提交
2841 2842 2843 2844 2845 2846 2847 2848

    virDomainDefFree(def);

    return vmx;
}



2849
static int
2850
esxConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
2851
{
M
Matthias Bolte 已提交
2852
    bool success = false;
M
Matthias Bolte 已提交
2853
    esxPrivate *priv = conn->privateData;
2854 2855 2856 2857 2858
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;
2859
    size_t i;
2860

2861
    if (maxnames == 0)
2862 2863
        return 0;

2864
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2865
        return -1;
2866

2867
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2868 2869
                                           "name\0"
                                           "runtime.powerState\0") < 0 ||
2870 2871
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
2872
        goto cleanup;
2873 2874
    }

2875
    for (virtualMachine = virtualMachineList; virtualMachine;
2876
         virtualMachine = virtualMachine->_next) {
2877
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2878
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
2879
            goto cleanup;
2880 2881
        }

2882
        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn)
2883 2884
            continue;

2885
        names[count] = NULL;
2886

2887 2888 2889
        if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
                                            NULL) < 0) {
            goto cleanup;
2890 2891
        }

2892 2893
        ++count;

2894
        if (count >= maxnames)
2895 2896 2897
            break;
    }

M
Matthias Bolte 已提交
2898
    success = true;
2899

2900
 cleanup:
M
Matthias Bolte 已提交
2901
    if (! success) {
2902
        for (i = 0; i < count; ++i)
M
Matthias Bolte 已提交
2903
            VIR_FREE(names[i]);
2904

M
Matthias Bolte 已提交
2905
        count = -1;
2906 2907
    }

M
Matthias Bolte 已提交
2908 2909
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2910

M
Matthias Bolte 已提交
2911
    return count;
2912 2913 2914 2915 2916
}



static int
2917
esxConnectNumOfDefinedDomains(virConnectPtr conn)
2918
{
M
Matthias Bolte 已提交
2919
    esxPrivate *priv = conn->privateData;
2920

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

2924
    return esxVI_LookupNumberOfDomainsByPowerState
2925
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
2926 2927 2928 2929 2930
}



static int
2931
esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
2932
{
M
Matthias Bolte 已提交
2933
    int result = -1;
M
Matthias Bolte 已提交
2934
    esxPrivate *priv = domain->conn->privateData;
2935 2936 2937
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
2938
    int id = -1;
2939 2940
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2941
    char *taskInfoErrorMessage = NULL;
2942

2943 2944
    virCheckFlags(0, -1);

2945
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
2946
        return -1;
2947

2948
    if (esxVI_String_AppendValueToList(&propertyNameList,
2949
                                       "runtime.powerState") < 0 ||
2950
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2951
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2952
           priv->parsedUri->autoAnswer) < 0 ||
2953 2954
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
M
Matthias Bolte 已提交
2955
        goto cleanup;
2956 2957 2958
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2959 2960
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not powered off"));
M
Matthias Bolte 已提交
2961
        goto cleanup;
2962 2963
    }

2964
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
2965
                             &task) < 0 ||
2966
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2967
                                    esxVI_Occurrence_RequiredItem,
2968
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2969
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2970
        goto cleanup;
2971 2972 2973
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2974 2975
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
2976
        goto cleanup;
2977 2978
    }

2979
    domain->id = id;
M
Matthias Bolte 已提交
2980 2981
    result = 0;

2982
 cleanup:
2983 2984 2985
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
2986
    VIR_FREE(taskInfoErrorMessage);
2987 2988 2989 2990

    return result;
}

2991 2992


2993 2994 2995 2996 2997
static int
esxDomainCreate(virDomainPtr domain)
{
    return esxDomainCreateWithFlags(domain, 0);
}
2998

2999 3000


M
Matthias Bolte 已提交
3001
static virDomainPtr
3002
esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
M
Matthias Bolte 已提交
3003
{
M
Matthias Bolte 已提交
3004
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3005 3006
    virDomainDefPtr def = NULL;
    char *vmx = NULL;
3007
    size_t i;
3008
    virDomainDiskDefPtr disk = NULL;
M
Matthias Bolte 已提交
3009
    esxVI_ObjectContent *virtualMachine = NULL;
3010 3011
    int virtualHW_version;
    virVMXContext ctx;
3012
    esxVMX_Data data;
M
Matthias Bolte 已提交
3013 3014
    char *datastoreName = NULL;
    char *directoryName = NULL;
3015
    char *escapedName = NULL;
M
Matthias Bolte 已提交
3016 3017 3018 3019 3020 3021 3022 3023
    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;
3024
    char *taskInfoErrorMessage = NULL;
M
Matthias Bolte 已提交
3025
    virDomainPtr domain = NULL;
3026
    const char *src;
3027
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
M
Matthias Bolte 已提交
3028

3029 3030 3031
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
3032
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
3033

3034
    memset(&data, 0, sizeof(data));
3035

3036
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
3037
        return NULL;
M
Matthias Bolte 已提交
3038 3039

    /* Parse domain XML */
3040
    def = virDomainDefParseString(xml, priv->caps, priv->xmlopt,
3041
                                  NULL, parse_flags);
M
Matthias Bolte 已提交
3042

3043
    if (!def)
M
Matthias Bolte 已提交
3044
        return NULL;
M
Matthias Bolte 已提交
3045

3046 3047 3048
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

M
Matthias Bolte 已提交
3049
    /* Check if an existing domain should be edited */
3050
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3051
                                         &virtualMachine,
M
Matthias Bolte 已提交
3052
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3053
        goto cleanup;
M
Matthias Bolte 已提交
3054 3055
    }

3056
    if (!virtualMachine &&
3057 3058 3059 3060 3061 3062
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

3063
    if (virtualMachine) {
M
Matthias Bolte 已提交
3064
        /* FIXME */
3065 3066 3067
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain already exists, editing existing domains is not "
                         "supported yet"));
M
Matthias Bolte 已提交
3068
        goto cleanup;
M
Matthias Bolte 已提交
3069 3070 3071
    }

    /* Build VMX from domain XML */
3072
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
3073
                          (priv->primary->productLine, priv->primary->productVersion);
3074

3075
    if (virtualHW_version < 0)
3076 3077
        goto cleanup;

3078
    data.ctx = priv->primary;
3079
    data.datastorePathWithoutFileName = NULL;
3080 3081 3082 3083 3084

    ctx.opaque = &data;
    ctx.parseFileName = NULL;
    ctx.formatFileName = esxFormatVMXFileName;
    ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
3085
    ctx.datacenterPath = NULL;
3086
    ctx.moref = NULL;
3087

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

3090
    if (!vmx)
M
Matthias Bolte 已提交
3091
        goto cleanup;
M
Matthias Bolte 已提交
3092

3093 3094 3095
    /*
     * 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
N
Nehal J Wani 已提交
3096
     * first disk, because it may be CDROM disk and ISO images are normally not
3097 3098 3099
     * 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 已提交
3100
    if (def->ndisks < 1) {
3101 3102 3103
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any disks, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3104
        goto cleanup;
3105 3106 3107 3108
    }

    for (i = 0; i < def->ndisks; ++i) {
        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
E
Eric Blake 已提交
3109
            virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_FILE) {
3110 3111 3112 3113 3114
            disk = def->disks[i];
            break;
        }
    }

3115
    if (!disk) {
3116 3117 3118
        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 已提交
3119
        goto cleanup;
M
Matthias Bolte 已提交
3120 3121
    }

3122 3123
    src = virDomainDiskGetSource(disk);
    if (!src) {
3124 3125 3126
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("First file-based harddisk has no source, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3127
        goto cleanup;
M
Matthias Bolte 已提交
3128 3129
    }

3130
    if (esxUtil_ParseDatastorePath(src, &datastoreName, &directoryName,
3131
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3132
        goto cleanup;
M
Matthias Bolte 已提交
3133 3134
    }

3135
    if (! virFileHasSuffix(src, ".vmdk")) {
3136 3137
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting source '%s' of first file-based harddisk to "
3138
                         "be a VMDK image"), src);
M
Matthias Bolte 已提交
3139
        goto cleanup;
M
Matthias Bolte 已提交
3140 3141
    }

3142
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3143 3144
                      conn->uri->server, conn->uri->port);

3145
    if (directoryName) {
M
Matthias Bolte 已提交
3146 3147 3148 3149
        virBufferURIEncodeString(&buffer, directoryName);
        virBufferAddChar(&buffer, '/');
    }

3150 3151
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

3152
    if (!escapedName)
3153 3154 3155
        goto cleanup;

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3156
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3157
    virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
M
Matthias Bolte 已提交
3158 3159 3160
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

3161
    if (virBufferCheckError(&buffer) < 0)
M
Matthias Bolte 已提交
3162
        goto cleanup;
M
Matthias Bolte 已提交
3163 3164 3165

    url = virBufferContentAndReset(&buffer);

3166 3167 3168 3169 3170 3171
    /* Check, if VMX file already exists */
    /* FIXME */

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

3172
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0)
3173 3174 3175
        goto cleanup;

    /* Register the domain */
3176
    if (directoryName) {
M
Matthias Bolte 已提交
3177
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s/%s.vmx", datastoreName,
3178
                        directoryName, escapedName) < 0)
M
Matthias Bolte 已提交
3179
            goto cleanup;
M
Matthias Bolte 已提交
3180 3181
    } else {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s.vmx", datastoreName,
3182
                        escapedName) < 0)
M
Matthias Bolte 已提交
3183
            goto cleanup;
M
Matthias Bolte 已提交
3184 3185
    }

3186
    if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
M
Matthias Bolte 已提交
3187
                              datastoreRelatedPath, NULL, esxVI_Boolean_False,
3188 3189 3190 3191
                              priv->primary->computeResource->resourcePool,
                              priv->primary->hostSystem->_reference,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3192
                                    esxVI_Occurrence_OptionalItem,
3193
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3194
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3195
        goto cleanup;
M
Matthias Bolte 已提交
3196 3197 3198
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3199 3200
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3201
        goto cleanup;
M
Matthias Bolte 已提交
3202 3203
    }

3204
    domain = virGetDomain(conn, def->name, def->uuid, -1);
M
Matthias Bolte 已提交
3205 3206 3207

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

3208
 cleanup:
3209
    if (!url)
M
Matthias Bolte 已提交
3210 3211
        virBufferFreeAndReset(&buffer);

M
Matthias Bolte 已提交
3212 3213 3214 3215
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3216
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3217 3218 3219 3220 3221 3222 3223
    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);
3224
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3225 3226 3227 3228

    return domain;
}

3229 3230 3231 3232 3233
static virDomainPtr
esxDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return esxDomainDefineXMLFlags(conn, xml, 0);
}
M
Matthias Bolte 已提交
3234

3235
static int
3236 3237
esxDomainUndefineFlags(virDomainPtr domain,
                       unsigned int flags)
3238
{
M
Matthias Bolte 已提交
3239
    int result = -1;
M
Matthias Bolte 已提交
3240
    esxPrivate *priv = domain->conn->privateData;
3241
    esxVI_Context *ctx = NULL;
3242 3243 3244 3245
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3246 3247 3248 3249
    /* 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);
3250

3251
    if (priv->vCenter) {
3252 3253 3254 3255 3256
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3257
    if (esxVI_EnsureSession(ctx) < 0)
M
Matthias Bolte 已提交
3258
        return -1;
3259

3260
    if (esxVI_String_AppendValueToList(&propertyNameList,
3261
                                       "runtime.powerState") < 0 ||
3262 3263
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3264
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3265
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3266
        goto cleanup;
3267 3268 3269 3270
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3271 3272
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3273
        goto cleanup;
3274 3275
    }

3276
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0)
M
Matthias Bolte 已提交
3277
        goto cleanup;
3278

M
Matthias Bolte 已提交
3279 3280
    result = 0;

3281
 cleanup:
3282 3283 3284 3285 3286 3287 3288
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


3289 3290 3291 3292 3293
static int
esxDomainUndefine(virDomainPtr domain)
{
    return esxDomainUndefineFlags(domain, 0);
}
3294

3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307
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;

3308
    if (esxVI_EnsureSession(priv->primary) < 0)
3309 3310 3311
        return -1;

    /* Check general autostart config */
3312
    if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0)
3313 3314 3315 3316 3317 3318 3319 3320 3321
        goto cleanup;

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

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

3325
    if (!powerInfoList) {
3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
        /* 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;
    }

3337
    for (powerInfo = powerInfoList; powerInfo;
3338 3339
         powerInfo = powerInfo->_next) {
        if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
3340
            if (STRCASEEQ(powerInfo->startAction, "powerOn"))
3341 3342 3343 3344 3345 3346 3347 3348
                *autostart = 1;

            break;
        }
    }

    result = 0;

3349
 cleanup:
3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371
    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;

3372
    if (esxVI_EnsureSession(priv->primary) < 0)
3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388
        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.
         */
3389
        if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0)
3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403
            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;
            }

3404
            for (powerInfo = powerInfoList; powerInfo;
3405 3406
                 powerInfo = powerInfo->_next) {
                if (STRNEQ(powerInfo->key->value, virtualMachine->obj->value)) {
3407 3408 3409
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("Cannot enable general autostart option "
                                     "without affecting other domains"));
3410 3411 3412 3413 3414
                    goto cleanup;
                }
            }

            /* Enable autostart in general */
3415
            if (esxVI_AutoStartDefaults_Alloc(&spec->defaults) < 0)
3416 3417 3418 3419 3420 3421 3422 3423 3424
                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 ||
3425
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0) {
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436
        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";

3437 3438 3439 3440 3441
    if (esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
                                              newPowerInfo) < 0) {
        goto cleanup;
    }

3442
    newPowerInfo = NULL;
3443

3444 3445 3446 3447 3448 3449 3450 3451 3452
    if (esxVI_ReconfigureAutostart
          (priv->primary,
           priv->primary->hostSystem->configManager->autoStartManager,
           spec) < 0) {
        goto cleanup;
    }

    result = 0;

3453
 cleanup:
3454
    if (newPowerInfo) {
3455 3456 3457 3458 3459 3460 3461 3462 3463 3464
        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);

3465
    esxVI_AutoStartPowerInfo_Free(&newPowerInfo);
3466

3467 3468 3469 3470 3471
    return result;
}



3472 3473 3474 3475 3476 3477 3478 3479 3480 3481
/*
 * 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:
 *
3482
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3483
 *
3484
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3485 3486
 *
 *
3487
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3488
 *
3489 3490
 *   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
3491 3492 3493 3494
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3495
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3496 3497 3498 3499 3500 3501
 *
 *   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'.
 */
3502
static char *
3503
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3504
{
3505
    char *type;
3506

3507
    if (VIR_STRDUP(type, "allocation") < 0)
3508
        return NULL;
3509

3510
    if (nparams)
3511
        *nparams = 3; /* reservation, limit, shares */
3512 3513 3514 3515 3516 3517 3518

    return type;
}



static int
3519 3520 3521
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int *nparams,
                                     unsigned int flags)
3522
{
M
Matthias Bolte 已提交
3523
    int result = -1;
M
Matthias Bolte 已提交
3524
    esxPrivate *priv = domain->conn->privateData;
3525 3526 3527 3528 3529
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    unsigned int mask = 0;
3530
    size_t i = 0;
3531

3532 3533
    virCheckFlags(0, -1);

3534
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
3535
        return -1;
3536

3537
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3538 3539 3540
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3541
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3542
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3543
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3544
        goto cleanup;
3545 3546 3547
    }

    for (dynamicProperty = virtualMachine->propSet;
3548
         dynamicProperty && mask != 7 && i < 3 && i < *nparams;
3549 3550
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
M
Matthias Bolte 已提交
3551
            ! (mask & (1 << 0))) {
3552
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3553
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3554
                goto cleanup;
3555
            }
3556 3557 3558 3559 3560
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_RESERVATION,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3561 3562 3563 3564
            mask |= 1 << 0;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.limit") &&
M
Matthias Bolte 已提交
3565
                   ! (mask & (1 << 1))) {
3566
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3567
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3568
                goto cleanup;
3569
            }
3570 3571 3572 3573 3574
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_LIMIT,
                                        VIR_TYPED_PARAM_LLONG,
                                        dynamicProperty->val->int64) < 0)
                goto cleanup;
3575 3576 3577 3578
            mask |= 1 << 1;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.shares") &&
M
Matthias Bolte 已提交
3579
                   ! (mask & (1 << 2))) {
3580 3581 3582 3583
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_SCHEDULER_SHARES,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
                goto cleanup;
3584
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3585
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3586
                goto cleanup;
3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606
            }

            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:
3607 3608 3609
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Shares level has unknown value %d"),
                               (int)sharesInfo->level);
3610
                esxVI_SharesInfo_Free(&sharesInfo);
M
Matthias Bolte 已提交
3611
                goto cleanup;
3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623
            }

            esxVI_SharesInfo_Free(&sharesInfo);

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

    *nparams = i;
M
Matthias Bolte 已提交
3624
    result = 0;
3625

3626
 cleanup:
3627 3628 3629 3630 3631 3632
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
}

3633 3634 3635 3636 3637 3638
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3639 3640 3641


static int
3642 3643 3644
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3645
{
M
Matthias Bolte 已提交
3646
    int result = -1;
M
Matthias Bolte 已提交
3647
    esxPrivate *priv = domain->conn->privateData;
3648 3649 3650 3651 3652
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3653
    char *taskInfoErrorMessage = NULL;
3654
    size_t i;
3655

3656
    virCheckFlags(0, -1);
3657 3658 3659 3660 3661 3662 3663 3664
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_RESERVATION,
                               VIR_TYPED_PARAM_LLONG,
                               VIR_DOMAIN_SCHEDULER_LIMIT,
                               VIR_TYPED_PARAM_LLONG,
                               VIR_DOMAIN_SCHEDULER_SHARES,
                               VIR_TYPED_PARAM_INT,
                               NULL) < 0)
3665
        return -1;
3666

3667
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
3668
        return -1;
3669

3670
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3671
          (priv->primary, domain->uuid, NULL, &virtualMachine,
3672
           priv->parsedUri->autoAnswer) < 0 ||
3673 3674
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
M
Matthias Bolte 已提交
3675
        goto cleanup;
3676 3677 3678
    }

    for (i = 0; i < nparams; ++i) {
3679
        if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_RESERVATION)) {
3680
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0)
M
Matthias Bolte 已提交
3681
                goto cleanup;
3682 3683

            if (params[i].value.l < 0) {
3684 3685 3686
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Could not set reservation to %lld MHz, expecting "
                                 "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3687
                goto cleanup;
3688 3689 3690
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
3691
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_LIMIT)) {
3692
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0)
M
Matthias Bolte 已提交
3693
                goto cleanup;
3694 3695

            if (params[i].value.l < -1) {
3696 3697 3698 3699
                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 已提交
3700
                goto cleanup;
3701 3702 3703
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
3704
        } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_SHARES)) {
3705 3706
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3707
                goto cleanup;
3708 3709 3710
            }

            spec->cpuAllocation->shares = sharesInfo;
3711
            sharesInfo = NULL;
3712

3713
            if (params[i].value.i >= 0) {
3714
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3715
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3716
            } else {
3717
                switch (params[i].value.i) {
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735
                  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:
3736 3737 3738 3739
                    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 已提交
3740
                    goto cleanup;
3741 3742 3743 3744 3745
                }
            }
        }
    }

3746
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3747
                              &task) < 0 ||
3748
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3749
                                    esxVI_Occurrence_RequiredItem,
3750
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3751
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3752
        goto cleanup;
3753 3754 3755
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3756 3757 3758
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change scheduler parameters: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3759
        goto cleanup;
3760 3761
    }

M
Matthias Bolte 已提交
3762 3763
    result = 0;

3764
 cleanup:
3765
    esxVI_SharesInfo_Free(&sharesInfo);
3766 3767 3768
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3769
    VIR_FREE(taskInfoErrorMessage);
3770 3771 3772 3773

    return result;
}

3774 3775 3776 3777 3778 3779
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3780

E
Eric Blake 已提交
3781 3782 3783 3784 3785 3786
/* 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)
3787 3788 3789 3790 3791

static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3792 3793
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
E
Eric Blake 已提交
3794
                        unsigned long flags,
3795 3796 3797
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3798
    esxPrivate *priv = dconn->privateData;
3799

E
Eric Blake 已提交
3800 3801
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3802
    if (!uri_in) {
3803 3804 3805
        if (virAsprintf(uri_out, "vpxmigr://%s/%s/%s",
                        priv->vCenter->ipAddress,
                        priv->vCenter->computeResource->resourcePool->value,
3806
                        priv->vCenter->hostSystem->_reference->value) < 0)
3807
            return -1;
3808 3809
    }

3810
    return 0;
3811 3812 3813 3814 3815 3816 3817 3818 3819
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
E
Eric Blake 已提交
3820
                        unsigned long flags,
3821 3822 3823
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3824
    int result = -1;
M
Matthias Bolte 已提交
3825
    esxPrivate *priv = domain->conn->privateData;
M
Martin Kletzander 已提交
3826
    virURIPtr parsedUri = NULL;
3827 3828 3829
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3830
    esxVI_ObjectContent *virtualMachine = NULL;
3831 3832
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3833 3834 3835
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3836
    char *taskInfoErrorMessage = NULL;
3837

E
Eric Blake 已提交
3838 3839
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3840
    if (!priv->vCenter) {
3841 3842
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration not possible without a vCenter"));
M
Matthias Bolte 已提交
3843
        return -1;
3844 3845
    }

3846
    if (dname) {
3847 3848
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Renaming domains on migration not supported"));
M
Matthias Bolte 已提交
3849
        return -1;
3850 3851
    }

3852
    if (esxVI_EnsureSession(priv->vCenter) < 0)
M
Matthias Bolte 已提交
3853
        return -1;
3854

3855
    /* Parse migration URI */
3856
    if (!(parsedUri = virURIParse(uri)))
M
Matthias Bolte 已提交
3857
        return -1;
3858

3859
    if (!parsedUri->scheme || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
3860 3861
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3862
        goto cleanup;
3863 3864
    }

3865
    if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
3866 3867 3868
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration source and destination have to refer to "
                         "the same vCenter"));
3869 3870 3871 3872 3873 3874
        goto cleanup;
    }

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

3875
    if (!path_resourcePool || !path_hostSystem) {
3876 3877
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Migration URI has to specify resource pool and host system"));
M
Matthias Bolte 已提交
3878
        goto cleanup;
3879 3880
    }

3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893
    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,
3894
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
3895
        goto cleanup;
3896 3897 3898
    }

    /* Validate the purposed migration */
3899
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3900 3901
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
3902
        goto cleanup;
3903 3904
    }

3905
    if (eventList) {
3906 3907 3908 3909
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
3910
        if (eventList->fullFormattedMessage) {
3911 3912 3913
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not migrate domain, validation reported a "
                             "problem: %s"), eventList->fullFormattedMessage);
3914
        } else {
3915 3916 3917
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not migrate domain, validation reported a "
                             "problem"));
3918 3919
        }

M
Matthias Bolte 已提交
3920
        goto cleanup;
3921 3922 3923
    }

    /* Perform the purposed migration */
3924 3925
    if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
                             &resourcePool, &hostSystem,
3926 3927 3928
                             esxVI_VirtualMachineMovePriority_DefaultPriority,
                             esxVI_VirtualMachinePowerState_Undefined,
                             &task) < 0 ||
3929
        esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
3930
                                    esxVI_Occurrence_RequiredItem,
3931
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3932
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3933
        goto cleanup;
3934 3935 3936
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3937 3938 3939 3940
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not migrate domain, migration task finished with "
                         "an error: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
3941
        goto cleanup;
3942 3943
    }

M
Matthias Bolte 已提交
3944 3945
    result = 0;

3946
 cleanup:
3947
    virURIFree(parsedUri);
3948 3949 3950
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
3951
    VIR_FREE(taskInfoErrorMessage);
3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962

    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 已提交
3963
                       unsigned long flags)
3964
{
E
Eric Blake 已提交
3965 3966
    virCheckFlags(ESX_MIGRATION_FLAGS, NULL);

3967 3968 3969 3970 3971
    return esxDomainLookupByName(dconn, dname);
}



M
Matthias Bolte 已提交
3972 3973 3974 3975
static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)
{
    unsigned long long result = 0;
3976
    unsigned long long usageBytes = 0;
M
Matthias Bolte 已提交
3977
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3978
    esxVI_String *propertyNameList = NULL;
3979 3980 3981
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_Int *memoryUsage = NULL;
    esxVI_Long *memorySize = NULL;
M
Matthias Bolte 已提交
3982

3983
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
3984
        return 0;
M
Matthias Bolte 已提交
3985

3986 3987 3988 3989 3990 3991 3992 3993 3994 3995
    /* Get memory usage of host system */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "summary.quickStats.overallMemoryUsage\0"
                                           "hardware.memorySize\0") < 0 ||
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0 ||
        esxVI_GetInt(hostSystem, "summary.quickStats.overallMemoryUsage",
                      &memoryUsage, esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetLong(hostSystem, "hardware.memorySize", &memorySize,
                      esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3996
        goto cleanup;
M
Matthias Bolte 已提交
3997 3998
    }

3999 4000
    usageBytes = (unsigned long long) (memoryUsage->value) * 1048576;
    result = memorySize->value - usageBytes;
M
Matthias Bolte 已提交
4001

4002
 cleanup:
M
Matthias Bolte 已提交
4003
    esxVI_String_Free(&propertyNameList);
4004 4005 4006
    esxVI_ObjectContent_Free(&hostSystem);
    esxVI_Int_Free(&memoryUsage);
    esxVI_Long_Free(&memorySize);
M
Matthias Bolte 已提交
4007 4008 4009 4010 4011 4012

    return result;
}



4013
static int
4014
esxConnectIsEncrypted(virConnectPtr conn)
4015
{
M
Matthias Bolte 已提交
4016
    esxPrivate *priv = conn->privateData;
4017

4018
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4019 4020 4021 4022 4023 4024 4025 4026 4027
        return 1;
    } else {
        return 0;
    }
}



static int
4028
esxConnectIsSecure(virConnectPtr conn)
4029
{
M
Matthias Bolte 已提交
4030
    esxPrivate *priv = conn->privateData;
4031

4032
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4033 4034 4035 4036 4037 4038 4039 4040
        return 1;
    } else {
        return 0;
    }
}



4041
static int
4042
esxConnectIsAlive(virConnectPtr conn)
4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057
{
    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;
}



4058 4059 4060
static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4061
    int result = -1;
M
Matthias Bolte 已提交
4062
    esxPrivate *priv = domain->conn->privateData;
4063 4064 4065 4066
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4067
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4068
        return -1;
4069

4070
    if (esxVI_String_AppendValueToList(&propertyNameList,
4071
                                       "runtime.powerState") < 0 ||
4072
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4073
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4074
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4075
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4076
        goto cleanup;
4077 4078 4079 4080 4081 4082 4083 4084
    }

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

4085
 cleanup:
4086 4087 4088 4089 4090 4091 4092 4093 4094
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
4095
esxDomainIsPersistent(virDomainPtr domain)
4096
{
4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112
    /* 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;

4113
 cleanup:
4114 4115 4116
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4117 4118
}

M
Matthias Bolte 已提交
4119 4120


4121 4122 4123
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139
    /* 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;

4140
 cleanup:
4141 4142 4143
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4144
}
4145

M
Matthias Bolte 已提交
4146 4147


4148 4149
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4150
                           unsigned int flags)
4151 4152 4153 4154 4155 4156 4157 4158
{
    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;
4159
    char *taskInfoErrorMessage = NULL;
4160
    virDomainSnapshotPtr snapshot = NULL;
4161 4162
    bool diskOnly = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) != 0;
    bool quiesce = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) != 0;
4163

4164 4165 4166 4167 4168
    /* ESX supports disk-only and quiesced snapshots; libvirt tracks no
     * snapshot metadata so supporting that flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
4169

4170
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4171
        return NULL;
4172

4173
    def = virDomainSnapshotDefParseString(xmlDesc, priv->caps,
4174
                                          priv->xmlopt, 0);
4175

4176
    if (!def)
M
Matthias Bolte 已提交
4177
        return NULL;
4178

4179
    if (def->ndisks) {
4180 4181
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
4182 4183 4184
        return NULL;
    }

4185
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4186
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4187
           priv->parsedUri->autoAnswer) < 0 ||
4188
        esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4189 4190
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
4191
                                    &snapshotTree, NULL,
4192
                                    esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4193
        goto cleanup;
4194 4195
    }

4196
    if (snapshotTree) {
4197 4198
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Snapshot '%s' already exists"), def->name);
M
Matthias Bolte 已提交
4199
        goto cleanup;
4200 4201
    }

4202
    if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4203
                                  def->name, def->description,
4204 4205 4206
                                  diskOnly ? esxVI_Boolean_False : esxVI_Boolean_True,
                                  quiesce ? esxVI_Boolean_True : esxVI_Boolean_False,
                                  &task) < 0 ||
4207
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4208
                                    esxVI_Occurrence_RequiredItem,
4209
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4210
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4211
        goto cleanup;
4212 4213 4214
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4215 4216
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4217
        goto cleanup;
4218 4219 4220 4221
    }

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

4222
 cleanup:
4223 4224 4225 4226
    virDomainSnapshotDefFree(def);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4227
    VIR_FREE(taskInfoErrorMessage);
4228 4229 4230 4231 4232 4233 4234

    return snapshot;
}



static char *
4235 4236
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4237 4238 4239 4240 4241 4242 4243 4244 4245
{
    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;

4246 4247
    virCheckFlags(0, NULL);

4248
    memset(&def, 0, sizeof(def));
4249

4250
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4251
        return NULL;
4252

4253
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4254 4255 4256 4257
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4258
        goto cleanup;
4259 4260 4261 4262
    }

    def.name = snapshot->name;
    def.description = snapshotTree->description;
4263
    def.parent = snapshotTreeParent ? snapshotTreeParent->name : NULL;
4264 4265 4266

    if (esxVI_DateTime_ConvertToCalendarTime(snapshotTree->createTime,
                                             &def.creationTime) < 0) {
M
Matthias Bolte 已提交
4267
        goto cleanup;
4268 4269 4270 4271 4272 4273 4274
    }

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

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

4275
    xml = virDomainSnapshotDefFormat(uuid_string, &def, priv->caps, priv->xmlopt,
4276 4277
                                     virDomainDefFormatConvertXMLFlags(flags),
                                     0);
4278

4279
 cleanup:
4280 4281 4282 4283 4284 4285 4286 4287
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



static int
4288
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4289
{
M
Matthias Bolte 已提交
4290
    int count;
4291 4292
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4293
    bool recurse;
4294
    bool leaves;
4295

4296
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4297 4298
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4299 4300

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4301
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4302

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

4306 4307 4308 4309
    /* ESX snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)
        return 0;

4310
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4311
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4312
        return -1;
4313 4314
    }

4315 4316
    count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList, recurse,
                                           leaves);
4317 4318 4319

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

M
Matthias Bolte 已提交
4320
    return count;
4321 4322 4323 4324 4325 4326
}



static int
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4327
                           unsigned int flags)
4328
{
M
Matthias Bolte 已提交
4329
    int result;
4330 4331
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4332
    bool recurse;
4333
    bool leaves;
4334 4335

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4336 4337
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4338

4339
    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4340
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4341

4342
    if (!names || nameslen < 0) {
4343
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4344 4345 4346
        return -1;
    }

4347
    if (nameslen == 0 || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA))
4348 4349
        return 0;

4350
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4351
        return -1;
4352

4353
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4354
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4355
        return -1;
4356 4357
    }

4358
    result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen,
4359
                                        recurse, leaves);
4360 4361 4362 4363 4364 4365 4366 4367

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4368 4369 4370 4371 4372 4373 4374 4375
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;
4376
    bool leaves;
4377 4378

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4379 4380
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4381 4382

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4383
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4384

4385
    if (esxVI_EnsureSession(priv->primary) < 0)
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
        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,
4403
                                           recurse, leaves);
4404

4405
 cleanup:
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422
    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;
4423
    bool leaves;
4424 4425

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4426 4427
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4428 4429

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4430
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4431

4432
    if (!names || nameslen < 0) {
4433
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4434 4435 4436
        return -1;
    }

4437
    if (nameslen == 0)
4438 4439
        return 0;

4440
    if (esxVI_EnsureSession(priv->primary) < 0)
4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457
        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,
4458
                                        names, nameslen, recurse, leaves);
4459

4460
 cleanup:
4461 4462 4463 4464 4465 4466 4467
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4468 4469
static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4470
                              unsigned int flags)
4471 4472 4473 4474 4475 4476
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    virDomainSnapshotPtr snapshot = NULL;

4477 4478
    virCheckFlags(0, NULL);

4479
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4480
        return NULL;
4481

4482
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4483 4484
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
4485
                                    NULL,
4486 4487 4488 4489 4490 4491
                                    esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, name);

4492
 cleanup:
4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return snapshot;
}



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

4506
    virCheckFlags(0, -1);
4507

4508
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4509
        return -1;
4510

4511
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4512 4513
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4514
        return -1;
4515 4516
    }

4517
    if (currentSnapshotTree) {
M
Matthias Bolte 已提交
4518 4519
        esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
        return 1;
4520 4521
    }

M
Matthias Bolte 已提交
4522
    return 0;
4523 4524 4525 4526
}



E
Eric Blake 已提交
4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537
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);

4538
    if (esxVI_EnsureSession(priv->primary) < 0)
E
Eric Blake 已提交
4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549
        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) {
4550 4551 4552
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshotTree->name);
E
Eric Blake 已提交
4553 4554 4555 4556 4557
        goto cleanup;
    }

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

4558
 cleanup:
E
Eric Blake 已提交
4559 4560 4561 4562 4563 4564 4565
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



4566 4567 4568 4569 4570
static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
M
Matthias Bolte 已提交
4571
    virDomainSnapshotPtr snapshot = NULL;
4572

4573
    virCheckFlags(0, NULL);
4574

4575
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4576
        return NULL;
4577

4578
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4579 4580
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4581
        return NULL;
4582 4583 4584 4585 4586 4587 4588 4589 4590 4591
    }

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}


4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602
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);

4603
    if (esxVI_EnsureSession(priv->primary) < 0)
4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622
        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);

4623
 cleanup:
4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639
    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);

4640
    if (esxVI_EnsureSession(priv->primary) < 0)
4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653
        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;

4654
 cleanup:
4655 4656 4657 4658
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    return ret;
}

4659 4660 4661 4662

static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4663
    int result = -1;
4664 4665 4666 4667 4668
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4669
    char *taskInfoErrorMessage = NULL;
4670

4671
    virCheckFlags(0, -1);
4672

4673
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4674
        return -1;
4675

4676
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4677 4678
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4679
                                    &snapshotTree, NULL,
4680
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4681
        goto cleanup;
4682 4683
    }

4684
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4685
                                    esxVI_Boolean_Undefined, &task) < 0 ||
4686
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4687
                                    esxVI_Occurrence_RequiredItem,
4688
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4689
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4690
        goto cleanup;
4691 4692 4693
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4694 4695 4696
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not revert to snapshot '%s': %s"), snapshot->name,
                       taskInfoErrorMessage);
M
Matthias Bolte 已提交
4697
        goto cleanup;
4698 4699
    }

M
Matthias Bolte 已提交
4700 4701
    result = 0;

4702
 cleanup:
4703 4704
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4705
    VIR_FREE(taskInfoErrorMessage);
4706 4707 4708 4709 4710 4711 4712 4713 4714

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4715
    int result = -1;
4716 4717 4718 4719 4720 4721
    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;
4722
    char *taskInfoErrorMessage = NULL;
4723

4724 4725
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4726

4727
    if (esxVI_EnsureSession(priv->primary) < 0)
M
Matthias Bolte 已提交
4728
        return -1;
4729

4730
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
4731 4732
        removeChildren = esxVI_Boolean_True;

4733
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4734 4735
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4736
                                    &snapshotTree, NULL,
4737
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4738
        goto cleanup;
4739 4740
    }

4741 4742 4743 4744 4745 4746 4747
    /* 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;
    }

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

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

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

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

    return result;
}



4776
static int
4777
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4778 4779 4780 4781 4782 4783 4784 4785
                             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;
4786
    char *taskInfoErrorMessage = NULL;
4787
    size_t i;
4788 4789

    virCheckFlags(0, -1);
4790 4791 4792 4793
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
4794
        return -1;
4795

4796
    if (esxVI_EnsureSession(priv->primary) < 0)
4797 4798 4799 4800
        return -1;

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4801
           priv->parsedUri->autoAnswer) < 0 ||
4802 4803 4804 4805 4806 4807
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
        goto cleanup;
    }

    for (i = 0; i < nparams; ++i) {
4808
        if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
4809
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0)
4810 4811 4812
                goto cleanup;

            spec->memoryAllocation->reservation->value =
4813
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4814 4815 4816 4817 4818 4819 4820
        }
    }

    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
4821
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4822
                                    &taskInfoErrorMessage) < 0) {
4823 4824 4825 4826
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4827 4828 4829
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not change memory parameters: %s"),
                       taskInfoErrorMessage);
4830 4831 4832 4833 4834
        goto cleanup;
    }

    result = 0;

4835
 cleanup:
4836 4837 4838
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4839
    VIR_FREE(taskInfoErrorMessage);
4840 4841 4842 4843 4844 4845 4846

    return result;
}



static int
4847
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862
                             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;
    }

4863
    if (esxVI_EnsureSession(priv->primary) < 0)
4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875
        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;
    }

4876 4877 4878 4879
    /* Scale from megabytes to kilobytes */
    if (virTypedParameterAssign(params, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                                VIR_TYPED_PARAM_ULLONG,
                                reservation->value * 1024) < 0)
4880 4881 4882 4883 4884
        goto cleanup;

    *nparams = 1;
    result = 0;

4885
 cleanup:
4886 4887 4888 4889 4890 4891 4892
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Long_Free(&reservation);

    return result;
}

4893 4894
#define MATCH(FLAG) (flags & (FLAG))
static int
4895 4896 4897
esxConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
                         unsigned int flags)
4898 4899 4900
{
    int ret = -1;
    esxPrivate *priv = conn->privateData;
4901 4902
    bool needIdentity;
    bool needPowerState;
4903 4904 4905
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    size_t ndoms = 0;
4906
    esxVI_String *propertyNameList = NULL;
4907 4908
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
4909
    esxVI_AutoStartDefaults *autoStartDefaults = NULL;
4910 4911 4912 4913 4914 4915 4916 4917 4918 4919
    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;
4920
    esxVI_DynamicProperty *dynamicProperty = NULL;
4921 4922 4923 4924 4925 4926 4927

    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
     */
4928
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
4929 4930 4931 4932 4933
         !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)
4934
            goto cleanup;
4935 4936 4937 4938 4939

        ret = 0;
        goto cleanup;
    }

4940
    if (esxVI_EnsureSession(priv->primary) < 0)
4941 4942 4943 4944 4945
        return -1;

    /* check system default autostart value */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
        if (esxVI_LookupAutoStartDefaults(priv->primary,
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
                                          &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) ||
4959
                   domains;
4960 4961 4962 4963 4964 4965 4966

    if (needIdentity) {
        /* Request required data for esxVI_GetVirtualMachineIdentity */
        if (esxVI_String_AppendValueListToList(&propertyNameList,
                                               "configStatus\0"
                                               "name\0"
                                               "config.uuid\0") < 0) {
4967
            goto cleanup;
4968 4969 4970 4971 4972
        }
    }

    needPowerState = MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) ||
                     MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) ||
4973
                     domains;
4974

4975 4976 4977
    if (needPowerState) {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "runtime.powerState") < 0) {
4978
            goto cleanup;
4979
        }
4980 4981
    }

4982 4983 4984 4985 4986 4987 4988
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
        if (esxVI_String_AppendValueToList(&propertyNameList,
                                           "snapshot.rootSnapshotList") < 0) {
            goto cleanup;
        }
    }

4989
    if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
4990 4991 4992 4993 4994
                                       &virtualMachineList) < 0)
        goto cleanup;

    if (domains) {
        if (VIR_ALLOC_N(doms, 1) < 0)
4995
            goto cleanup;
4996 4997 4998
        ndoms = 1;
    }

4999
    for (virtualMachine = virtualMachineList; virtualMachine;
5000
         virtualMachine = virtualMachine->_next) {
5001 5002
        if (needIdentity) {
            VIR_FREE(name);
5003

5004 5005 5006 5007 5008
            if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id,
                                                &name, uuid) < 0) {
                goto cleanup;
            }
        }
5009

5010 5011 5012 5013 5014 5015
        if (needPowerState) {
            if (esxVI_GetVirtualMachinePowerState(virtualMachine,
                                                  &powerState) < 0) {
                goto cleanup;
            }
        }
5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026

        /* 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)) {
5027

5028 5029
            esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5030 5031 5032 5033 5034 5035 5036 5037 5038 5039
            for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
                dynamicProperty = dynamicProperty->_next) {
                if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
                    if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
                        (dynamicProperty->val, &rootSnapshotTreeList) < 0) {
                        goto cleanup;
                    }

                    break;
                }
5040 5041 5042
            }

            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
5043
                   rootSnapshotTreeList) ||
5044
                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
5045
                   !rootSnapshotTreeList)))
5046 5047 5048 5049 5050 5051 5052
                continue;
        }

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

5053
            if (autoStartDefaults->enabled == esxVI_Boolean_True) {
5054
                for (powerInfo = powerInfoList; powerInfo;
5055 5056 5057 5058
                     powerInfo = powerInfo->_next) {
                    if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
                        if (STRCASEEQ(powerInfo->startAction, "powerOn"))
                            autostart = true;
5059

5060 5061
                        break;
                    }
5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074
                }
            }

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

5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094
            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;
        }

5095
        if (VIR_RESIZE_N(doms, ndoms, count, 2) < 0)
5096
            goto cleanup;
5097 5098

        /* Only running/suspended virtual machines have an ID != -1 */
5099 5100 5101 5102 5103
        if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
            id = -1;

        if (!(dom = virGetDomain(conn, name, uuid, id)))
            goto cleanup;
5104 5105 5106 5107 5108 5109 5110 5111 5112

        doms[count++] = dom;
    }

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

5113
 cleanup:
5114
    if (doms) {
5115
        for (id = 0; id < count; id++)
5116
            virObjectUnref(doms[id]);
5117 5118

        VIR_FREE(doms);
5119
    }
5120

5121
    VIR_FREE(name);
5122 5123
    esxVI_AutoStartDefaults_Free(&autoStartDefaults);
    esxVI_AutoStartPowerInfo_Free(&powerInfoList);
5124 5125
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
5126 5127
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

5128 5129 5130
    return ret;
}
#undef MATCH
5131

5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167
static int
esxDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ManagedObjectReference *managedObjectReference = NULL;
    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";

    virCheckFlags(0, -1);

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

    virUUIDFormat(domain->uuid, uuid_string);

    if (esxVI_FindByUuid(priv->primary, priv->primary->datacenter->_reference,
                         uuid_string, esxVI_Boolean_True,
                         esxVI_Boolean_Undefined,
                         &managedObjectReference) < 0) {
        return -1;
    }

    if (!managedObjectReference) {
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("Could not find domain with UUID '%s'"),
                       uuid_string);
        goto cleanup;
    }

    result = 0;

 cleanup:
    esxVI_ManagedObjectReference_Free(&managedObjectReference);
    return result;
}

5168

5169
static virHypervisorDriver esxHypervisorDriver = {
5170
    .name = "ESX",
5171 5172 5173 5174 5175 5176
    .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 */
5177
    .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
5178 5179 5180 5181
    .connectGetCapabilities = esxConnectGetCapabilities, /* 0.7.1 */
    .connectListDomains = esxConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = esxConnectNumOfDomains, /* 0.7.0 */
    .connectListAllDomains = esxConnectListAllDomains, /* 0.10.2 */
5182 5183 5184 5185 5186 5187
    .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 */
5188
    .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
5189 5190
    .domainReboot = esxDomainReboot, /* 0.7.0 */
    .domainDestroy = esxDomainDestroy, /* 0.7.0 */
5191
    .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
5192 5193 5194 5195 5196 5197 5198 5199
    .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 */
5200
    .domainScreenshot = esxDomainScreenshot, /* 1.2.10 */
5201 5202 5203 5204 5205
    .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 */
5206 5207 5208 5209
    .connectDomainXMLFromNative = esxConnectDomainXMLFromNative, /* 0.7.0 */
    .connectDomainXMLToNative = esxConnectDomainXMLToNative, /* 0.7.2 */
    .connectListDefinedDomains = esxConnectListDefinedDomains, /* 0.7.0 */
    .connectNumOfDefinedDomains = esxConnectNumOfDefinedDomains, /* 0.7.0 */
5210 5211 5212
    .domainCreate = esxDomainCreate, /* 0.7.0 */
    .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
5213
    .domainDefineXMLFlags = esxDomainDefineXMLFlags, /* 1.2.12 */
5214
    .domainUndefine = esxDomainUndefine, /* 0.7.1 */
5215
    .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
5216 5217 5218 5219
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
5220
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
5221
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
5222
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
5223 5224 5225 5226
    .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
    .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
    .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
    .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
5227 5228
    .connectIsEncrypted = esxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = esxConnectIsSecure, /* 0.7.3 */
5229 5230 5231 5232 5233 5234 5235
    .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 */
5236 5237
    .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
5238 5239
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
E
Eric Blake 已提交
5240
    .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
5241 5242
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
5243 5244
    .domainSnapshotIsCurrent = esxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = esxDomainSnapshotHasMetadata, /* 0.9.13 */
5245
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
5246
    .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */
5247
    .domainHasManagedSaveImage = esxDomainHasManagedSaveImage, /* 1.2.13 */
5248 5249 5250
};


5251 5252 5253 5254 5255 5256
static virConnectDriver esxConnectDriver = {
    .hypervisorDriver = &esxHypervisorDriver,
    .interfaceDriver = &esxInterfaceDriver,
    .networkDriver = &esxNetworkDriver,
    .storageDriver = &esxStorageDriver,
};
5257 5258 5259 5260

int
esxRegister(void)
{
5261 5262
    return virRegisterConnectDriver(&esxConnectDriver,
                                    false);
5263
}