esx_driver.c 149.6 KB
Newer Older
1 2

/*
3
 * esx_driver.c: core driver functions for managing VMware ESX hosts
4
 *
E
Eric Blake 已提交
5
 * Copyright (C) 2010-2011 Red Hat, Inc.
6
 * Copyright (C) 2009-2011 Matthias Bolte <matthias.bolte@googlemail.com>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

#include "internal.h"
#include "domain_conf.h"
29
#include "authhelper.h"
30 31 32 33
#include "util.h"
#include "memory.h"
#include "logging.h"
#include "uuid.h"
34
#include "vmx.h"
35
#include "esx_driver.h"
36 37 38 39 40
#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 已提交
41
#include "esx_nwfilter_driver.h"
42
#include "esx_private.h"
43 44 45 46 47 48 49 50
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"

#define VIR_FROM_THIS VIR_FROM_ESX

static int esxDomainGetMaxVcpus(virDomainPtr domain);

51 52 53 54
typedef struct _esxVMX_Data esxVMX_Data;

struct _esxVMX_Data {
    esxVI_Context *ctx;
55
    char *datastorePathWithoutFileName;
56 57 58 59
};



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

    esxVI_Context_Free(&(*priv)->host);
    esxVI_Context_Free(&(*priv)->vCenter);
    esxUtil_FreeParsedUri(&(*priv)->parsedUri);
    virCapabilitiesFree((*priv)->caps);
    VIR_FREE(*priv);
}



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

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

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

169
            tmp = (char *)STRSKIP(fileName, hostMount->mountInfo->path);
170

171 172 173
            if (tmp == NULL) {
                continue;
            }
174

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

180 181 182
            if (esxVI_String_DeepCopyValue(&strippedFileName, tmp) < 0) {
                goto cleanup;
            }
183

184
            tmp = strippedFileName;
185

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

192 193
                ++tmp;
            }
194

195
            if (virAsprintf(&result, "[%s] %s", datastoreName,
196 197 198 199
                            strippedFileName) < 0) {
                virReportOOMError();
                goto cleanup;
            }
200

201 202
            break;
        }
203

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

210 211 212 213 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) {
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                          _("File name '%s' doesn't have expected format "
                            "'/vmfs/volumes/<datastore>/<path>'"), fileName);
                goto cleanup;
            }
219

220
            esxVI_ObjectContent_Free(&datastoreList);
221

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

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

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

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

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

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

264
    return result;
265 266 267 268
}



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

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

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

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

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

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

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

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

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

334 335
                ++tmp;
            }
336
        }
337

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

341 342 343 344 345 346 347 348 349 350 351 352 353 354
        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 {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not handle file name '%s'"), fileName);
355 356 357 358 359 360 361 362 363
        goto cleanup;
    }

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

    success = true;

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

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

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



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

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

405
    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434

    if (vmDiskFileInfo == NULL || vmDiskFileInfo->controllerType == NULL) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not lookup controller model for '%s'"), def->src);
        goto cleanup;
    }

    if (STRCASEEQ(vmDiskFileInfo->controllerType,
                  "VirtualBusLogicController")) {
        *model = VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC;
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicController")) {
        *model = VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC;
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicSASController")) {
        *model = VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068;
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "ParaVirtualSCSIController")) {
        *model = VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI;
    } else {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Found unexpected controller model '%s' for disk '%s'"),
                  vmDiskFileInfo->controllerType, def->src);
        goto cleanup;
    }

    result = 0;

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

    return result;
}

440 441


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

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

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

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

    if (hostSystem == NULL) {
469 470
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
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
                        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
498 499 500 501
                                  _("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 535 536
static int
esxLookupHostSystemBiosUuid(esxPrivate *priv, unsigned char *uuid)
{
    int result = -1;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

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

    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "hardware.systemInfo.uuid") < 0 ||
543 544
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
        goto cleanup;
    }

    if (hostSystem == NULL) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
        goto cleanup;
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.systemInfo.uuid")) {
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
                                         esxVI_Type_String) < 0) {
                goto cleanup;
            }

            if (strlen(dynamicProperty->val->string) > 0) {
                if (virUUIDParse(dynamicProperty->val->string, uuid) < 0) {
564 565 566 567 568
                    VIR_WARN("Could not parse host UUID from string '%s'",
                             dynamicProperty->val->string);

                    /* HostSystem has an invalid UUID, ignore it */
                    memset(uuid, 0, VIR_UUID_BUFLEN);
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
                }
            } else {
                /* HostSystem has an empty UUID */
                memset(uuid, 0, VIR_UUID_BUFLEN);
            }

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

    result = 0;

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

    return result;
}



592
static virCapsPtr
593
esxCapsInit(esxPrivate *priv)
594
{
595
    esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
596 597 598
    virCapsPtr caps = NULL;
    virCapsGuestPtr guest = NULL;

599 600 601 602 603 604 605 606 607
    if (supportsLongMode == esxVI_Boolean_Undefined) {
        return NULL;
    }

    if (supportsLongMode == esxVI_Boolean_True) {
        caps = virCapabilitiesNew("x86_64", 1, 1);
    } else {
        caps = virCapabilitiesNew("i686", 1, 1);
    }
608 609

    if (caps == NULL) {
610
        virReportOOMError();
611 612 613
        return NULL;
    }

614
    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x0c, 0x29 });
615
    virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
616

617 618
    caps->hasWideScsiBus = true;

619 620 621 622
    if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0) {
        goto failure;
    }

623 624 625
    /* i686 */
    guest = virCapabilitiesAddGuest(caps, "hvm", "i686", 32, NULL, NULL, 0,
                                    NULL);
626 627 628 629 630 631 632 633 634 635

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

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

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
    /* x86_64 */
    if (supportsLongMode == esxVI_Boolean_True) {
        guest = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 64, NULL, NULL,
                                        0, NULL);

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

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

651 652 653 654 655 656 657 658 659 660
    return caps;

  failure:
    virCapabilitiesFree(caps);

    return NULL;
}



661 662 663 664 665 666 667 668 669 670
static int
esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
                 const char *hostname, int port,
                 const char *predefinedUsername,
                 esxVI_ProductVersion expectedProductVersion,
                 char **vCenterIpAddress)
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
671
    char *unescapedPassword = NULL;
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    char *password = NULL;
    char *url = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;

    if (vCenterIpAddress == NULL || *vCenterIpAddress != NULL) {
        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
        return -1;
    }

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

    if (predefinedUsername != NULL) {
        username = strdup(predefinedUsername);

        if (username == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
        username = virRequestUsername(auth, "root", hostname);

        if (username == NULL) {
            ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
            goto cleanup;
        }
    }

M
Matthias Bolte 已提交
703
    unescapedPassword = virRequestPassword(auth, username, hostname);
704

M
Matthias Bolte 已提交
705
    if (unescapedPassword == NULL) {
706 707 708 709
        ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
        goto cleanup;
    }

M
Matthias Bolte 已提交
710 711 712 713 714 715
    password = esxUtil_EscapeForXml(unescapedPassword);

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

716 717
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
                    hostname, port) < 0) {
718 719 720 721 722 723
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->host) < 0 ||
        esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
724 725
                              priv->parsedUri) < 0 ||
        esxVI_Context_LookupObjectsByPath(priv->host, priv->parsedUri) < 0) {
726 727 728 729 730
        goto cleanup;
    }

    if (expectedProductVersion == esxVI_ProductVersion_ESX) {
        if (priv->host->productVersion != esxVI_ProductVersion_ESX35 &&
M
Matthias Bolte 已提交
731 732 733
            priv->host->productVersion != esxVI_ProductVersion_ESX40 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX41 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX4x) {
734
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
M
Matthias Bolte 已提交
735
                      _("%s is neither an ESX 3.5 host nor an ESX 4.x host"),
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
                      hostname);
            goto cleanup;
        }
    } else { /* GSX */
        if (priv->host->productVersion != esxVI_ProductVersion_GSX20) {
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("%s isn't a GSX 2.0 host"), hostname);
            goto cleanup;
        }
    }

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

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

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

    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
780 781
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
782 783 784 785 786 787 788 789 790 791 792 793 794
    VIR_FREE(url);
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



static int
esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
                    const char *hostname, int port,
                    const char *predefinedUsername,
795
                    const char *hostSystemIpAddress)
796 797 798 799
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
800
    char *unescapedPassword = NULL;
801 802 803
    char *password = NULL;
    char *url = NULL;

804
    if (hostSystemIpAddress == NULL &&
805 806
        (priv->parsedUri->path_datacenter == NULL ||
         priv->parsedUri->path_computeResource == NULL)) {
807 808 809 810 811
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Path has to specify the datacenter and compute resource"));
        return -1;
    }

