esx_driver.c 169.7 KB
Newer Older
1 2

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

#include <config.h>

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

#define VIR_FROM_THIS VIR_FROM_ESX

static int esxDomainGetMaxVcpus(virDomainPtr domain);

54 55 56 57
typedef struct _esxVMX_Data esxVMX_Data;

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



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

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



80
/*
81 82
 * Parse a file name from a .vmx file and convert it to datastore path format
 * if possbile. A .vmx file can contain file names in various formats:
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
 *
 * - 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
 *
104 105 106 107 108 109 110 111
 * - 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.
 *
112 113 114 115 116 117 118
 * 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
119
 * function via the opaque parameter by the caller of virVMXParseConfig.
120 121 122 123 124 125 126 127 128
 *
 * 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.
 */
129
static char *
130
esxParseVMXFileName(const char *fileName, void *opaque)
131
{
132
    char *result = NULL;
133
    esxVMX_Data *data = opaque;
134
    esxVI_String *propertyNameList = NULL;
135
    esxVI_ObjectContent *datastoreList = NULL;
136
    esxVI_ObjectContent *datastore = NULL;
137 138 139 140 141 142 143 144 145 146
    esxVI_DatastoreHostMount *hostMount = NULL;
    char *datastoreName;
    char *tmp;
    char *saveptr;
    char *strippedFileName = NULL;
    char *copyOfFileName = NULL;
    char *directoryAndFileName;

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

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

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

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

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

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

185 186 187
            if (esxVI_String_DeepCopyValue(&strippedFileName, tmp) < 0) {
                goto cleanup;
            }
188

189
            tmp = strippedFileName;
190

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

197 198
                ++tmp;
            }
199

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

206 207
            break;
        }
208

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

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

225
            esxVI_ObjectContent_Free(&datastoreList);
226

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

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

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

247 248 249 250 251 252 253 254 255
        /* If it's an absolute path outside of a datastore just use it as is */
        if (result == NULL && *fileName == '/') {
            /* FIXME: need to deal with Windows paths here too */
            if (esxVI_String_DeepCopyValue(&result, fileName) < 0) {
                goto cleanup;
            }
        }

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

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

269
    return result;
270 271 272 273
}



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

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

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

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

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

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

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

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

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

340 341
                ++tmp;
            }
342
        }
343

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

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

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

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

    success = true;

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

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

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



static int
esxAutodetectSCSIControllerModel(virDomainDiskDefPtr def, int *model,
                                 void *opaque)
{
    int result = -1;
    esxVMX_Data *data = opaque;
390
    esxVI_FileInfo *fileInfo = NULL;
391 392 393 394 395 396 397 398 399 400 401 402 403 404
    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;

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

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

411
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
412 413

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

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

    result = 0;

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

    return result;
}

446 447


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

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

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

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

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

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

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

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

                    break;
                }
            }

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

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

    return priv->supportsLongMode;
}



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

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

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

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

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

    result = 0;

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

    return result;
}


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

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

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

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

594
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
595

596

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

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

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

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

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

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

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

633 634 635
    return caps;

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

    return NULL;
}



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

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

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

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

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

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

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

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

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

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

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

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

    /* Query the host for maintenance mode and vCenter IP address */
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "runtime.inMaintenanceMode\0"
                                           "summary.managementServerIp\0") < 0 ||
734 735
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
736 737 738 739 740 741 742 743 744 745 746
        esxVI_GetBoolean(hostSystem, "runtime.inMaintenanceMode",
                         &inMaintenanceMode,
                         esxVI_Occurrence_RequiredItem) < 0 ||
        esxVI_GetStringValue(hostSystem, "summary.managementServerIp",
                             vCenterIpAddress,
                             esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

    /* Warn if host is in maintenance mode */
    if (inMaintenanceMode == esxVI_Boolean_True) {
747
        VIR_WARN("The server is in maintenance mode");
748 749
    }

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

    result = 0;

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

    return result;
}



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

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

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

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

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

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

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

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

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

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

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

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

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