812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
    if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST) < 0) {
        return -1;
    }

    if (predefinedUsername != NULL) {
        username = strdup(predefinedUsername);

        if (username == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    } else {
        username = virRequestUsername(auth, "administrator", hostname);

        if (username == NULL) {
            ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
            goto cleanup;
        }
    }

M
Matthias Bolte 已提交
832
    unescapedPassword = virRequestPassword(auth, username, hostname);
833

M
Matthias Bolte 已提交
834
    if (unescapedPassword == NULL) {
835 836 837 838
        ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
        goto cleanup;
    }

M
Matthias Bolte 已提交
839 840 841 842 843 844
    password = esxUtil_EscapeForXml(unescapedPassword);

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

845 846
    if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
                    hostname, port) < 0) {
847 848 849 850 851 852
        virReportOOMError();
        goto cleanup;
    }

    if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
        esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
853
                              password, priv->parsedUri) < 0) {
854 855 856 857
        goto cleanup;
    }

    if (priv->vCenter->productVersion != esxVI_ProductVersion_VPX25 &&
M
Matthias Bolte 已提交
858 859 860
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX40 &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX41 &&
        priv->vCenter->productVersion != esxVI_ProductVersion_VPX4x) {
861 862
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("%s is neither a vCenter 2.5 server nor a vCenter "
M
Matthias Bolte 已提交
863
                    "4.x server"), hostname);
864 865 866
        goto cleanup;
    }

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

879 880 881 882
    result = 0;

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

    return result;
}



892
/*
893 894
 * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter> ...]
 *             <path> = <datacenter>/<computeresource>[/<hostsystem>]
895
 *
896 897
 * If no port is specified the default port is set dependent on the scheme and
 * transport parameter:
898 899
 * - vpx+http  80
 * - vpx+https 443
900
 * - esx+http  80
901
 * - esx+https 443
902 903 904
 * - gsx+http  8222
 * - gsx+https 8333
 *
905 906 907 908 909
 * 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
 * can be omitted.
 *
910 911
 * Optional query parameters:
 * - transport={http|https}
912
 * - vcenter={<vcenter>|*}             only useful for an esx:// connection
913 914
 * - no_verify={0|1}
 * - auto_answer={0|1}
M
Matthias Bolte 已提交
915
 * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
916
 *
917 918 919
 * If no transport parameter is specified https is used.
 *
 * The vcenter parameter is only necessary for migration, because the vCenter
920
 * server is in charge to initiate a migration between two ESX hosts. The
921
 * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
922 923
 * the driver will check if the ESX host is managed by a vCenter and connect to
 * it. If the ESX host is not managed by a vCenter an error is reported.
924 925
 *
 * If the no_verify parameter is set to 1, this disables libcurl client checks
926
 * of the server's certificate. The default value it 0.
927 928 929 930
 *
 * If the auto_answer parameter is set to 1, the driver will respond to all
 * virtual machine questions with the default answer, otherwise virtual machine
 * questions will be reported as errors. The default value it 0.
M
Matthias Bolte 已提交
931 932 933 934
 *
 * The proxy parameter allows to specify a proxy for to be used by libcurl.
 * The default for the optional <type> part is http and socks is synonymous for
 * socks5. The optional <port> part allows to override the default port 1080.
935 936 937 938
 */
static virDrvOpenStatus
esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
939
    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
940
    esxPrivate *priv = NULL;
941
    char *potentialVCenterIpAddress = NULL;
M
Matthias Bolte 已提交
942
    char vCenterIpAddress[NI_MAXHOST] = "";
943

944
    /* Decline if the URI is NULL or the scheme is not one of {vpx|esx|gsx} */
945
    if (conn->uri == NULL || conn->uri->scheme == NULL ||
946 947
        (STRCASENEQ(conn->uri->scheme, "vpx") &&
         STRCASENEQ(conn->uri->scheme, "esx") &&
948
         STRCASENEQ(conn->uri->scheme, "gsx"))) {
949 950 951
        return VIR_DRV_OPEN_DECLINED;
    }

952 953 954 955 956 957 958 959 960 961 962 963
    /* Require server part */
    if (conn->uri->server == NULL) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("URI is missing the server part"));
        return VIR_DRV_OPEN_ERROR;
    }

    /* Require auth */
    if (auth == NULL || auth->cb == NULL) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Missing or invalid auth pointer"));
        return VIR_DRV_OPEN_ERROR;
964 965 966 967
    }

    /* Allocate per-connection private data */
    if (VIR_ALLOC(priv) < 0) {
968
        virReportOOMError();
M
Matthias Bolte 已提交
969
        goto cleanup;
970 971
    }

972
    if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0) {
973 974 975
        goto cleanup;
    }

M
Matthias Bolte 已提交
976 977
    priv->maxVcpus = -1;
    priv->supportsVMotion = esxVI_Boolean_Undefined;
978
    priv->supportsLongMode = esxVI_Boolean_Undefined;
979 980
    priv->usedCpuTimeCounterId = -1;

M
Matthias Bolte 已提交
981 982 983 984 985 986 987
    /*
     * 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) {
988 989
        if (STRCASEEQ(conn->uri->scheme, "vpx") ||
            STRCASEEQ(conn->uri->scheme, "esx")) {
990
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
991 992 993 994 995
                conn->uri->port = 443;
            } else {
                conn->uri->port = 80;
            }
        } else { /* GSX */
996
            if (STRCASEEQ(priv->parsedUri->transport, "https")) {
M
Matthias Bolte 已提交
997 998 999 1000
                conn->uri->port = 8333;
            } else {
                conn->uri->port = 8222;
            }
1001
        }
M
Matthias Bolte 已提交
1002
    }
1003

1004 1005 1006 1007
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
        if (esxConnectToHost(priv, auth, conn->uri->server, conn->uri->port,
1008
                             conn->uri->user,
1009 1010 1011 1012
                             STRCASEEQ(conn->uri->scheme, "esx")
                               ? esxVI_ProductVersion_ESX
                               : esxVI_ProductVersion_GSX,
                             &potentialVCenterIpAddress) < 0) {
M
Matthias Bolte 已提交
1013
            goto cleanup;
1014
        }
1015

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

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

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

1050
            if (esxConnectToVCenter(priv, auth, vCenterIpAddress,
1051
                                    conn->uri->port, NULL,
1052
                                    priv->host->ipAddress) < 0) {
1053 1054
                goto cleanup;
            }
1055 1056
        }

1057 1058 1059 1060
        priv->primary = priv->host;
    } else { /* VPX */
        /* Connect to vCenter */
        if (esxConnectToVCenter(priv, auth, conn->uri->server, conn->uri->port,
1061
                                conn->uri->user, NULL) < 0) {
M
Matthias Bolte 已提交
1062
            goto cleanup;
1063 1064
        }

1065
        priv->primary = priv->vCenter;
1066 1067
    }

M
Matthias Bolte 已提交
1068
    /* Setup capabilities */
1069
    priv->caps = esxCapsInit(priv);
1070

M
Matthias Bolte 已提交
1071
    if (priv->caps == NULL) {
M
Matthias Bolte 已提交
1072
        goto cleanup;
1073 1074
    }

1075 1076
    conn->privateData = priv;

M
Matthias Bolte 已提交
1077
    result = VIR_DRV_OPEN_SUCCESS;
1078

M
Matthias Bolte 已提交
1079
  cleanup:
1080 1081
    if (result == VIR_DRV_OPEN_ERROR) {
        esxFreePrivate(&priv);
1082 1083
    }

1084
    VIR_FREE(potentialVCenterIpAddress);
1085

M
Matthias Bolte 已提交
1086
    return result;
1087 1088 1089 1090 1091 1092 1093
}



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

1097 1098 1099 1100 1101 1102
    if (priv->host != NULL) {
        if (esxVI_EnsureSession(priv->host) < 0 ||
            esxVI_Logout(priv->host) < 0) {
            result = -1;
        }
    }
1103

M
Matthias Bolte 已提交
1104
    if (priv->vCenter != NULL) {
E
Eric Blake 已提交
1105 1106 1107 1108
        if (esxVI_EnsureSession(priv->vCenter) < 0 ||
            esxVI_Logout(priv->vCenter) < 0) {
            result = -1;
        }
1109 1110
    }

1111
    esxFreePrivate(&priv);
1112 1113 1114

    conn->privateData = NULL;

E
Eric Blake 已提交
1115
    return result;
1116 1117 1118 1119 1120
}



static esxVI_Boolean
1121
esxSupportsVMotion(esxPrivate *priv)
1122 1123 1124 1125
{
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;

M
Matthias Bolte 已提交
1126 1127
    if (priv->supportsVMotion != esxVI_Boolean_Undefined) {
        return priv->supportsVMotion;
1128 1129
    }

1130
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1131
        return esxVI_Boolean_Undefined;
1132 1133
    }

1134
    if (esxVI_String_AppendValueToList(&propertyNameList,
1135
                                       "capability.vmotionSupported") < 0 ||
1136 1137
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1138
        goto cleanup;
1139 1140 1141
    }

    if (hostSystem == NULL) {
1142 1143
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1144
        goto cleanup;
1145 1146
    }

1147 1148 1149 1150
    if (esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1151 1152 1153
    }

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

M
Matthias Bolte 已提交
1161
    return priv->supportsVMotion;
1162 1163 1164 1165 1166 1167 1168
}



static int
esxSupportsFeature(virConnectPtr conn, int feature)
{
M
Matthias Bolte 已提交
1169
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1170
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1171 1172 1173

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1174
        supportsVMotion = esxSupportsVMotion(priv);
1175

M
Matthias Bolte 已提交
1176
        if (supportsVMotion == esxVI_Boolean_Undefined) {
1177 1178 1179
            return -1;
        }

M
Matthias Bolte 已提交
1180 1181 1182
        /* Migration is only possible via a vCenter and if VMotion is enabled */
        return priv->vCenter != NULL &&
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201

      default:
        return 0;
    }
}



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



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

1204
    if (virParseVersionString(priv->primary->service->about->version,
1205 1206
                              version) < 0) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1207
                  _("Could not parse version number from '%s'"),
1208
                  priv->primary->service->about->version);
1209

1210
        return -1;
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
    }

    return 0;
}



static char *
esxGetHostname(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1221
    esxPrivate *priv = conn->privateData;
1222 1223 1224 1225 1226 1227 1228
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1229
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1230
        return NULL;
1231 1232 1233
    }

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

    if (hostSystem == NULL) {
1243 1244
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1245
        goto cleanup;
1246 1247 1248 1249 1250 1251
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1252
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1253
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1254
                goto cleanup;
1255 1256 1257 1258 1259
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1260
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1261
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1262
                goto cleanup;
1263 1264 1265 1266 1267 1268 1269 1270
            }

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

M
Matthias Bolte 已提交
1271
    if (hostName == NULL || strlen(hostName) < 1) {
1272 1273
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1274
        goto cleanup;
1275 1276
    }

M
Matthias Bolte 已提交
1277
    if (domainName == NULL || strlen(domainName) < 1) {
1278
        complete = strdup(hostName);
1279

1280
        if (complete == NULL) {
1281
            virReportOOMError();
M
Matthias Bolte 已提交
1282
            goto cleanup;
1283 1284 1285
        }
    } else {
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0) {
1286
            virReportOOMError();
M
Matthias Bolte 已提交
1287
            goto cleanup;
1288
        }
1289 1290 1291
    }

  cleanup:
M
Matthias Bolte 已提交
1292 1293 1294 1295 1296
    /*
     * If we goto cleanup in case of an error then complete is still NULL,
     * either strdup returned NULL or virAsprintf failed. When virAsprintf
     * fails it guarantees setting complete to NULL
     */
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1308
    int result = -1;
M
Matthias Bolte 已提交
1309
    esxPrivate *priv = conn->privateData;
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
    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;

M
Matthias Bolte 已提交
1321
    memset(nodeinfo, 0, sizeof (*nodeinfo));
1322

1323
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1324
        return -1;
1325 1326
    }

1327
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1328 1329 1330 1331 1332 1333 1334
                                           "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 ||
1335 1336
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1337
        goto cleanup;
1338 1339 1340
    }

    if (hostSystem == NULL) {
1341 1342
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1343
        goto cleanup;
1344 1345 1346 1347 1348
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1349
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1350
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1351
                goto cleanup;
1352 1353 1354 1355 1356
            }

            cpuInfo_hz = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuCores")) {
1357
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1358
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1359
                goto cleanup;
1360 1361 1362 1363 1364
            }

            cpuInfo_numCpuCores = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuPackages")) {
1365
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1366
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1367
                goto cleanup;
1368 1369 1370 1371 1372
            }

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

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1380
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1381
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1382
                goto cleanup;
1383 1384 1385 1386 1387
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1388
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1389
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1390
                goto cleanup;
1391 1392 1393 1394 1395
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1396
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1397
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1398
                goto cleanup;
1399 1400 1401 1402 1403 1404
            }

            ptr = dynamicProperty->val->string;

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

                ++ptr;
            }

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

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1434
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1435 1436 1437 1438 1439 1440 1441 1442 1443
    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 已提交
1444 1445
    result = 0;

1446 1447 1448 1449 1450 1451 1452 1453 1454
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1455 1456 1457
static char *
esxGetCapabilities(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1458
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1459
    char *xml = virCapabilitiesFormatXML(priv->caps);
1460 1461

    if (xml == NULL) {
1462
        virReportOOMError();
1463 1464 1465 1466 1467 1468 1469 1470
        return NULL;
    }

    return xml;
}



1471 1472 1473
static int
esxListDomains(virConnectPtr conn, int *ids, int maxids)
{
M
Matthias Bolte 已提交
1474
    bool success = false;
M
Matthias Bolte 已提交
1475
    esxPrivate *priv = conn->privateData;
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

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

1486
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1487
        return -1;
1488 1489
    }

1490
    if (esxVI_String_AppendValueToList(&propertyNameList,
1491
                                       "runtime.powerState") < 0 ||
1492 1493
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1494
        goto cleanup;
1495 1496 1497 1498
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1499
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1500
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1501
            goto cleanup;
1502 1503 1504 1505 1506 1507 1508 1509 1510
        }

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1511
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1512
                      _("Failed to parse positive integer from '%s'"),
1513
                      virtualMachine->obj->value);
M
Matthias Bolte 已提交
1514
            goto cleanup;
1515 1516 1517 1518 1519 1520 1521 1522 1523
        }

        count++;

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

M
Matthias Bolte 已提交
1524 1525
    success = true;

1526 1527 1528 1529
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1530
    return success ? count : -1;
1531 1532 1533 1534 1535 1536 1537
}



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

1540
    if (esxVI_EnsureSession(priv->primary) < 0) {
1541 1542 1543
        return -1;
    }

1544
    return esxVI_LookupNumberOfDomainsByPowerState
1545
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1546 1547 1548 1549 1550 1551 1552
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1553
    esxPrivate *priv = conn->privateData;
1554 1555 1556 1557
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1558 1559 1560
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1561 1562
    virDomainPtr domain = NULL;

1563
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1564
        return NULL;
1565 1566
    }

1567
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1568
                                           "configStatus\0"
1569 1570
                                           "name\0"
                                           "runtime.powerState\0"
1571
                                           "config.uuid\0") < 0 ||
1572 1573
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1574
        goto cleanup;
1575 1576 1577 1578
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1579
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1580
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1581
            goto cleanup;
1582 1583 1584 1585 1586 1587 1588
        }

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

M
Matthias Bolte 已提交
1589
        VIR_FREE(name_candidate);
1590

1591
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1592 1593
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1594
            goto cleanup;
1595 1596
        }

M
Matthias Bolte 已提交
1597
        if (id != id_candidate) {
1598 1599 1600
            continue;
        }

M
Matthias Bolte 已提交
1601
        domain = virGetDomain(conn, name_candidate, uuid_candidate);
1602 1603

        if (domain == NULL) {
M
Matthias Bolte 已提交
1604
            goto cleanup;
1605 1606 1607 1608 1609 1610 1611 1612
        }

        domain->id = id;

        break;
    }

    if (domain == NULL) {
1613
        ESX_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1614 1615 1616 1617 1618
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1619
    VIR_FREE(name_candidate);
1620 1621 1622 1623 1624 1625 1626 1627 1628

    return domain;
}



static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
M
Matthias Bolte 已提交
1629
    esxPrivate *priv = conn->privateData;
1630 1631 1632
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1633 1634
    int id = -1;
    char *name = NULL;
1635 1636
    virDomainPtr domain = NULL;

1637
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1638
        return NULL;
1639 1640
    }

1641
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1642
                                           "name\0"
1643
                                           "runtime.powerState\0") < 0 ||
1644
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1645
                                         &virtualMachine,
M
Matthias Bolte 已提交
1646
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1647 1648
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1649
        goto cleanup;
1650 1651
    }

1652
    domain = virGetDomain(conn, name, uuid);
1653 1654

    if (domain == NULL) {
M
Matthias Bolte 已提交
1655
        goto cleanup;
1656
    }
1657

1658 1659 1660 1661 1662
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1663 1664 1665 1666
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1667 1668
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1669 1670 1671 1672 1673 1674 1675 1676 1677

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1678
    esxPrivate *priv = conn->privateData;
1679 1680 1681
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1682 1683
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1684 1685
    virDomainPtr domain = NULL;

1686
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1687
        return NULL;
1688 1689
    }

1690
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1691
                                           "configStatus\0"
1692
                                           "runtime.powerState\0"
1693
                                           "config.uuid\0") < 0 ||
1694
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1695 1696
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1697
        goto cleanup;
1698 1699
    }