856 857 858 859
    result = 0;

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

    return result;
}



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

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

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

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
    /* Decline if the scheme is not one of {vpx|esx|gsx} */
    plus = strchr(conn->uri->scheme, '+');

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

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

954 955 956 957 958 959
    if (STRCASENEQ(conn->uri->scheme, "vpx") &&
        conn->uri->path != NULL && STRNEQ(conn->uri->path, "/")) {
        VIR_WARN("Ignoring unexpected path '%s' for non-vpx scheme '%s'",
                 conn->uri->path, conn->uri->scheme);
    }

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

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

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

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

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

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

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

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

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

1042 1043
                if (potentialVCenterIpAddress != NULL &&
                    STRNEQ(vCenterIpAddress, potentialVCenterIpAddress)) {
1044 1045 1046 1047 1048 1049
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("This host is managed by a vCenter with IP "
                                     "address %s, but a mismachting vCenter '%s' "
                                     "(%s) has been specified"),
                                   potentialVCenterIpAddress, priv->parsedUri->vCenter,
                                   vCenterIpAddress);
M
Matthias Bolte 已提交
1050
                    goto cleanup;
1051 1052
                }
            }
1053

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

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

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

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

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

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

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

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

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



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

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

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

1116
    esxFreePrivate(&priv);
1117 1118 1119

    conn->privateData = NULL;

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



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

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

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

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

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

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



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

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

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

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

      default:
        return 0;
    }
}



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



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

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

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

    return 0;
}



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

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

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

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

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

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

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

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

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

    return complete;
}



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

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

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

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

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

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

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

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

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

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

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

            ptr = dynamicProperty->val->string;

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

                ++ptr;
            }

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

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

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

    return result;
}



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

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

    return xml;
}



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

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

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

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

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

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

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

        count++;

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

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

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

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



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

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

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



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

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

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

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

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

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

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

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

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

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

        domain->id = id;

        break;
    }

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

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

    return domain;
}



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

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

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

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

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

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

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

    return domain;
}



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

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

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

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

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

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

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

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

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

    return domain;
}



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

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

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

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

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

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

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

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

    return result;
}



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

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

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

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

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

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

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

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

    return result;
}



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

1837 1838
    virCheckFlags(0, -1);

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

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

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

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

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

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

    return result;
}


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

1878 1879

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

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

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

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

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

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

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

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

    return result;
}



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

1938 1939
    virCheckFlags(0, -1);

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

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

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

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

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

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

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

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

    return result;
}


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

1998 1999

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

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



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

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

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

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

            if (dynamicProperty->val->int32 < 0) {
2040 2041 2042
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Got invalid memory size %d"),
                               dynamicProperty->val->int32);
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064
            } else {
                memoryMB = dynamicProperty->val->int32;
            }

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

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

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



static int
esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2065
    int result = -1;
M
Matthias Bolte 已提交
2066
    esxPrivate *priv = domain->conn->privateData;
2067
    esxVI_String *propertyNameList = NULL;
2068
    esxVI_ObjectContent *virtualMachine = NULL;
2069
    esxVI_VirtualMachinePowerState powerState;
2070 2071 2072
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2073
    char *taskInfoErrorMessage = NULL;
2074

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

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

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

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

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

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

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

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

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

    return result;
}



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

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

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

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

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

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

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

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

    return result;
}



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

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

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

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

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

    info->state = VIR_DOMAIN_NOSTATE;

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

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

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

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

            memory_limit = dynamicProperty->val->int64;

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

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

2286
#if ESX_QUERY_FOR_USED_CPU_TIME
2287
    /* Verify the cached 'used CPU time' performance counter ID */