1700
    if (virtualMachine == NULL) {
1701
        ESX_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1702
        goto cleanup;
1703
    }
1704

M
Matthias Bolte 已提交
1705 1706 1707
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1708
    }
1709

1710
    domain = virGetDomain(conn, name, uuid);
1711

1712
    if (domain == NULL) {
M
Matthias Bolte 已提交
1713
        goto cleanup;
1714 1715
    }

1716 1717 1718 1719 1720
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1721 1722 1723 1724
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1725
    esxVI_ObjectContent_Free(&virtualMachine);
1726 1727 1728 1729 1730 1731 1732 1733 1734

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1735
    int result = -1;
M
Matthias Bolte 已提交
1736
    esxPrivate *priv = domain->conn->privateData;
1737 1738 1739 1740 1741
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1742
    char *taskInfoErrorMessage = NULL;
1743

1744
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1745
        return -1;
1746 1747
    }

1748
    if (esxVI_String_AppendValueToList(&propertyNameList,
1749
                                       "runtime.powerState") < 0 ||
1750
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1751
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1752
           priv->parsedUri->autoAnswer) < 0 ||
1753
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1754
        goto cleanup;
1755 1756 1757
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1758 1759
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1760
        goto cleanup;
1761 1762
    }

1763 1764
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1765
                                    esxVI_Occurrence_RequiredItem,
1766
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1767
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1768
        goto cleanup;
1769 1770 1771
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1772 1773
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
1774
        goto cleanup;
1775 1776
    }

M
Matthias Bolte 已提交
1777 1778
    result = 0;

1779 1780 1781 1782
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1783
    VIR_FREE(taskInfoErrorMessage);
1784 1785 1786 1787 1788 1789 1790 1791 1792

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1793
    int result = -1;
M
Matthias Bolte 已提交
1794
    esxPrivate *priv = domain->conn->privateData;
1795 1796 1797 1798 1799
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1800
    char *taskInfoErrorMessage = NULL;
1801

1802
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1803
        return -1;
1804 1805
    }

1806
    if (esxVI_String_AppendValueToList(&propertyNameList,
1807
                                       "runtime.powerState") < 0 ||
1808
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1809
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1810
           priv->parsedUri->autoAnswer) < 0 ||
1811
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1812
        goto cleanup;
1813 1814 1815
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1816
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1817
        goto cleanup;
1818 1819
    }

1820
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1821
                             &task) < 0 ||
1822
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1823
                                    esxVI_Occurrence_RequiredItem,
1824
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1825
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1826
        goto cleanup;
1827 1828 1829
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1830 1831
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
1832
        goto cleanup;
1833 1834
    }

M
Matthias Bolte 已提交
1835 1836
    result = 0;

1837 1838 1839 1840
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1841
    VIR_FREE(taskInfoErrorMessage);
1842 1843 1844 1845 1846 1847 1848 1849 1850

    return result;
}



static int
esxDomainShutdown(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1851
    int result = -1;
M
Matthias Bolte 已提交
1852
    esxPrivate *priv = domain->conn->privateData;
1853 1854 1855 1856
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1857
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1858
        return -1;
1859 1860
    }

1861
    if (esxVI_String_AppendValueToList(&propertyNameList,
1862
                                       "runtime.powerState") < 0 ||
1863
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1864
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1865
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1866
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1867
        goto cleanup;
1868 1869 1870
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1871 1872
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1873
        goto cleanup;
1874 1875
    }

1876
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1877
        goto cleanup;
1878 1879
    }

M
Matthias Bolte 已提交
1880 1881
    result = 0;

1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
esxDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
1894
    int result = -1;
M
Matthias Bolte 已提交
1895
    esxPrivate *priv = domain->conn->privateData;
1896 1897 1898 1899
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1900
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1901
        return -1;
1902 1903
    }

1904
    if (esxVI_String_AppendValueToList(&propertyNameList,
1905
                                       "runtime.powerState") < 0 ||
1906
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1907
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1908
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1909
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1910
        goto cleanup;
1911 1912 1913
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1914 1915
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1916
        goto cleanup;
1917 1918
    }

1919
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1920
        goto cleanup;
1921 1922
    }

M
Matthias Bolte 已提交
1923 1924
    result = 0;

1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
esxDomainDestroy(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1937
    int result = -1;
M
Matthias Bolte 已提交
1938
    esxPrivate *priv = domain->conn->privateData;
1939
    esxVI_Context *ctx = NULL;
1940 1941 1942 1943 1944
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1945
    char *taskInfoErrorMessage = NULL;
1946

1947 1948 1949 1950 1951 1952
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1953
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
1954
        return -1;
1955 1956
    }

1957
    if (esxVI_String_AppendValueToList(&propertyNameList,
1958
                                       "runtime.powerState") < 0 ||
1959
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1960
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1961
           priv->parsedUri->autoAnswer) < 0 ||
1962
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1963
        goto cleanup;
1964 1965 1966
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1967 1968
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1969
        goto cleanup;
1970 1971
    }

1972
    if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1973 1974
        esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
1975
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1976
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1977
        goto cleanup;
1978 1979 1980
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1981 1982
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
1983
        goto cleanup;
1984 1985
    }

1986
    domain->id = -1;
M
Matthias Bolte 已提交
1987 1988
    result = 0;

1989 1990 1991 1992
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1993
    VIR_FREE(taskInfoErrorMessage);
1994 1995 1996 1997 1998 1999 2000

    return result;
}



static char *
2001
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
2002
{
2003 2004 2005
    char *osType = strdup("hvm");

    if (osType == NULL) {
2006
        virReportOOMError();
2007 2008 2009 2010
        return NULL;
    }

    return osType;
2011 2012 2013 2014 2015 2016 2017
}



static unsigned long
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
2018
    esxPrivate *priv = domain->conn->privateData;
2019 2020 2021 2022 2023
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

2024
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2025
        return 0;
2026 2027
    }

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

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

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

2080
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2081
        return -1;
2082 2083
    }

2084 2085 2086 2087
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2088
           priv->parsedUri->autoAnswer) < 0 ||
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered off"));
        goto cleanup;
    }

    if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
2100
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
2101
        goto cleanup;
2102 2103
    }

2104
    /* max-memory must be a multiple of 4096 kilobyte */
2105
    spec->memoryMB->value =
2106
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2107

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2118
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2119 2120
                  _("Could not set max-memory to %lu kilobytes: %s"), memory,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2121
        goto cleanup;
2122 2123
    }

M
Matthias Bolte 已提交
2124 2125
    result = 0;

2126
  cleanup:
2127
    esxVI_String_Free(&propertyNameList);
2128 2129 2130
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2131
    VIR_FREE(taskInfoErrorMessage);
2132 2133 2134 2135 2136 2137 2138 2139 2140

    return result;
}



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

2149
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2150
        return -1;
2151 2152
    }

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

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

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2175
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2176 2177
                  _("Could not set memory to %lu kilobytes: %s"), memory,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2178
        goto cleanup;
2179 2180
    }

M
Matthias Bolte 已提交
2181 2182
    result = 0;

2183 2184 2185 2186
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2187
    VIR_FREE(taskInfoErrorMessage);
2188 2189 2190 2191 2192 2193

    return result;
}



2194 2195 2196 2197 2198 2199 2200 2201 2202
/*
 * 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

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

M
Matthias Bolte 已提交
2228 2229
    memset(info, 0, sizeof (*info));

2230
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2231
        return -1;
2232 2233
    }

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

    info->state = VIR_DOMAIN_NOSTATE;

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

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

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

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

            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;

2291
#if ESX_QUERY_FOR_USED_CPU_TIME
2292
    /* Verify the cached 'used CPU time' performance counter ID */
2293 2294 2295 2296 2297 2298
    /* 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;
            }
2299

2300
            counterId->value = priv->usedCpuTimeCounterId;
2301

2302 2303 2304
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                goto cleanup;
            }
2305

2306 2307 2308 2309
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2310

2311 2312 2313 2314 2315
            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);
2316

2317 2318 2319 2320 2321
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2322 2323
        }

2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
        /*
         * 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;
            }
2334

2335 2336 2337 2338
            for (perfMetricId = perfMetricIdList; perfMetricId != NULL;
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2339

2340
                counterId = NULL;
2341

2342 2343 2344 2345 2346
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2347

2348 2349
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2350
                goto cleanup;
2351 2352
            }

2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
            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;
                }
2370 2371
            }

2372
            if (priv->usedCpuTimeCounterId < 0) {
2373
                VIR_WARN("Could not find 'used CPU time' performance counter");
2374
            }
2375 2376
        }

2377 2378 2379 2380 2381 2382
        /*
         * 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);
2383

2384 2385 2386 2387 2388 2389
            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;
            }
2390

2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
            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;
            }
2401

2402 2403 2404
            for (perfEntityMetricBase = perfEntityMetricBaseList;
                 perfEntityMetricBase != NULL;
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2405
                VIR_DEBUG("perfEntityMetric ...");
2406

2407 2408
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2409

2410
                if (perfEntityMetric == NULL) {
2411 2412
                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                              _("QueryPerf returned object with unexpected type '%s'"),
2413
                              esxVI_Type_ToString(perfEntityMetricBase->_type));
2414
                    goto cleanup;
2415
                }
2416

2417 2418
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2419

2420
                if (perfMetricIntSeries == NULL) {
2421 2422
                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                              _("QueryPerf returned object with unexpected type '%s'"),
2423
                              esxVI_Type_ToString(perfEntityMetric->value->_type));
2424
                    goto cleanup;
2425
                }
2426

2427 2428
                for (; perfMetricIntSeries != NULL;
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2429
                    VIR_DEBUG("perfMetricIntSeries ...");
2430

2431 2432 2433 2434 2435
                    for (value = perfMetricIntSeries->value;
                         value != NULL;
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2436 2437 2438
                }
            }

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

2441
            /*
E
Eric Blake 已提交
2442
             * FIXME: Cannot map between relative used-cpu-time and absolute
2443 2444 2445
             *        info->cpuTime
             */
        }
2446
    }
2447
#endif
2448

M
Matthias Bolte 已提交
2449 2450
    result = 0;

2451
  cleanup:
2452
#if ESX_QUERY_FOR_USED_CPU_TIME
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
    /*
     * 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;
        }
    }
2465
#endif
2466

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

    return result;
}



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



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

2538 2539 2540 2541 2542
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

2543
    if (nvcpus < 1) {
2544 2545
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2546
        return -1;
2547 2548
    }

2549
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2550
        return -1;
2551 2552
    }

M
Matthias Bolte 已提交
2553
    maxVcpus = esxDomainGetMaxVcpus(domain);
2554

M
Matthias Bolte 已提交
2555
    if (maxVcpus < 0) {
M
Matthias Bolte 已提交
2556
        return -1;
2557 2558
    }

M
Matthias Bolte 已提交
2559
    if (nvcpus > maxVcpus) {
2560
        ESX_ERROR(VIR_ERR_INVALID_ARG,
2561 2562
                  _("Requested number of virtual CPUs is greater than max "
                    "allowable number of virtual CPUs for the domain: %d > %d"),
M
Matthias Bolte 已提交
2563
                  nvcpus, maxVcpus);
M
Matthias Bolte 已提交
2564
        return -1;
2565 2566
    }

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

    spec->numCPUs->value = nvcpus;

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2587
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2588 2589
                  _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2590
        goto cleanup;
2591 2592
    }

M
Matthias Bolte 已提交
2593 2594
    result = 0;

2595 2596 2597 2598
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2599
    VIR_FREE(taskInfoErrorMessage);
2600 2601 2602 2603 2604

    return result;
}


M
Matthias Bolte 已提交
2605

2606 2607 2608 2609 2610 2611
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

2612

M
Matthias Bolte 已提交
2613

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

2622 2623 2624 2625 2626
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

M
Matthias Bolte 已提交
2627 2628
    if (priv->maxVcpus > 0) {
        return priv->maxVcpus;
2629 2630
    }

M
Matthias Bolte 已提交
2631 2632
    priv->maxVcpus = -1;

2633
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2634
        return -1;
2635 2636
    }

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

    if (hostSystem == NULL) {
2645 2646
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
2647
        goto cleanup;
2648 2649 2650 2651 2652
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2653
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2654
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2655
                goto cleanup;
2656 2657
            }

M
Matthias Bolte 已提交
2658
            priv->maxVcpus = dynamicProperty->val->int32;
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

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

M
Matthias Bolte 已提交
2669
    return priv->maxVcpus;
2670 2671
}

M
Matthias Bolte 已提交
2672 2673


2674 2675 2676 2677 2678 2679
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_LIVE |
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2680

M
Matthias Bolte 已提交
2681 2682


2683
static char *
2684
esxDomainGetXMLDesc(virDomainPtr domain, int flags)
2685
{
M
Matthias Bolte 已提交
2686
    esxPrivate *priv = domain->conn->privateData;
2687 2688
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2689 2690
    esxVI_VirtualMachinePowerState powerState;
    int id;
2691
    char *vmPathName = NULL;
2692
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2693
    char *directoryName = NULL;
2694
    char *directoryAndFileName = NULL;
2695
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2696 2697
    char *url = NULL;
    char *vmx = NULL;
2698
    virVMXContext ctx;
2699
    esxVMX_Data data;
2700 2701 2702
    virDomainDefPtr def = NULL;
    char *xml = NULL;

2703
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2704
        return NULL;
2705 2706
    }

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

2720
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2721
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2722
        goto cleanup;
2723 2724
    }

2725
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2726
                      domain->conn->uri->server, domain->conn->uri->port);
2727
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2728
    virBufferAddLit(&buffer, "?dcPath=");
2729
    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
2730 2731 2732 2733
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
2734
        virReportOOMError();
M
Matthias Bolte 已提交
2735
        goto cleanup;
2736 2737
    }

2738 2739
    url = virBufferContentAndReset(&buffer);

2740
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx) < 0) {
M
Matthias Bolte 已提交
2741
        goto cleanup;
2742 2743
    }

2744
    data.ctx = priv->primary;
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758

    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;
        }
    }
2759 2760 2761 2762 2763 2764

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

2765
    def = virVMXParseConfig(&ctx, priv->caps, vmx);
2766 2767

    if (def != NULL) {
2768 2769 2770 2771
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
            def->id = id;
        }

2772
        xml = virDomainDefFormat(def, flags);
2773 2774 2775
    }

  cleanup:
M
Matthias Bolte 已提交
2776 2777 2778 2779
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

2780 2781
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2782
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2783
    VIR_FREE(directoryName);
2784
    VIR_FREE(directoryAndFileName);
2785
    VIR_FREE(url);
2786
    VIR_FREE(data.datastorePathWithoutFileName);
2787
    VIR_FREE(vmx);
2788
    virDomainDefFree(def);
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799

    return xml;
}



static char *
esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                       const char *nativeConfig,
                       unsigned int flags ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
2800
    esxPrivate *priv = conn->privateData;
2801
    virVMXContext ctx;
2802
    esxVMX_Data data;
2803 2804 2805 2806
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2807
        ESX_ERROR(VIR_ERR_INVALID_ARG,
2808
                  _("Unsupported config format '%s'"), nativeFormat);
2809
        return NULL;
2810 2811
    }

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

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

2820
    def = virVMXParseConfig(&ctx, priv->caps, nativeConfig);
2821 2822

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

    virDomainDefFree(def);

    return xml;
}



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

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

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

    if (virtualHW_version < 0) {
        return NULL;
    }

2858
    def = virDomainDefParseString(priv->caps, domainXml, 0);
M
Matthias Bolte 已提交
2859 2860 2861 2862 2863

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

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

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

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

    virDomainDefFree(def);

    return vmx;
}



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

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

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

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

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

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2920
        names[count] = NULL;
2921

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

2927 2928
        ++count;

2929 2930 2931 2932 2933
        if (count >= maxnames) {
            break;
        }
    }

M
Matthias Bolte 已提交
2934
    success = true;
2935

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

M
Matthias Bolte 已提交
2942
        count = -1;
2943 2944
    }

M
Matthias Bolte 已提交
2945 2946
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2947

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



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

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

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



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

2981 2982
    virCheckFlags(0, -1);

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

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

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

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

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

3018
    domain->id = id;
M
Matthias Bolte 已提交
3019 3020
    result = 0;

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

    return result;
}

3030 3031


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

3038 3039


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

3066
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3067
        return NULL;
M
Matthias Bolte 已提交
3068 3069 3070
    }

    /* Parse domain XML */
3071
    def = virDomainDefParseString(priv->caps, xml,
M
Matthias Bolte 已提交
3072 3073 3074
                                  VIR_DOMAIN_XML_INACTIVE);

    if (def == NULL) {
M
Matthias Bolte 已提交
3075
        return NULL;
M
Matthias Bolte 已提交
3076 3077 3078
    }

    /* Check if an existing domain should be edited */
3079
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3080
                                         &virtualMachine,
M
Matthias Bolte 已提交
3081
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3082
        goto cleanup;
M
Matthias Bolte 已提交
3083 3084
    }

3085 3086 3087 3088 3089 3090 3091
    if (virtualMachine == NULL &&
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

M
Matthias Bolte 已提交
3092 3093
    if (virtualMachine != NULL) {
        /* FIXME */
3094 3095 3096
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Domain already exists, editing existing domains is not "
                    "supported yet"));
M
Matthias Bolte 已提交
3097
        goto cleanup;
M
Matthias Bolte 已提交
3098 3099 3100
    }

    /* Build VMX from domain XML */