2288 2289 2290 2291 2292 2293
    /* FIXME: Currently no host for a vpx:// connection */
    if (priv->host != NULL) {
        if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
            if (esxVI_Int_Alloc(&counterId) < 0) {
                goto cleanup;
            }
2294

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

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

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

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

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

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

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

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

2335
                counterId = NULL;
2336

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

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

2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
            for (perfCounterInfo = perfCounterInfoList; perfCounterInfo != NULL;
                 perfCounterInfo = perfCounterInfo->_next) {
                VIR_DEBUG("perfCounterInfo key %d, nameInfo '%s', groupInfo '%s', "
                          "unitInfo '%s', rollupType %d, statsType %d",
                          perfCounterInfo->key->value,
                          perfCounterInfo->nameInfo->key,
                          perfCounterInfo->groupInfo->key,
                          perfCounterInfo->unitInfo->key,
                          perfCounterInfo->rollupType,
                          perfCounterInfo->statsType);

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

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

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

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

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

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

2402 2403
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2404

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

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

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

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

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

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

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

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

2446
  cleanup:
2447
#if ESX_QUERY_FOR_USED_CPU_TIME
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
    /*
     * Remove values owned by data structures to prevent them from being freed
     * by the call to esxVI_PerfQuerySpec_Free().
     */
    if (querySpec != NULL) {
        querySpec->entity = NULL;
        querySpec->format = NULL;

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

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

    return result;
}



2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519
static int
esxDomainGetState(virDomainPtr domain,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;

    virCheckFlags(0, -1);

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

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

    *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState);

    if (reason)
        *reason = 0;

    result = 0;

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

    return result;
}



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

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

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

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

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

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

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

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

    spec->numCPUs->value = nvcpus;

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

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

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

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

    return result;
}


M
Matthias Bolte 已提交
2600

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

2607

M
Matthias Bolte 已提交
2608

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

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

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

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

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

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

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

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

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

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

M
Matthias Bolte 已提交
2661 2662


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

M
Matthias Bolte 已提交
2670 2671


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

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

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

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

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

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

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

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

2731 2732
    url = virBufferContentAndReset(&buffer);

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

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

    if (directoryName == NULL) {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s]",
                        datastoreName) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
        if (virAsprintf(&data.datastorePathWithoutFileName, "[%s] %s",
                        datastoreName, directoryName) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }
2752 2753 2754 2755 2756 2757

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

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

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

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

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

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

    return xml;
}



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

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

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

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

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

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

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

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

    virDomainDefFree(def);

    return xml;
}



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

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

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

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

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

    if (virtualHW_version < 0) {
        return NULL;
    }

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

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

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

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

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

    virDomainDefFree(def);

    return vmx;
}



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

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

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

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

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

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2922
        names[count] = NULL;
2923

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

2929 2930
        ++count;

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

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

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

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

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

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



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

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

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



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

2983 2984
    virCheckFlags(0, -1);

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

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

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

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

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

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

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

    return result;
}

3032 3033


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

3040 3041


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

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

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

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

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

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

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

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

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

    if (virtualHW_version < 0) {
        goto cleanup;
    }

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

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

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

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

3127 3128 3129 3130 3131 3132 3133
    /*
     * Build VMX datastore URL. Use the source of the first file-based harddisk
     * to deduce the datastore and path for the VMX file. Don't just use the
     * first disk, because it may be CDROM disk and ISO images are normaly not
     * located in the virtual machine's directory. This approach to deduce the
     * datastore isn't perfect but should work in the majority of cases.
     */
M
Matthias Bolte 已提交
3134
    if (def->ndisks < 1) {
3135 3136 3137
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Domain XML doesn't contain any disks, cannot deduce "
                         "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3138
        goto cleanup;
3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149
    }

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

    if (disk == NULL) {
3150 3151 3152
        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 已提交
3153
        goto cleanup;
M
Matthias Bolte 已提交
3154 3155
    }

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

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

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

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

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

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

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

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

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

    url = virBufferContentAndReset(&buffer);

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

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

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

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

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

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

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

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

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

  cleanup:
M
Matthias Bolte 已提交
3254 3255 3256 3257
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

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

    return domain;
}



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

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

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

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

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

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

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

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

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

    return result;
}


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

3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418
static int
esxDomainGetAutostart(virDomainPtr domain, int *autostart)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_AutoStartDefaults *defaults = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;

    *autostart = 0;

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

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

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

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

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

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

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

            break;
        }
    }

    result = 0;

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

    return result;
}



static int
esxDomainSetAutostart(virDomainPtr domain, int autostart)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_HostAutoStartManagerConfig *spec = NULL;
    esxVI_AutoStartDefaults *defaults = NULL;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_AutoStartPowerInfo *newPowerInfo = NULL;
3419
    bool newPowerInfo_isAppended = false;
3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457

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

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

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

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

            for (powerInfo = powerInfoList; powerInfo != NULL;
                 powerInfo = powerInfo->_next) {
                if (STRNEQ(powerInfo->key->value, virtualMachine->obj->value)) {
3458 3459 3460
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("Cannot enable general autostart option "
                                     "without affecting other domains"));
3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476
                    goto cleanup;
                }
            }

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

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

    if (esxVI_AutoStartPowerInfo_Alloc(&newPowerInfo) < 0 ||
        esxVI_Int_Alloc(&newPowerInfo->startOrder) < 0 ||
        esxVI_Int_Alloc(&newPowerInfo->startDelay) < 0 ||
3477
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0) {
3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488
        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";

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

    newPowerInfo_isAppended = true;

3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516
    if (esxVI_ReconfigureAutostart
          (priv->primary,
           priv->primary->hostSystem->configManager->autoStartManager,
           spec) < 0) {
        goto cleanup;
    }

    result = 0;

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

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

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

3521 3522 3523 3524 3525
    return result;
}



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

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

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

    return type;
}



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

3587 3588
    virCheckFlags(0, -1);

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

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

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

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

            esxVI_SharesInfo_Free(&sharesInfo);

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

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

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

    return result;
}

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


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

3711
    virCheckFlags(0, -1);
3712 3713 3714 3715 3716 3717 3718 3719 3720
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_SCHEDULER_RESERVATION,
                                       VIR_TYPED_PARAM_LLONG,
                                       VIR_DOMAIN_SCHEDULER_LIMIT,
                                       VIR_TYPED_PARAM_LLONG,
                                       VIR_DOMAIN_SCHEDULER_SHARES,
                                       VIR_TYPED_PARAM_INT,
                                       NULL) < 0)
        return -1;
3721

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

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

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

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

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

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

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

            spec->cpuAllocation->shares = sharesInfo;

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

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

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

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

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

    return result;
}

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

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

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

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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

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

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

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

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

    result = resourcePoolResourceUsage->unreservedForVm->value;

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

    return result;
}



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

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



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

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



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



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

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

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

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

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

    return result;
}



static int
4171
esxDomainIsPersistent(virDomainPtr domain)
4172
{
4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192
    /* ESX has no concept of transient domains, so all of them are
     * persistent.  However, we do want to check for existence. */
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;

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

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

    result = 1;

cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4193 4194
}

M
Matthias Bolte 已提交
4195 4196


4197 4198 4199
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219
    /* ESX domains never have a persistent state that differs from
     * current state.  However, we do want to check for existence.  */
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_ObjectContent *virtualMachine = NULL;

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

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

    result = 0;

cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);

    return result;
4220
}
4221

M
Matthias Bolte 已提交
4222 4223


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

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

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

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

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

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

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

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

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

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

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

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

    return snapshot;
}



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

4318 4319
    virCheckFlags(0, NULL);

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

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

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

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

    if (esxVI_DateTime_ConvertToCalendarTime(snapshotTree->createTime,
                                             &def.creationTime) < 0) {
M
Matthias Bolte 已提交
4340
        goto cleanup;
4341 4342 4343 4344 4345 4346 4347
    }

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

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

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

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



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

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

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

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

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

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



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

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

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

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

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

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



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

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

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

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

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

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

    count = esxVI_GetNumberOfSnapshotTrees(snapshotTree->childSnapshotList,
4478
                                           recurse, leaves);
4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return count;
}



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

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

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

    if (names == NULL || nameslen < 0) {
4508
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534
        return -1;
    }

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

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

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

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

    result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
4535
                                        names, nameslen, recurse, leaves);
4536 4537 4538 4539 4540 4541 4542 4543 4544

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



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