3101 3102 3103 3104 3105 3106 3107
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        goto cleanup;
    }

3108
    data.ctx = priv->primary;
3109
    data.datastorePathWithoutFileName = NULL;
3110 3111 3112 3113 3114 3115

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

3116
    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
M
Matthias Bolte 已提交
3117 3118

    if (vmx == NULL) {
M
Matthias Bolte 已提交
3119
        goto cleanup;
M
Matthias Bolte 已提交
3120 3121
    }

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

    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) {
3145 3146 3147
        ESX_ERROR(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 已提交
3148
        goto cleanup;
M
Matthias Bolte 已提交
3149 3150
    }

3151
    if (disk->src == NULL) {
3152 3153 3154
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("First file-based harddisk has no source, cannot deduce "
                    "datastore and path for VMX file"));
M
Matthias Bolte 已提交
3155
        goto cleanup;
M
Matthias Bolte 已提交
3156 3157
    }

3158
    if (esxUtil_ParseDatastorePath(disk->src, &datastoreName, &directoryName,
3159
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3160
        goto cleanup;
M
Matthias Bolte 已提交
3161 3162
    }

3163
    if (! virFileHasSuffix(disk->src, ".vmdk")) {
3164
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3165 3166
                  _("Expecting source '%s' of first file-based harddisk to "
                    "be a VMDK image"), disk->src);
M
Matthias Bolte 已提交
3167
        goto cleanup;
M
Matthias Bolte 已提交
3168 3169
    }

3170
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3171 3172 3173 3174 3175 3176 3177
                      conn->uri->server, conn->uri->port);

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

3178 3179 3180 3181 3182 3183 3184
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

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

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3185
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3186
    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
M
Matthias Bolte 已提交
3187 3188 3189 3190
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
3191
        virReportOOMError();
M
Matthias Bolte 已提交
3192
        goto cleanup;
M
Matthias Bolte 已提交
3193 3194 3195 3196
    }

    url = virBufferContentAndReset(&buffer);

3197 3198 3199 3200 3201 3202
    /* Check, if VMX file already exists */
    /* FIXME */

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

3203
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0) {
3204 3205 3206 3207
        goto cleanup;
    }

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

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3235 3236
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3237
        goto cleanup;
M
Matthias Bolte 已提交
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248
    }

    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 已提交
3249 3250 3251 3252
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

M
Matthias Bolte 已提交
3253 3254 3255 3256
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3257
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3258 3259 3260 3261 3262 3263 3264
    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);
3265
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3266 3267 3268 3269 3270 3271

    return domain;
}



3272 3273 3274
static int
esxDomainUndefine(virDomainPtr domain)
{
M
Matthias Bolte 已提交
3275
    int result = -1;
M
Matthias Bolte 已提交
3276
    esxPrivate *priv = domain->conn->privateData;
3277
    esxVI_Context *ctx = NULL;
3278 3279 3280 3281
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3282 3283 3284 3285 3286 3287
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3288
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
3289
        return -1;
3290 3291
    }

3292
    if (esxVI_String_AppendValueToList(&propertyNameList,
3293
                                       "runtime.powerState") < 0 ||
3294 3295
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3296
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3297
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3298
        goto cleanup;
3299 3300 3301 3302
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3303 3304
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3305
        goto cleanup;
3306 3307
    }

3308
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
3309
        goto cleanup;
3310 3311
    }

M
Matthias Bolte 已提交
3312 3313
    result = 0;

3314 3315 3316 3317 3318 3319 3320 3321 3322
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501
static int
esxDomainGetAutostart(virDomainPtr domain, int *autostart)
{
    int result = -1;
    esxPrivate *priv = domain->conn->privateData;
    esxVI_AutoStartDefaults *defaults = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostAutoStartManager = 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_ObjectContent_Free(&hostAutoStartManager);
    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;

    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)) {
                    ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                              _("Cannot enable general autostart option "
                                "without affecting other domains"));
                    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 ||
        esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0 ||
        esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
                                              newPowerInfo) < 0) {
        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";

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

    return result;
}



3502 3503 3504 3505 3506 3507 3508 3509 3510 3511
/*
 * 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:
 *
3512
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3513
 *
3514
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3515 3516
 *
 *
3517
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3518
 *
3519 3520
 *   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
3521 3522 3523 3524
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3525
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3526 3527 3528 3529 3530 3531
 *
 *   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'.
 */
3532
static char *
3533
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3534 3535 3536 3537
{
    char *type = strdup("allocation");

    if (type == NULL) {
3538
        virReportOOMError();
3539
        return NULL;
3540 3541
    }

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

    return type;
}



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

3565 3566
    virCheckFlags(0, -1);

3567
    if (*nparams < 3) {
3568 3569
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Parameter array must have space for 3 items"));
M
Matthias Bolte 已提交
3570
        return -1;
3571 3572
    }

3573
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3574
        return -1;
3575 3576
    }

3577
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3578 3579 3580
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3581
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3582
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3583
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3584
        goto cleanup;
3585 3586 3587 3588 3589 3590
    }

    for (dynamicProperty = virtualMachine->propSet;
         dynamicProperty != NULL && mask != 7 && i < 3;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
M
Matthias Bolte 已提交
3591
            ! (mask & (1 << 0))) {
3592
            snprintf (params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH, "%s",
3593 3594
                      "reservation");

3595
            params[i].type = VIR_TYPED_PARAM_LLONG;
3596

3597
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3598
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3599
                goto cleanup;
3600 3601 3602 3603 3604 3605 3606
            }

            params[i].value.l = dynamicProperty->val->int64;
            mask |= 1 << 0;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.limit") &&
M
Matthias Bolte 已提交
3607
                   ! (mask & (1 << 1))) {
3608
            snprintf (params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH, "%s",
3609 3610
                      "limit");

3611
            params[i].type = VIR_TYPED_PARAM_LLONG;
3612

3613
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3614
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3615
                goto cleanup;
3616 3617 3618 3619 3620 3621 3622
            }

            params[i].value.l = dynamicProperty->val->int64;
            mask |= 1 << 1;
            ++i;
        } else if (STREQ(dynamicProperty->name,
                         "config.cpuAllocation.shares") &&
M
Matthias Bolte 已提交
3623
                   ! (mask & (1 << 2))) {
3624
            snprintf (params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH, "%s",
3625 3626
                      "shares");

3627
            params[i].type = VIR_TYPED_PARAM_INT;
3628

3629
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3630
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3631
                goto cleanup;
3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651
            }

            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:
3652
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3653
                          _("Shares level has unknown value %d"),
3654
                          (int)sharesInfo->level);
M
Matthias Bolte 已提交
3655
                goto cleanup;
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667
            }

            esxVI_SharesInfo_Free(&sharesInfo);

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

    *nparams = i;
M
Matthias Bolte 已提交
3668
    result = 0;
3669 3670 3671 3672 3673 3674 3675 3676

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

    return result;
}

3677 3678 3679 3680 3681 3682
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3683 3684 3685


static int
3686 3687 3688
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3689
{
M
Matthias Bolte 已提交
3690
    int result = -1;
M
Matthias Bolte 已提交
3691
    esxPrivate *priv = domain->conn->privateData;
3692 3693 3694 3695 3696
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3697
    char *taskInfoErrorMessage = NULL;
3698 3699
    int i;

3700 3701
    virCheckFlags(0, -1);

3702
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3703
        return -1;
3704 3705
    }

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

    for (i = 0; i < nparams; ++i) {
        if (STREQ (params[i].field, "reservation") &&
3716
            params[i].type == VIR_TYPED_PARAM_LLONG) {
3717
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0) {
M
Matthias Bolte 已提交
3718
                goto cleanup;
3719 3720 3721
            }

            if (params[i].value.l < 0) {
3722
                ESX_ERROR(VIR_ERR_INVALID_ARG,
3723 3724
                          _("Could not set reservation to %lld MHz, expecting "
                            "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3725
                goto cleanup;
3726 3727 3728 3729
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
        } else if (STREQ (params[i].field, "limit") &&
3730
                   params[i].type == VIR_TYPED_PARAM_LLONG) {
3731
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0) {
M
Matthias Bolte 已提交
3732
                goto cleanup;
3733 3734 3735
            }

            if (params[i].value.l < -1) {
3736
                ESX_ERROR(VIR_ERR_INVALID_ARG,
3737 3738
                          _("Could not set limit to %lld MHz, expecting "
                            "positive value or -1 (unlimited)"),
3739
                          params[i].value.l);
M
Matthias Bolte 已提交
3740
                goto cleanup;
3741 3742 3743 3744
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
        } else if (STREQ (params[i].field, "shares") &&
3745
                   params[i].type == VIR_TYPED_PARAM_INT) {
3746 3747
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3748
                goto cleanup;
3749 3750 3751 3752
            }

            spec->cpuAllocation->shares = sharesInfo;

3753
            if (params[i].value.i >= 0) {
3754
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3755
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3756
            } else {
3757
                switch (params[i].value.i) {
3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775
                  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:
3776
                    ESX_ERROR(VIR_ERR_INVALID_ARG,
3777 3778
                              _("Could not set shares to %d, expecting positive "
                                "value or -1 (low), -2 (normal) or -3 (high)"),
3779
                              params[i].value.i);
M
Matthias Bolte 已提交
3780
                    goto cleanup;
3781 3782 3783
                }
            }
        } else {
3784
            ESX_ERROR(VIR_ERR_INVALID_ARG, _("Unknown field '%s'"),
3785
                      params[i].field);
M
Matthias Bolte 已提交
3786
            goto cleanup;
3787 3788 3789
        }
    }

3790
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3791
                              &task) < 0 ||