4554 4555
    virCheckFlags(0, NULL);

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

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

    snapshot = virGetDomainSnapshot(domain, name);

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return snapshot;
}



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

4584
    virCheckFlags(0, -1);
4585

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

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

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

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



E
Eric Blake 已提交
4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629
static virDomainSnapshotPtr
esxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

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

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

    if (!snapshotTreeParent) {
4630 4631 4632
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshotTree->name);
E
Eric Blake 已提交
4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645
        goto cleanup;
    }

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



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

4653
    virCheckFlags(0, NULL);
4654

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}


4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741
static int
esxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

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

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

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


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

    virCheckFlags(0, -1);

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

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

    ret = 0;

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

4742 4743 4744 4745

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

4754
    virCheckFlags(0, -1);
4755

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

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

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

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

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

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

    return result;
}



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

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

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

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

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

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

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

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

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

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

    return result;
}



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

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

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

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

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

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

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

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

    result = 0;

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

    return result;
}



static int
4935
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964
                             int *nparams, unsigned int flags)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_Long *reservation = NULL;

    virCheckFlags(0, -1);

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

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

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

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

    *nparams = 1;
    result = 0;

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

    return result;
}

4982 4983
#define MATCH(FLAG) (flags & (FLAG))
static int
4984 4985 4986
esxConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
                         unsigned int flags)
4987 4988 4989
{
    int ret = -1;
    esxPrivate *priv = conn->privateData;
4990 4991
    bool needIdentity;
    bool needPowerState;
4992 4993 4994
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    size_t ndoms = 0;
4995
    esxVI_String *propertyNameList = NULL;
4996 4997
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
4998
    esxVI_AutoStartDefaults *autoStartDefaults = NULL;
4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015
    esxVI_VirtualMachinePowerState powerState;
    esxVI_AutoStartPowerInfo *powerInfoList = NULL;
    esxVI_AutoStartPowerInfo *powerInfo = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    char *name = NULL;
    int id;
    unsigned char uuid[VIR_UUID_BUFLEN];
    int count = 0;
    bool autostart;
    int state;

    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);

    /* check for flags that would produce empty output lists:
     * - persistence: all esx machines are persistent
     * - managed save: esx doesn't support managed save
     */
5016
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027
         !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
        if (domains &&
            VIR_ALLOC_N(*domains, 1) < 0)
            goto no_memory;

        ret = 0;
        goto cleanup;
    }

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

    /* check system default autostart value */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
        if (esxVI_LookupAutoStartDefaults(priv->primary,
5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054
                                          &autoStartDefaults) < 0) {
            goto cleanup;
        }

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

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

    if (needIdentity) {
        /* Request required data for esxVI_GetVirtualMachineIdentity */
        if (esxVI_String_AppendValueListToList(&propertyNameList,
                                               "configStatus\0"
                                               "name\0"
                                               "config.uuid\0") < 0) {
5055
            goto cleanup;
5056 5057 5058 5059 5060 5061
        }
    }

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

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

5070
    if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081
                                       &virtualMachineList) < 0)
        goto cleanup;

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

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
5082 5083
        if (needIdentity) {
            VIR_FREE(name);
5084

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

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

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

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

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

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

5126 5127 5128 5129 5130 5131
            if (autoStartDefaults->enabled == esxVI_Boolean_True) {
                for (powerInfo = powerInfoList; powerInfo != NULL;
                     powerInfo = powerInfo->_next) {
                    if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
                        if (STRCASEEQ(powerInfo->startAction, "powerOn"))
                            autostart = true;
5132

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

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

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

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

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

5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190
        /* Only running/suspended virtual machines have an ID != -1 */
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff)
            dom->id = id;
        else
            dom->id = -1;

        doms[count++] = dom;
    }

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

cleanup:
    if (doms) {
        for (id = 0; id < count; id++) {
5191
            virDomainFree(doms[id]);
5192
        }
5193 5194

        VIR_FREE(doms);
5195
    }
5196

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

5204 5205 5206 5207 5208 5209 5210
    return ret;

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


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



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

    return 0;
}