3792
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3793
                                    esxVI_Occurrence_RequiredItem,
3794
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3795
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3796
        goto cleanup;
3797 3798 3799
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3800 3801 3802
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not change scheduler parameters: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3803
        goto cleanup;
3804 3805
    }

M
Matthias Bolte 已提交
3806 3807
    result = 0;

3808 3809 3810 3811
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3812
    VIR_FREE(taskInfoErrorMessage);
3813 3814 3815 3816

    return result;
}

3817 3818 3819 3820 3821 3822
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3823 3824 3825 3826 3827 3828


static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3829 3830
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
3831 3832 3833 3834
                        unsigned long flags ATTRIBUTE_UNUSED,
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3835
    esxPrivate *priv = dconn->privateData;
3836 3837

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

3847
    return 0;
3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
                        unsigned long flags ATTRIBUTE_UNUSED,
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3861
    int result = -1;
M
Matthias Bolte 已提交
3862
    esxPrivate *priv = domain->conn->privateData;
3863 3864 3865 3866
    xmlURIPtr parsedUri = NULL;
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3867
    esxVI_ObjectContent *virtualMachine = NULL;
3868 3869
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3870 3871 3872
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3873
    char *taskInfoErrorMessage = NULL;
3874

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

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

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

3891 3892
    /* Parse migration URI */
    parsedUri = xmlParseURI(uri);
3893

3894
    if (parsedUri == NULL) {
3895
        virReportOOMError();
M
Matthias Bolte 已提交
3896
        return -1;
3897 3898
    }

3899 3900 3901
    if (parsedUri->scheme == NULL || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3902
        goto cleanup;
3903 3904
    }

3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917
    if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Migration source and destination have to refer to "
                    "the same vCenter"));
        goto cleanup;
    }

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

    if (path_resourcePool == NULL || path_hostSystem == NULL) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Migration URI has to specify resource pool and host system"));
M
Matthias Bolte 已提交
3918
        goto cleanup;
3919 3920
    }

3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933
    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,
3934
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
3935
        goto cleanup;
3936 3937 3938
    }

    /* Validate the purposed migration */
3939
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3940 3941
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
3942
        goto cleanup;
3943 3944 3945 3946 3947 3948 3949 3950
    }

    if (eventList != NULL) {
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
        if (eventList->fullFormattedMessage != NULL) {
3951
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3952 3953
                      _("Could not migrate domain, validation reported a "
                        "problem: %s"), eventList->fullFormattedMessage);
3954
        } else {
3955 3956 3957
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                      _("Could not migrate domain, validation reported a "
                        "problem"));
3958 3959
        }

M
Matthias Bolte 已提交
3960
        goto cleanup;
3961 3962 3963
    }

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3977
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3978
                  _("Could not migrate domain, migration task finished with "
3979 3980
                    "an error: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3981
        goto cleanup;
3982 3983
    }

M
Matthias Bolte 已提交
3984 3985
    result = 0;

3986
  cleanup:
3987
    xmlFreeURI(parsedUri);
3988 3989 3990
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
3991
    VIR_FREE(taskInfoErrorMessage);
3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009

    return result;
}



static virDomainPtr
esxDomainMigrateFinish(virConnectPtr dconn, const char *dname,
                       const char *cookie ATTRIBUTE_UNUSED,
                       int cookielen ATTRIBUTE_UNUSED,
                       const char *uri ATTRIBUTE_UNUSED,
                       unsigned long flags ATTRIBUTE_UNUSED)
{
    return esxDomainLookupByName(dconn, dname);
}



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

4020
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4021
        return 0;
M
Matthias Bolte 已提交
4022 4023 4024
    }

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

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

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

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

    result = resourcePoolResourceUsage->unreservedForVm->value;

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

    return result;
}



4067 4068 4069
static int
esxIsEncrypted(virConnectPtr conn)
{
M
Matthias Bolte 已提交
4070
    esxPrivate *priv = conn->privateData;
4071

4072
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083
        return 1;
    } else {
        return 0;
    }
}



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

4086
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097
        return 1;
    } else {
        return 0;
    }
}



static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4098
    int result = -1;
M
Matthias Bolte 已提交
4099
    esxPrivate *priv = domain->conn->privateData;
4100 4101 4102 4103
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4104
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4105
        return -1;
4106 4107
    }

4108
    if (esxVI_String_AppendValueToList(&propertyNameList,
4109
                                       "runtime.powerState") < 0 ||
4110
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4111
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4112
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4113
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4114
        goto cleanup;
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138
    }

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

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

    return result;
}



static int
esxDomainIsPersistent(virDomainPtr domain ATTRIBUTE_UNUSED)
{
    /* ESX has no concept of transient domains, so all of them are persistent */
    return 1;
}

M
Matthias Bolte 已提交
4139 4140


4141 4142 4143 4144 4145
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
    return 0;
}
4146

M
Matthias Bolte 已提交
4147 4148


4149 4150
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4151
                           unsigned int flags)
4152 4153 4154 4155 4156 4157 4158 4159 4160
{
    esxPrivate *priv = domain->conn->privateData;
    virDomainSnapshotDefPtr def = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4161
    char *taskInfoErrorMessage = NULL;
4162 4163
    virDomainSnapshotPtr snapshot = NULL;

4164 4165
    virCheckFlags(0, NULL);

4166
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4167
        return NULL;
4168 4169 4170 4171 4172
    }

    def = virDomainSnapshotDefParseString(xmlDesc, 1);

    if (def == NULL) {
M
Matthias Bolte 已提交
4173
        return NULL;
4174 4175 4176
    }

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4177
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4178
           priv->parsedUri->autoAnswer) < 0 ||
4179
        esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4180 4181 4182 4183
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, def->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4184
        goto cleanup;
4185 4186 4187 4188 4189
    }

    if (snapshotTree != NULL) {
        ESX_ERROR(VIR_ERR_OPERATION_INVALID,
                  _("Snapshot '%s' already exists"), def->name);
M
Matthias Bolte 已提交
4190
        goto cleanup;
4191 4192
    }

4193
    if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4194 4195 4196
                                  def->name, def->description,
                                  esxVI_Boolean_True,
                                  esxVI_Boolean_False, &task) < 0 ||
4197
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4198
                                    esxVI_Occurrence_RequiredItem,
4199
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4200
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4201
        goto cleanup;
4202 4203 4204
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4205 4206
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
4207
        goto cleanup;
4208 4209 4210 4211 4212 4213 4214 4215 4216
    }

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

  cleanup:
    virDomainSnapshotDefFree(def);
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4217
    VIR_FREE(taskInfoErrorMessage);
4218 4219 4220 4221 4222 4223 4224

    return snapshot;
}



static char *
4225 4226
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4227 4228 4229 4230 4231 4232 4233 4234 4235
{
    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;

4236 4237
    virCheckFlags(0, NULL);

M
Matthias Bolte 已提交
4238
    memset(&def, 0, sizeof (def));
4239

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

4244
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4245 4246 4247 4248
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4249
        goto cleanup;
4250 4251 4252 4253 4254 4255 4256 4257
    }

    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 已提交
4258
        goto cleanup;
4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276
    }

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

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

    xml = virDomainSnapshotDefFormat(uuid_string, &def, 0);

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



static int
4277
esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4278
{
M
Matthias Bolte 已提交
4279
    int count;
4280 4281 4282
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;

4283 4284
    virCheckFlags(0, -1);

4285
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4286
        return -1;
4287 4288
    }

4289
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4290
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4291
        return -1;
4292 4293
    }

M
Matthias Bolte 已提交
4294
    count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList);
4295 4296 4297

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

M
Matthias Bolte 已提交
4298
    return count;
4299 4300 4301 4302 4303 4304
}



static int
esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4305
                           unsigned int flags)
4306
{
M
Matthias Bolte 已提交
4307
    int result;
4308 4309 4310
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;

4311 4312
    virCheckFlags(0, -1);

4313 4314 4315 4316 4317 4318 4319 4320 4321
    if (names == NULL || nameslen < 0) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
        return -1;
    }

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

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

4326
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4327
                                         &rootSnapshotTreeList) < 0) {
M
Matthias Bolte 已提交
4328
        return -1;
4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341
    }

    result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen);

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4342
                              unsigned int flags)
4343 4344 4345 4346 4347 4348 4349
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotPtr snapshot = NULL;

4350 4351
    virCheckFlags(0, NULL);

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

4356
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379
                                         &rootSnapshotTreeList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
                                    &snapshotTreeParent,
                                    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;

4380
    virCheckFlags(0, -1);
4381

4382
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4383
        return -1;
4384 4385
    }

4386
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4387 4388
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
4389
        return -1;
4390 4391 4392
    }

    if (currentSnapshotTree != NULL) {
M
Matthias Bolte 已提交
4393 4394
        esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
        return 1;
4395 4396
    }

M
Matthias Bolte 已提交
4397
    return 0;
4398 4399 4400 4401 4402 4403 4404 4405 4406
}



static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
{
    esxPrivate *priv = domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
M
Matthias Bolte 已提交
4407
    virDomainSnapshotPtr snapshot = NULL;
4408

4409
    virCheckFlags(0, NULL);
4410

4411
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4412
        return NULL;
4413 4414
    }

4415
    if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4416 4417
                                        &currentSnapshotTree,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4418
        return NULL;
4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432
    }

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}



static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4433
    int result = -1;
4434 4435 4436 4437 4438 4439
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4440
    char *taskInfoErrorMessage = NULL;
4441

4442
    virCheckFlags(0, -1);
4443

4444
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4445
        return -1;
4446 4447
    }

4448
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4449 4450 4451 4452
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4453
        goto cleanup;
4454 4455
    }

4456
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4457
                                    &task) < 0 ||
4458
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4459
                                    esxVI_Occurrence_RequiredItem,
4460
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4461
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4462
        goto cleanup;
4463 4464 4465 4466
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
4467 4468
                  _("Could not revert to snapshot '%s': %s"), snapshot->name,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
4469
        goto cleanup;
4470 4471
    }

M
Matthias Bolte 已提交
4472 4473
    result = 0;

4474 4475 4476
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4477
    VIR_FREE(taskInfoErrorMessage);
4478 4479 4480 4481 4482 4483 4484 4485 4486

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4487
    int result = -1;
4488 4489 4490 4491 4492 4493 4494
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    esxVI_Boolean removeChildren = esxVI_Boolean_False;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4495
    char *taskInfoErrorMessage = NULL;
4496

4497 4498
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);

4499
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4500
        return -1;
4501 4502 4503 4504 4505 4506
    }

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

4507
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4508 4509 4510 4511
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
                                    &snapshotTree, &snapshotTreeParent,
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4512
        goto cleanup;
4513 4514
    }

4515
    if (esxVI_RemoveSnapshot_Task(priv->primary, snapshotTree->snapshot,
4516
                                  removeChildren, &task) < 0 ||
4517
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4518
                                    esxVI_Occurrence_RequiredItem,
4519
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4520
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4521
        goto cleanup;
4522 4523 4524 4525
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
4526 4527
                  _("Could not delete snapshot '%s': %s"), snapshot->name,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
4528
        goto cleanup;
4529 4530
    }

M
Matthias Bolte 已提交
4531 4532
    result = 0;

4533 4534 4535
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4536
    VIR_FREE(taskInfoErrorMessage);
4537 4538 4539 4540 4541 4542

    return result;
}



4543
static int
4544
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4545 4546 4547 4548 4549 4550 4551 4552
                             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;
4553
    char *taskInfoErrorMessage = NULL;
4554 4555 4556 4557 4558 4559 4560 4561 4562 4563
    int i;

    virCheckFlags(0, -1);

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

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4564
           priv->parsedUri->autoAnswer) < 0 ||
4565 4566 4567 4568 4569 4570 4571
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
        goto cleanup;
    }

    for (i = 0; i < nparams; ++i) {
        if (STREQ (params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE) &&
4572
            params[i].type == VIR_TYPED_PARAM_ULLONG) {
4573 4574 4575 4576 4577
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) {
                goto cleanup;
            }

            spec->memoryAllocation->reservation->value =
4578
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589
        } else {
            ESX_ERROR(VIR_ERR_INVALID_ARG, _("Unknown field '%s'"),
                      params[i].field);
            goto cleanup;
        }
    }

    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
                                    esxVI_Occurrence_RequiredItem,
4590
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4591
                                    &taskInfoErrorMessage) < 0) {
4592 4593 4594 4595
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4596 4597 4598
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not change memory parameters: %s"),
                  taskInfoErrorMessage);
4599 4600 4601 4602 4603 4604 4605 4606 4607
        goto cleanup;
    }

    result = 0;

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4608
    VIR_FREE(taskInfoErrorMessage);
4609 4610 4611 4612 4613 4614 4615

    return result;
}



static int
4616
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659
                             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 (*nparams < 1) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Parameter array must have space for 1 item"));
        return -1;
    }

    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;
    }

    if (virStrcpyStatic(params[0].field,
                        VIR_DOMAIN_MEMORY_MIN_GUARANTEE) == NULL) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Field %s too big for destination"),
                  VIR_DOMAIN_MEMORY_MIN_GUARANTEE);
        goto cleanup;
    }

4660
    params[0].type = VIR_TYPED_PARAM_ULLONG;
4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675
    params[0].value.ul = reservation->value * 1024; /* Scale from megabytes to kilobytes */

    *nparams = 1;
    result = 0;

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

    return result;
}



4676
static virDriver esxDriver = {
4677 4678
    .no = VIR_DRV_ESX,
    .name = "ESX",
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
    .open = esxOpen, /* 0.7.0 */
    .close = esxClose, /* 0.7.0 */
    .supports_feature = esxSupportsFeature, /* 0.7.0 */
    .type = esxGetType, /* 0.7.0 */
    .version = esxGetVersion, /* 0.7.0 */
    .getHostname = esxGetHostname, /* 0.7.0 */
    .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
    .getCapabilities = esxGetCapabilities, /* 0.7.1 */
    .listDomains = esxListDomains, /* 0.7.0 */
    .numOfDomains = esxNumberOfDomains, /* 0.7.0 */
    .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 */
    .domainReboot = esxDomainReboot, /* 0.7.0 */
    .domainDestroy = esxDomainDestroy, /* 0.7.0 */
    .domainGetOSType = esxDomainGetOSType, /* 0.7.0 */
    .domainGetMaxMemory = esxDomainGetMaxMemory, /* 0.7.0 */
    .domainSetMaxMemory = esxDomainSetMaxMemory, /* 0.7.0 */
    .domainSetMemory = esxDomainSetMemory, /* 0.7.0 */
    .domainSetMemoryParameters = esxDomainSetMemoryParameters, /* 0.8.6 */
    .domainGetMemoryParameters = esxDomainGetMemoryParameters, /* 0.8.6 */
    .domainGetInfo = esxDomainGetInfo, /* 0.7.0 */
    .domainGetState = esxDomainGetState, /* 0.9.2 */
    .domainSetVcpus = esxDomainSetVcpus, /* 0.7.0 */
    .domainSetVcpusFlags = esxDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = esxDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = esxDomainGetMaxVcpus, /* 0.7.0 */
    .domainGetXMLDesc = esxDomainGetXMLDesc, /* 0.7.0 */
    .domainXMLFromNative = esxDomainXMLFromNative, /* 0.7.0 */
    .domainXMLToNative = esxDomainXMLToNative, /* 0.7.2 */
    .listDefinedDomains = esxListDefinedDomains, /* 0.7.0 */
    .numOfDefinedDomains = esxNumberOfDefinedDomains, /* 0.7.0 */
    .domainCreate = esxDomainCreate, /* 0.7.0 */
    .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
    .domainUndefine = esxDomainUndefine, /* 0.7.1 */
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
4722
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
4723
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
4724
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742
    .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
    .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
    .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
    .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
    .isEncrypted = esxIsEncrypted, /* 0.7.3 */
    .isSecure = esxIsSecure, /* 0.7.3 */
    .domainIsActive = esxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = esxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = esxDomainIsUpdated, /* 0.8.6 */
    .domainSnapshotCreateXML = esxDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = esxDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = esxDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = esxDomainSnapshotListNames, /* 0.8.0 */
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
4743 4744 4745 4746 4747 4748 4749
};



int
esxRegister(void)
{
4750 4751 4752 4753 4754
    if (virRegisterDriver(&esxDriver) < 0 ||
        esxInterfaceRegister() < 0 ||
        esxNetworkRegister() < 0 ||
        esxStorageRegister() < 0 ||
        esxDeviceRegister() < 0 ||
M
Matthias Bolte 已提交
4755 4756
        esxSecretRegister() < 0 ||
        esxNWFilterRegister() < 0) {
4757 4758
        return -1;
    }
4759 4760 4761

    return 0;
}