esx_driver.c 157.8 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
 *
 * The datastore path format and the formats found in a .vmx file are described
 * in the documentation of esxParseVMXFileName.
 *
 * Firstly parse the datastore path. Then use the datastore name to lookup the
 * datastore and it's mount path. Finally concatenate the mount path, directory
E
Eric Blake 已提交
279
 * and file name to an absolute path and return it. Detect the separator type
280 281
 * 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

    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")) {
415
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
416 417
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicController")) {
418
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
419 420
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "VirtualLsiLogicSASController")) {
421
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068;
422 423
    } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
                         "ParaVirtualSCSIController")) {
424
        *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI;
425 426 427 428 429 430 431 432 433 434
    } 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
            priv->host->productVersion != esxVI_ProductVersion_ESX40 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX41 &&
P
Patrice LACHANCE 已提交
733 734 735
            priv->host->productVersion != esxVI_ProductVersion_ESX4x &&
            priv->host->productVersion != esxVI_ProductVersion_ESX50 &&
            priv->host->productVersion != esxVI_ProductVersion_ESX5x) {
736
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
P
Patrice LACHANCE 已提交
737
                      _("%s is neither an ESX 3.5, 4.x nor 5.x host"),
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
                      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 ||
753 754
        esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
                                         &hostSystem) < 0 ||
755 756 757 758 759 760 761 762 763 764 765
        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) {
766
        VIR_WARN("The server is in maintenance mode");
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
    }

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

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

    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
782 783
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
784 785 786 787 788 789 790 791 792 793 794 795 796
    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,
797
                    const char *hostSystemIpAddress)
798 799 800 801
{
    int result = -1;
    char ipAddress[NI_MAXHOST] = "";
    char *username = NULL;
M
Matthias Bolte 已提交
802
    char *unescapedPassword = NULL;
803 804 805
    char *password = NULL;
    char *url = NULL;

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

814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
    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 已提交
834
    unescapedPassword = virRequestPassword(auth, username, hostname);
835

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

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

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

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

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

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

871 872 873 874 875 876
    if (hostSystemIpAddress != NULL) {
        if (esxVI_Context_LookupObjectsByHostSystemIp(priv->vCenter,
                                                      hostSystemIpAddress) < 0) {
            goto cleanup;
        }
    } else {
877 878
        if (esxVI_Context_LookupObjectsByPath(priv->vCenter,
                                              priv->parsedUri) < 0) {
879 880 881 882
            goto cleanup;
        }
    }

883 884 885 886
    result = 0;

  cleanup:
    VIR_FREE(username);
M
Matthias Bolte 已提交
887 888
    VIR_FREE(unescapedPassword);
    VIR_FREE(password);
889 890 891 892 893 894 895
    VIR_FREE(url);

    return result;
}



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

E
Eric Blake 已提交
950 951
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

952 953
    /* Decline if the URI is NULL or the scheme is NULL */
    if (conn->uri == NULL || conn->uri->scheme == NULL) {
954 955 956
        return VIR_DRV_OPEN_DECLINED;
    }

957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
    /* Decline if the scheme is not one of {vpx|esx|gsx} */
    plus = strchr(conn->uri->scheme, '+');

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

        ESX_ERROR(VIR_ERR_INVALID_ARG,
                  _("Transport '%s' in URI scheme is not supported, try again "
                    "without the transport part"), plus + 1);
        return VIR_DRV_OPEN_ERROR;
    }

980 981 982 983 984 985 986 987 988 989 990 991
    /* 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;
992 993 994 995
    }

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

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

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

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

1032 1033 1034 1035
    if (STRCASEEQ(conn->uri->scheme, "esx") ||
        STRCASEEQ(conn->uri->scheme, "gsx")) {
        /* Connect to host */
        if (esxConnectToHost(priv, auth, conn->uri->server, conn->uri->port,
1036
                             conn->uri->user,
1037 1038 1039 1040
                             STRCASEEQ(conn->uri->scheme, "esx")
                               ? esxVI_ProductVersion_ESX
                               : esxVI_ProductVersion_GSX,
                             &potentialVCenterIpAddress) < 0) {
M
Matthias Bolte 已提交
1041
            goto cleanup;
1042
        }
1043

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

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

1066 1067
                if (potentialVCenterIpAddress != NULL &&
                    STRNEQ(vCenterIpAddress, potentialVCenterIpAddress)) {
1068
                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1069 1070 1071
                              _("This host is managed by a vCenter with IP "
                                "address %s, but a mismachting vCenter '%s' "
                                "(%s) has been specified"),
1072
                              potentialVCenterIpAddress, priv->parsedUri->vCenter,
1073
                              vCenterIpAddress);
M
Matthias Bolte 已提交
1074
                    goto cleanup;
1075 1076
                }
            }
1077

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

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

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

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

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

1103 1104
    conn->privateData = priv;

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

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

1112
    VIR_FREE(potentialVCenterIpAddress);
1113

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



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

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

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

1139
    esxFreePrivate(&priv);
1140 1141 1142

    conn->privateData = NULL;

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



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

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

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

1162
    if (esxVI_String_AppendValueToList(&propertyNameList,
1163
                                       "capability.vmotionSupported") < 0 ||
1164 1165
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1166
        goto cleanup;
1167 1168 1169
    }

    if (hostSystem == NULL) {
1170 1171
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1172
        goto cleanup;
1173 1174
    }

1175 1176 1177 1178
    if (esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
                         &priv->supportsVMotion,
                         esxVI_Occurrence_RequiredItem) < 0) {
        goto cleanup;
1179 1180 1181
    }

  cleanup:
M
Matthias Bolte 已提交
1182 1183 1184 1185
    /*
     * 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.
     */
1186 1187 1188
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

M
Matthias Bolte 已提交
1189
    return priv->supportsVMotion;
1190 1191 1192 1193 1194 1195 1196
}



static int
esxSupportsFeature(virConnectPtr conn, int feature)
{
M
Matthias Bolte 已提交
1197
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1198
    esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1199 1200 1201

    switch (feature) {
      case VIR_DRV_FEATURE_MIGRATION_V1:
1202
        supportsVMotion = esxSupportsVMotion(priv);
1203

M
Matthias Bolte 已提交
1204
        if (supportsVMotion == esxVI_Boolean_Undefined) {
1205 1206 1207
            return -1;
        }

M
Matthias Bolte 已提交
1208 1209 1210
        /* Migration is only possible via a vCenter and if VMotion is enabled */
        return priv->vCenter != NULL &&
               supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229

      default:
        return 0;
    }
}



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



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

1232
    if (virParseVersionString(priv->primary->service->about->version,
1233
                              version, false) < 0) {
1234
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1235
                  _("Could not parse version number from '%s'"),
1236
                  priv->primary->service->about->version);
1237

1238
        return -1;
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
    }

    return 0;
}



static char *
esxGetHostname(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1249
    esxPrivate *priv = conn->privateData;
1250 1251 1252 1253 1254 1255 1256
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    const char *hostName = NULL;
    const char *domainName = NULL;
    char *complete = NULL;

1257
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1258
        return NULL;
1259 1260 1261
    }

    if (esxVI_String_AppendValueListToList
1262
          (&propertyNameList,
1263 1264
           "config.network.dnsConfig.hostName\0"
           "config.network.dnsConfig.domainName\0") < 0 ||
1265 1266
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1267
        goto cleanup;
1268 1269 1270
    }

    if (hostSystem == NULL) {
1271 1272
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1273
        goto cleanup;
1274 1275 1276 1277 1278 1279
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name,
                  "config.network.dnsConfig.hostName")) {
1280
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1281
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1282
                goto cleanup;
1283 1284 1285 1286 1287
            }

            hostName = dynamicProperty->val->string;
        } else if (STREQ(dynamicProperty->name,
                         "config.network.dnsConfig.domainName")) {
1288
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1289
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1290
                goto cleanup;
1291 1292 1293 1294 1295 1296 1297 1298
            }

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

M
Matthias Bolte 已提交
1299
    if (hostName == NULL || strlen(hostName) < 1) {
1300 1301
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Missing or empty 'hostName' property"));
M
Matthias Bolte 已提交
1302
        goto cleanup;
1303 1304
    }

M
Matthias Bolte 已提交
1305
    if (domainName == NULL || strlen(domainName) < 1) {
1306
        complete = strdup(hostName);
1307

1308
        if (complete == NULL) {
1309
            virReportOOMError();
M
Matthias Bolte 已提交
1310
            goto cleanup;
1311 1312 1313
        }
    } else {
        if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0) {
1314
            virReportOOMError();
M
Matthias Bolte 已提交
1315
            goto cleanup;
1316
        }
1317 1318 1319
    }

  cleanup:
M
Matthias Bolte 已提交
1320 1321 1322 1323 1324
    /*
     * 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
     */
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return complete;
}



static int
esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
{
M
Matthias Bolte 已提交
1336
    int result = -1;
M
Matthias Bolte 已提交
1337
    esxPrivate *priv = conn->privateData;
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
    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 已提交
1349
    memset(nodeinfo, 0, sizeof (*nodeinfo));
1350

1351
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1352
        return -1;
1353 1354
    }

1355
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1356 1357 1358 1359 1360 1361 1362
                                           "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 ||
1363 1364
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
1365
        goto cleanup;
1366 1367 1368
    }

    if (hostSystem == NULL) {
1369 1370
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
1371
        goto cleanup;
1372 1373 1374 1375 1376
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1377
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1378
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1379
                goto cleanup;
1380 1381 1382 1383 1384
            }

            cpuInfo_hz = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuCores")) {
1385
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1386
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1387
                goto cleanup;
1388 1389 1390 1391 1392
            }

            cpuInfo_numCpuCores = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuPackages")) {
1393
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1394
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1395
                goto cleanup;
1396 1397 1398 1399 1400
            }

            cpuInfo_numCpuPackages = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.cpuInfo.numCpuThreads")) {
1401
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1402
                                         esxVI_Type_Short) < 0) {
M
Matthias Bolte 已提交
1403
                goto cleanup;
1404 1405 1406 1407
            }

            cpuInfo_numCpuThreads = dynamicProperty->val->int16;
        } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1408
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1409
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
1410
                goto cleanup;
1411 1412 1413 1414 1415
            }

            memorySize = dynamicProperty->val->int64;
        } else if (STREQ(dynamicProperty->name,
                         "hardware.numaInfo.numNodes")) {
1416
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1417
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
1418
                goto cleanup;
1419 1420 1421 1422 1423
            }

            numaInfo_numNodes = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "summary.hardware.cpuModel")) {
1424
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1425
                                         esxVI_Type_String) < 0) {
M
Matthias Bolte 已提交
1426
                goto cleanup;
1427 1428 1429 1430 1431 1432
            }

            ptr = dynamicProperty->val->string;

            /* Strip the string to fit more relevant information in 32 chars */
            while (*ptr != '\0') {
M
Matthias Bolte 已提交
1433 1434
                if (STRPREFIX(ptr, "  ")) {
                    memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1435
                    continue;
1436
                } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
M
Matthias Bolte 已提交
1437
                    memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1438
                    continue;
1439 1440 1441
                } else if (STRPREFIX(ptr, "(TM)")) {
                    memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
                    continue;
1442 1443 1444 1445 1446
                }

                ++ptr;
            }

C
Chris Lalancette 已提交
1447 1448 1449
            if (virStrncpy(nodeinfo->model, dynamicProperty->val->string,
                           sizeof(nodeinfo->model) - 1,
                           sizeof(nodeinfo->model)) == NULL) {
1450
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1451
                          _("CPU Model %s too long for destination"),
C
Chris Lalancette 已提交
1452
                          dynamicProperty->val->string);
M
Matthias Bolte 已提交
1453
                goto cleanup;
C
Chris Lalancette 已提交
1454
            }
1455 1456 1457 1458 1459 1460 1461
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

    nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
    nodeinfo->cpus = cpuInfo_numCpuCores;
1462
    nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1463 1464 1465 1466 1467 1468 1469 1470 1471
    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 已提交
1472 1473
    result = 0;

1474 1475 1476 1477 1478 1479 1480 1481 1482
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&hostSystem);

    return result;
}



1483 1484 1485
static char *
esxGetCapabilities(virConnectPtr conn)
{
M
Matthias Bolte 已提交
1486
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
1487
    char *xml = virCapabilitiesFormatXML(priv->caps);
1488 1489

    if (xml == NULL) {
1490
        virReportOOMError();
1491 1492 1493 1494 1495 1496 1497 1498
        return NULL;
    }

    return xml;
}



1499 1500 1501
static int
esxListDomains(virConnectPtr conn, int *ids, int maxids)
{
M
Matthias Bolte 已提交
1502
    bool success = false;
M
Matthias Bolte 已提交
1503
    esxPrivate *priv = conn->privateData;
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;

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

1514
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1515
        return -1;
1516 1517
    }

1518
    if (esxVI_String_AppendValueToList(&propertyNameList,
1519
                                       "runtime.powerState") < 0 ||
1520 1521
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1522
        goto cleanup;
1523 1524 1525 1526
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1527
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1528
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1529
            goto cleanup;
1530 1531 1532 1533 1534 1535 1536 1537 1538
        }

        if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

        if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
                                                &ids[count]) < 0 ||
            ids[count] <= 0) {
1539
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
1540
                      _("Failed to parse positive integer from '%s'"),
1541
                      virtualMachine->obj->value);
M
Matthias Bolte 已提交
1542
            goto cleanup;
1543 1544 1545 1546 1547 1548 1549 1550 1551
        }

        count++;

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

M
Matthias Bolte 已提交
1552 1553
    success = true;

1554 1555 1556 1557
  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);

M
Matthias Bolte 已提交
1558
    return success ? count : -1;
1559 1560 1561 1562 1563 1564 1565
}



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

1568
    if (esxVI_EnsureSession(priv->primary) < 0) {
1569 1570 1571
        return -1;
    }

1572
    return esxVI_LookupNumberOfDomainsByPowerState
1573
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1574 1575 1576 1577 1578 1579 1580
}



static virDomainPtr
esxDomainLookupByID(virConnectPtr conn, int id)
{
M
Matthias Bolte 已提交
1581
    esxPrivate *priv = conn->privateData;
1582 1583 1584 1585
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
M
Matthias Bolte 已提交
1586 1587 1588
    int id_candidate = -1;
    char *name_candidate = NULL;
    unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1589 1590
    virDomainPtr domain = NULL;

1591
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1592
        return NULL;
1593 1594
    }

1595
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1596
                                           "configStatus\0"
1597 1598
                                           "name\0"
                                           "runtime.powerState\0"
1599
                                           "config.uuid\0") < 0 ||
1600 1601
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
1602
        goto cleanup;
1603 1604 1605 1606
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
1607
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1608
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
1609
            goto cleanup;
1610 1611 1612 1613 1614 1615 1616
        }

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

M
Matthias Bolte 已提交
1617
        VIR_FREE(name_candidate);
1618

1619
        if (esxVI_GetVirtualMachineIdentity(virtualMachine,
M
Matthias Bolte 已提交
1620 1621
                                            &id_candidate, &name_candidate,
                                            uuid_candidate) < 0) {
M
Matthias Bolte 已提交
1622
            goto cleanup;
1623 1624
        }

M
Matthias Bolte 已提交
1625
        if (id != id_candidate) {
1626 1627 1628
            continue;
        }

M
Matthias Bolte 已提交
1629
        domain = virGetDomain(conn, name_candidate, uuid_candidate);
1630 1631

        if (domain == NULL) {
M
Matthias Bolte 已提交
1632
            goto cleanup;
1633 1634 1635 1636 1637 1638 1639 1640
        }

        domain->id = id;

        break;
    }

    if (domain == NULL) {
1641
        ESX_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1642 1643 1644 1645 1646
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
M
Matthias Bolte 已提交
1647
    VIR_FREE(name_candidate);
1648 1649 1650 1651 1652 1653 1654 1655 1656

    return domain;
}



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

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

1669
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1670
                                           "name\0"
1671
                                           "runtime.powerState\0") < 0 ||
1672
        esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1673
                                         &virtualMachine,
M
Matthias Bolte 已提交
1674
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1675 1676
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1677
        goto cleanup;
1678 1679
    }

1680
    domain = virGetDomain(conn, name, uuid);
1681 1682

    if (domain == NULL) {
M
Matthias Bolte 已提交
1683
        goto cleanup;
1684
    }
1685

1686 1687 1688 1689 1690
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1691 1692 1693 1694
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1695 1696
    esxVI_ObjectContent_Free(&virtualMachine);
    VIR_FREE(name);
1697 1698 1699 1700 1701 1702 1703 1704 1705

    return domain;
}



static virDomainPtr
esxDomainLookupByName(virConnectPtr conn, const char *name)
{
M
Matthias Bolte 已提交
1706
    esxPrivate *priv = conn->privateData;
1707 1708 1709
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
1710 1711
    int id = -1;
    unsigned char uuid[VIR_UUID_BUFLEN];
1712 1713
    virDomainPtr domain = NULL;

1714
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1715
        return NULL;
1716 1717
    }

1718
    if (esxVI_String_AppendValueListToList(&propertyNameList,
1719
                                           "configStatus\0"
1720
                                           "runtime.powerState\0"
1721
                                           "config.uuid\0") < 0 ||
1722
        esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1723 1724
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
1725
        goto cleanup;
1726 1727
    }

1728
    if (virtualMachine == NULL) {
1729
        ESX_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with name '%s'"), name);
M
Matthias Bolte 已提交
1730
        goto cleanup;
1731
    }
1732

M
Matthias Bolte 已提交
1733 1734 1735
    if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
        goto cleanup;
1736
    }
1737

1738
    domain = virGetDomain(conn, name, uuid);
1739

1740
    if (domain == NULL) {
M
Matthias Bolte 已提交
1741
        goto cleanup;
1742 1743
    }

1744 1745 1746 1747 1748
    /* Only running/suspended virtual machines have an ID != -1 */
    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
        domain->id = id;
    } else {
        domain->id = -1;
1749 1750 1751 1752
    }

  cleanup:
    esxVI_String_Free(&propertyNameList);
1753
    esxVI_ObjectContent_Free(&virtualMachine);
1754 1755 1756 1757 1758 1759 1760 1761 1762

    return domain;
}



static int
esxDomainSuspend(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1763
    int result = -1;
M
Matthias Bolte 已提交
1764
    esxPrivate *priv = domain->conn->privateData;
1765 1766 1767 1768 1769
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1770
    char *taskInfoErrorMessage = NULL;
1771

1772
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1773
        return -1;
1774 1775
    }

1776
    if (esxVI_String_AppendValueToList(&propertyNameList,
1777
                                       "runtime.powerState") < 0 ||
1778
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1779
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1780
           priv->parsedUri->autoAnswer) < 0 ||
1781
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1782
        goto cleanup;
1783 1784 1785
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1786 1787
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1788
        goto cleanup;
1789 1790
    }

1791 1792
    if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1793
                                    esxVI_Occurrence_RequiredItem,
1794
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1795
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1796
        goto cleanup;
1797 1798 1799
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1800 1801
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
1802
        goto cleanup;
1803 1804
    }

M
Matthias Bolte 已提交
1805 1806
    result = 0;

1807 1808 1809 1810
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1811
    VIR_FREE(taskInfoErrorMessage);
1812 1813 1814 1815 1816 1817 1818 1819 1820

    return result;
}



static int
esxDomainResume(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1821
    int result = -1;
M
Matthias Bolte 已提交
1822
    esxPrivate *priv = domain->conn->privateData;
1823 1824 1825 1826 1827
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1828
    char *taskInfoErrorMessage = NULL;
1829

1830
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1831
        return -1;
1832 1833
    }

1834
    if (esxVI_String_AppendValueToList(&propertyNameList,
1835
                                       "runtime.powerState") < 0 ||
1836
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1837
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1838
           priv->parsedUri->autoAnswer) < 0 ||
1839
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1840
        goto cleanup;
1841 1842 1843
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1844
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
M
Matthias Bolte 已提交
1845
        goto cleanup;
1846 1847
    }

1848
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1849
                             &task) < 0 ||
1850
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1851
                                    esxVI_Occurrence_RequiredItem,
1852
                                    priv->parsedUri->autoAnswer, &taskInfoState,
1853
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
1854
        goto cleanup;
1855 1856 1857
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
1858 1859
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
1860
        goto cleanup;
1861 1862
    }

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

1865 1866 1867 1868
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
1869
    VIR_FREE(taskInfoErrorMessage);
1870 1871 1872 1873 1874 1875 1876 1877 1878

    return result;
}



static int
esxDomainShutdown(virDomainPtr domain)
{
M
Matthias Bolte 已提交
1879
    int result = -1;
M
Matthias Bolte 已提交
1880
    esxPrivate *priv = domain->conn->privateData;
1881 1882 1883 1884
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

1885
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1886
        return -1;
1887 1888
    }

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

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1899 1900
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1901
        goto cleanup;
1902 1903
    }

1904
    if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1905
        goto cleanup;
1906 1907
    }

M
Matthias Bolte 已提交
1908 1909
    result = 0;

1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
E
Eric Blake 已提交
1920
esxDomainReboot(virDomainPtr domain, unsigned int flags)
1921
{
M
Matthias Bolte 已提交
1922
    int result = -1;
M
Matthias Bolte 已提交
1923
    esxPrivate *priv = domain->conn->privateData;
1924 1925 1926 1927
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

E
Eric Blake 已提交
1928 1929
    virCheckFlags(0, -1);

1930
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
1931
        return -1;
1932 1933
    }

1934
    if (esxVI_String_AppendValueToList(&propertyNameList,
1935
                                       "runtime.powerState") < 0 ||
1936
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1937
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
1938
                                         esxVI_Occurrence_RequiredItem) < 0 ||
1939
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1940
        goto cleanup;
1941 1942 1943
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1944 1945
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
1946
        goto cleanup;
1947 1948
    }

1949
    if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
1950
        goto cleanup;
1951 1952
    }

M
Matthias Bolte 已提交
1953 1954
    result = 0;

1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}



static int
1965 1966
esxDomainDestroyFlags(virDomainPtr domain,
                      unsigned int flags)
1967
{
M
Matthias Bolte 已提交
1968
    int result = -1;
M
Matthias Bolte 已提交
1969
    esxPrivate *priv = domain->conn->privateData;
1970
    esxVI_Context *ctx = NULL;
1971 1972 1973 1974 1975
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
1976
    char *taskInfoErrorMessage = NULL;
1977

1978 1979
    virCheckFlags(0, -1);

1980 1981 1982 1983 1984 1985
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

1986
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
1987
        return -1;
1988 1989
    }

1990
    if (esxVI_String_AppendValueToList(&propertyNameList,
1991
                                       "runtime.powerState") < 0 ||
1992
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1993
          (ctx, domain->uuid, propertyNameList, &virtualMachine,
1994
           priv->parsedUri->autoAnswer) < 0 ||
1995
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
1996
        goto cleanup;
1997 1998 1999
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
2000 2001
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered on"));
M
Matthias Bolte 已提交
2002
        goto cleanup;
2003 2004
    }

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

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2014 2015
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2016
        goto cleanup;
2017 2018
    }

2019
    domain->id = -1;
M
Matthias Bolte 已提交
2020 2021
    result = 0;

2022 2023 2024 2025
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
2026
    VIR_FREE(taskInfoErrorMessage);
2027 2028 2029 2030 2031

    return result;
}


2032 2033 2034 2035 2036 2037
static int
esxDomainDestroy(virDomainPtr dom)
{
    return esxDomainDestroyFlags(dom, 0);
}

2038 2039

static char *
2040
esxDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
2041
{
2042 2043 2044
    char *osType = strdup("hvm");

    if (osType == NULL) {
2045
        virReportOOMError();
2046 2047 2048 2049
        return NULL;
    }

    return osType;
2050 2051 2052 2053 2054 2055 2056
}



static unsigned long
esxDomainGetMaxMemory(virDomainPtr domain)
{
M
Matthias Bolte 已提交
2057
    esxPrivate *priv = domain->conn->privateData;
2058 2059 2060 2061 2062
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    unsigned long memoryMB = 0;

2063
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2064
        return 0;
2065 2066
    }

2067
    if (esxVI_String_AppendValueToList(&propertyNameList,
2068
                                       "config.hardware.memoryMB") < 0 ||
2069
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2070
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2071
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2072
        goto cleanup;
2073 2074 2075 2076 2077
    }

    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2078
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2079
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2080
                goto cleanup;
2081 2082 2083
            }

            if (dynamicProperty->val->int32 < 0) {
2084 2085
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                          _("Got invalid memory size %d"),
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
                          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 已提交
2109
    int result = -1;
M
Matthias Bolte 已提交
2110
    esxPrivate *priv = domain->conn->privateData;
2111
    esxVI_String *propertyNameList = NULL;
2112
    esxVI_ObjectContent *virtualMachine = NULL;
2113
    esxVI_VirtualMachinePowerState powerState;
2114 2115 2116
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2117
    char *taskInfoErrorMessage = NULL;
2118

2119
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2120
        return -1;
2121 2122
    }

2123 2124 2125 2126
    if (esxVI_String_AppendValueToList(&propertyNameList,
                                       "runtime.powerState") < 0 ||
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2127
           priv->parsedUri->autoAnswer) < 0 ||
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
        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 ||
2139
        esxVI_Long_Alloc(&spec->memoryMB) < 0) {
M
Matthias Bolte 已提交
2140
        goto cleanup;
2141 2142
    }

2143
    /* max-memory must be a multiple of 4096 kilobyte */
2144
    spec->memoryMB->value =
2145
      VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
2146

2147
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2148
                              &task) < 0 ||
2149
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2150
                                    esxVI_Occurrence_RequiredItem,
2151
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2152
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2153
        goto cleanup;
2154 2155 2156
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2157
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2158 2159
                  _("Could not set max-memory to %lu kilobytes: %s"), memory,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2160
        goto cleanup;
2161 2162
    }

M
Matthias Bolte 已提交
2163 2164
    result = 0;

2165
  cleanup:
2166
    esxVI_String_Free(&propertyNameList);
2167 2168 2169
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2170
    VIR_FREE(taskInfoErrorMessage);
2171 2172 2173 2174 2175 2176 2177 2178 2179

    return result;
}



static int
esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
M
Matthias Bolte 已提交
2180
    int result = -1;
M
Matthias Bolte 已提交
2181
    esxPrivate *priv = domain->conn->privateData;
2182 2183 2184 2185
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2186
    char *taskInfoErrorMessage = NULL;
2187

2188
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2189
        return -1;
2190 2191
    }

2192
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2193
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2194
           priv->parsedUri->autoAnswer) < 0 ||
2195 2196 2197
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
        esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
M
Matthias Bolte 已提交
2198
        goto cleanup;
2199 2200 2201
    }

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

2204
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2205
                              &task) < 0 ||
2206
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2207
                                    esxVI_Occurrence_RequiredItem,
2208
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2209
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2210
        goto cleanup;
2211 2212 2213
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2214
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2215 2216
                  _("Could not set memory to %lu kilobytes: %s"), memory,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2217
        goto cleanup;
2218 2219
    }

M
Matthias Bolte 已提交
2220 2221
    result = 0;

2222 2223 2224 2225
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2226
    VIR_FREE(taskInfoErrorMessage);
2227 2228 2229 2230 2231 2232

    return result;
}



2233 2234 2235 2236 2237 2238 2239 2240 2241
/*
 * 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

2242 2243 2244
static int
esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
M
Matthias Bolte 已提交
2245
    int result = -1;
M
Matthias Bolte 已提交
2246
    esxPrivate *priv = domain->conn->privateData;
2247 2248 2249 2250 2251
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int64_t memory_limit = -1;
2252
#if ESX_QUERY_FOR_USED_CPU_TIME
2253 2254 2255 2256 2257 2258 2259
    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;
2260 2261
    esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
    esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2262 2263 2264
    esxVI_PerfEntityMetric *perfEntityMetric = NULL;
    esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
    esxVI_Long *value = NULL;
2265
#endif
2266

M
Matthias Bolte 已提交
2267 2268
    memset(info, 0, sizeof (*info));

2269
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2270
        return -1;
2271 2272
    }

2273
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2274 2275 2276 2277
                                           "runtime.powerState\0"
                                           "config.hardware.memoryMB\0"
                                           "config.hardware.numCPU\0"
                                           "config.memoryAllocation.limit\0") < 0 ||
2278
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2279
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
2280
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2281
        goto cleanup;
2282 2283 2284 2285 2286 2287 2288 2289
    }

    info->state = VIR_DOMAIN_NOSTATE;

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

2294 2295
            info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
                            (powerState);
2296
        } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2297
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2298
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2299
                goto cleanup;
2300 2301 2302 2303
            }

            info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
        } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2304
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2305
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2306
                goto cleanup;
2307 2308 2309 2310 2311
            }

            info->nrVirtCpu = dynamicProperty->val->int32;
        } else if (STREQ(dynamicProperty->name,
                         "config.memoryAllocation.limit")) {
2312
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2313
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
2314
                goto cleanup;
2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329
            }

            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;

2330
#if ESX_QUERY_FOR_USED_CPU_TIME
2331
    /* Verify the cached 'used CPU time' performance counter ID */
2332 2333 2334 2335 2336 2337
    /* 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;
            }
2338

2339
            counterId->value = priv->usedCpuTimeCounterId;
2340

2341 2342 2343
            if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                goto cleanup;
            }
2344

2345 2346 2347 2348
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfo) < 0) {
                goto cleanup;
            }
2349

2350 2351 2352 2353 2354
            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);
2355

2356 2357 2358 2359 2360
                priv->usedCpuTimeCounterId = -1;
            }

            esxVI_Int_Free(&counterIdList);
            esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2361 2362
        }

2363 2364 2365 2366 2367 2368 2369 2370 2371 2372
        /*
         * 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;
            }
2373

2374 2375 2376 2377
            for (perfMetricId = perfMetricIdList; perfMetricId != NULL;
                 perfMetricId = perfMetricId->_next) {
                VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
                          perfMetricId->counterId->value, perfMetricId->instance);
2378

2379
                counterId = NULL;
2380

2381 2382 2383 2384 2385
                if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
                    esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
                    goto cleanup;
                }
            }
2386

2387 2388
            if (esxVI_QueryPerfCounter(priv->host, counterIdList,
                                       &perfCounterInfoList) < 0) {
M
Matthias Bolte 已提交
2389
                goto cleanup;
2390 2391
            }

2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408
            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;
                }
2409 2410
            }

2411
            if (priv->usedCpuTimeCounterId < 0) {
2412
                VIR_WARN("Could not find 'used CPU time' performance counter");
2413
            }
2414 2415
        }

2416 2417 2418 2419 2420 2421
        /*
         * 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);
2422

2423 2424 2425 2426 2427 2428
            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;
            }
2429

2430 2431 2432 2433 2434 2435 2436 2437 2438 2439
            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;
            }
2440

2441 2442 2443
            for (perfEntityMetricBase = perfEntityMetricBaseList;
                 perfEntityMetricBase != NULL;
                 perfEntityMetricBase = perfEntityMetricBase->_next) {
2444
                VIR_DEBUG("perfEntityMetric ...");
2445

2446 2447
                perfEntityMetric =
                  esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2448

2449
                if (perfEntityMetric == NULL) {
2450 2451
                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                              _("QueryPerf returned object with unexpected type '%s'"),
2452
                              esxVI_Type_ToString(perfEntityMetricBase->_type));
2453
                    goto cleanup;
2454
                }
2455

2456 2457
                perfMetricIntSeries =
                  esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2458

2459
                if (perfMetricIntSeries == NULL) {
2460 2461
                    ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                              _("QueryPerf returned object with unexpected type '%s'"),
2462
                              esxVI_Type_ToString(perfEntityMetric->value->_type));
2463
                    goto cleanup;
2464
                }
2465

2466 2467
                for (; perfMetricIntSeries != NULL;
                     perfMetricIntSeries = perfMetricIntSeries->_next) {
2468
                    VIR_DEBUG("perfMetricIntSeries ...");
2469

2470 2471 2472 2473 2474
                    for (value = perfMetricIntSeries->value;
                         value != NULL;
                         value = value->_next) {
                        VIR_DEBUG("value %lld", (long long int)value->value);
                    }
2475 2476 2477
                }
            }

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

2480
            /*
E
Eric Blake 已提交
2481
             * FIXME: Cannot map between relative used-cpu-time and absolute
2482 2483 2484
             *        info->cpuTime
             */
        }
2485
    }
2486
#endif
2487

M
Matthias Bolte 已提交
2488 2489
    result = 0;

2490
  cleanup:
2491
#if ESX_QUERY_FOR_USED_CPU_TIME
2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
    /*
     * 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;
        }
    }
2504
#endif
2505

2506 2507
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2508
#if ESX_QUERY_FOR_USED_CPU_TIME
2509 2510 2511 2512
    esxVI_PerfMetricId_Free(&perfMetricIdList);
    esxVI_Int_Free(&counterIdList);
    esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
    esxVI_PerfQuerySpec_Free(&querySpec);
2513
    esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2514
#endif
2515 2516 2517 2518 2519 2520

    return result;
}



2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
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;
}



2564
static int
2565 2566
esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
                       unsigned int flags)
2567
{
M
Matthias Bolte 已提交
2568
    int result = -1;
M
Matthias Bolte 已提交
2569
    esxPrivate *priv = domain->conn->privateData;
M
Matthias Bolte 已提交
2570
    int maxVcpus;
2571 2572 2573 2574
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
2575
    char *taskInfoErrorMessage = NULL;
2576

2577
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2578 2579 2580 2581
        ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

2582
    if (nvcpus < 1) {
2583 2584
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Requested number of virtual CPUs must at least be 1"));
M
Matthias Bolte 已提交
2585
        return -1;
2586 2587
    }

2588
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2589
        return -1;
2590 2591
    }

M
Matthias Bolte 已提交
2592
    maxVcpus = esxDomainGetMaxVcpus(domain);
2593

M
Matthias Bolte 已提交
2594
    if (maxVcpus < 0) {
M
Matthias Bolte 已提交
2595
        return -1;
2596 2597
    }

M
Matthias Bolte 已提交
2598
    if (nvcpus > maxVcpus) {
2599
        ESX_ERROR(VIR_ERR_INVALID_ARG,
2600 2601
                  _("Requested number of virtual CPUs is greater than max "
                    "allowable number of virtual CPUs for the domain: %d > %d"),
M
Matthias Bolte 已提交
2602
                  nvcpus, maxVcpus);
M
Matthias Bolte 已提交
2603
        return -1;
2604 2605
    }

2606
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2607
          (priv->primary, domain->uuid, NULL, &virtualMachine,
2608
           priv->parsedUri->autoAnswer) < 0 ||
2609 2610
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_Int_Alloc(&spec->numCPUs) < 0) {
M
Matthias Bolte 已提交
2611
        goto cleanup;
2612 2613 2614 2615
    }

    spec->numCPUs->value = nvcpus;

2616
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2617
                              &task) < 0 ||
2618
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2619
                                    esxVI_Occurrence_RequiredItem,
2620
                                    priv->parsedUri->autoAnswer, &taskInfoState,
2621
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
2622
        goto cleanup;
2623 2624 2625
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
2626
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
2627 2628
                  _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
2629
        goto cleanup;
2630 2631
    }

M
Matthias Bolte 已提交
2632 2633
    result = 0;

2634 2635 2636 2637
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
2638
    VIR_FREE(taskInfoErrorMessage);
2639 2640 2641 2642 2643

    return result;
}


M
Matthias Bolte 已提交
2644

2645 2646 2647
static int
esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
{
2648
    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2649 2650
}

2651

M
Matthias Bolte 已提交
2652

2653
static int
2654
esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2655
{
M
Matthias Bolte 已提交
2656
    esxPrivate *priv = domain->conn->privateData;
2657 2658 2659 2660
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *hostSystem = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;

2661
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2662 2663 2664 2665
        ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

M
Matthias Bolte 已提交
2666 2667
    if (priv->maxVcpus > 0) {
        return priv->maxVcpus;
2668 2669
    }

M
Matthias Bolte 已提交
2670 2671
    priv->maxVcpus = -1;

2672
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2673
        return -1;
2674 2675
    }

2676
    if (esxVI_String_AppendValueToList(&propertyNameList,
2677
                                       "capability.maxSupportedVcpus") < 0 ||
2678 2679
        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
                                         &hostSystem) < 0) {
M
Matthias Bolte 已提交
2680
        goto cleanup;
2681 2682 2683
    }

    if (hostSystem == NULL) {
2684 2685
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve the HostSystem object"));
M
Matthias Bolte 已提交
2686
        goto cleanup;
2687 2688 2689 2690 2691
    }

    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2692
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2693
                                         esxVI_Type_Int) < 0) {
M
Matthias Bolte 已提交
2694
                goto cleanup;
2695 2696
            }

M
Matthias Bolte 已提交
2697
            priv->maxVcpus = dynamicProperty->val->int32;
2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
            break;
        } else {
            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
        }
    }

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

M
Matthias Bolte 已提交
2708
    return priv->maxVcpus;
2709 2710
}

M
Matthias Bolte 已提交
2711 2712


2713 2714 2715
static int
esxDomainGetMaxVcpus(virDomainPtr domain)
{
2716
    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2717 2718
                                           VIR_DOMAIN_VCPU_MAXIMUM));
}
2719

M
Matthias Bolte 已提交
2720 2721


2722
static char *
2723
esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2724
{
M
Matthias Bolte 已提交
2725
    esxPrivate *priv = domain->conn->privateData;
2726 2727
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
2728 2729
    esxVI_VirtualMachinePowerState powerState;
    int id;
2730
    char *vmPathName = NULL;
2731
    char *datastoreName = NULL;
M
Matthias Bolte 已提交
2732
    char *directoryName = NULL;
2733
    char *directoryAndFileName = NULL;
2734
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2735 2736
    char *url = NULL;
    char *vmx = NULL;
2737
    virVMXContext ctx;
2738
    esxVMX_Data data;
2739 2740 2741
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2742 2743
    /* Flags checked by virDomainDefFormat */

2744 2745
    memset(&data, 0, sizeof (data));

2746
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2747
        return NULL;
2748 2749
    }

2750 2751 2752
    if (esxVI_String_AppendValueListToList(&propertyNameList,
                                           "config.files.vmPathName\0"
                                           "runtime.powerState\0") < 0 ||
2753
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2754
                                         propertyNameList, &virtualMachine,
2755
                                         esxVI_Occurrence_RequiredItem) < 0 ||
2756 2757
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2758 2759
        esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
                             &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
2760
        goto cleanup;
2761 2762
    }

2763
    if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2764
                                   &directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
2765
        goto cleanup;
2766 2767
    }

2768
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2769
                      domain->conn->uri->server, domain->conn->uri->port);
2770
    virBufferURIEncodeString(&buffer, directoryAndFileName);
2771
    virBufferAddLit(&buffer, "?dcPath=");
2772
    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
2773 2774 2775 2776
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
2777
        virReportOOMError();
M
Matthias Bolte 已提交
2778
        goto cleanup;
2779 2780
    }

2781 2782
    url = virBufferContentAndReset(&buffer);

2783
    if (esxVI_CURL_Download(priv->primary->curl, url, &vmx) < 0) {
M
Matthias Bolte 已提交
2784
        goto cleanup;
2785 2786
    }

2787
    data.ctx = priv->primary;
2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801

    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;
        }
    }
2802 2803 2804 2805 2806 2807

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

2808
    def = virVMXParseConfig(&ctx, priv->caps, vmx);
2809 2810

    if (def != NULL) {
2811 2812 2813 2814
        if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
            def->id = id;
        }

2815
        xml = virDomainDefFormat(def, flags);
2816 2817 2818
    }

  cleanup:
M
Matthias Bolte 已提交
2819 2820 2821 2822
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

2823 2824
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachine);
2825
    VIR_FREE(datastoreName);
M
Matthias Bolte 已提交
2826
    VIR_FREE(directoryName);
2827
    VIR_FREE(directoryAndFileName);
2828
    VIR_FREE(url);
2829
    VIR_FREE(data.datastorePathWithoutFileName);
2830
    VIR_FREE(vmx);
2831
    virDomainDefFree(def);
2832 2833 2834 2835 2836 2837 2838 2839 2840

    return xml;
}



static char *
esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
                       const char *nativeConfig,
E
Eric Blake 已提交
2841
                       unsigned int flags)
2842
{
M
Matthias Bolte 已提交
2843
    esxPrivate *priv = conn->privateData;
2844
    virVMXContext ctx;
2845
    esxVMX_Data data;
2846 2847 2848
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2849 2850
    virCheckFlags(0, NULL);

2851 2852
    memset(&data, 0, sizeof (data));

2853
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2854
        ESX_ERROR(VIR_ERR_INVALID_ARG,
2855
                  _("Unsupported config format '%s'"), nativeFormat);
2856
        return NULL;
2857 2858
    }

2859
    data.ctx = priv->primary;
2860
    data.datastorePathWithoutFileName = (char *)"[?] ?";
2861 2862 2863 2864 2865 2866

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

2867
    def = virVMXParseConfig(&ctx, priv->caps, nativeConfig);
2868 2869

    if (def != NULL) {
2870
        xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
2871 2872 2873 2874 2875 2876 2877 2878 2879
    }

    virDomainDefFree(def);

    return xml;
}



M
Matthias Bolte 已提交
2880 2881 2882
static char *
esxDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
                     const char *domainXml,
E
Eric Blake 已提交
2883
                     unsigned int flags)
M
Matthias Bolte 已提交
2884
{
M
Matthias Bolte 已提交
2885
    esxPrivate *priv = conn->privateData;
2886 2887
    int virtualHW_version;
    virVMXContext ctx;
2888
    esxVMX_Data data;
M
Matthias Bolte 已提交
2889 2890 2891
    virDomainDefPtr def = NULL;
    char *vmx = NULL;

E
Eric Blake 已提交
2892 2893
    virCheckFlags(0, NULL);

2894 2895
    memset(&data, 0, sizeof (data));

M
Matthias Bolte 已提交
2896
    if (STRNEQ(nativeFormat, "vmware-vmx")) {
2897
        ESX_ERROR(VIR_ERR_INVALID_ARG,
2898
                  _("Unsupported config format '%s'"), nativeFormat);
M
Matthias Bolte 已提交
2899 2900 2901
        return NULL;
    }

2902 2903 2904 2905 2906 2907 2908
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        return NULL;
    }

M
Matthias Bolte 已提交
2909 2910
    def = virDomainDefParseString(priv->caps, domainXml,
                                  1 << VIR_DOMAIN_VIRT_VMWARE, 0);
M
Matthias Bolte 已提交
2911 2912 2913 2914 2915

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

2916
    data.ctx = priv->primary;
2917
    data.datastorePathWithoutFileName = NULL;
2918 2919 2920 2921 2922 2923

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

2924
    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
M
Matthias Bolte 已提交
2925 2926 2927 2928 2929 2930 2931 2932

    virDomainDefFree(def);

    return vmx;
}



2933 2934 2935
static int
esxListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
{
M
Matthias Bolte 已提交
2936
    bool success = false;
M
Matthias Bolte 已提交
2937
    esxPrivate *priv = conn->privateData;
2938 2939 2940 2941 2942
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachineList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachinePowerState powerState;
    int count = 0;
2943
    int i;
2944 2945 2946 2947 2948

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

2949
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
2950
        return -1;
2951 2952
    }

2953
    if (esxVI_String_AppendValueListToList(&propertyNameList,
2954 2955
                                           "name\0"
                                           "runtime.powerState\0") < 0 ||
2956 2957
        esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
                                       &virtualMachineList) < 0) {
M
Matthias Bolte 已提交
2958
        goto cleanup;
2959 2960 2961 2962
    }

    for (virtualMachine = virtualMachineList; virtualMachine != NULL;
         virtualMachine = virtualMachine->_next) {
2963
        if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2964
                                              &powerState) < 0) {
M
Matthias Bolte 已提交
2965
            goto cleanup;
2966 2967 2968 2969 2970 2971
        }

        if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) {
            continue;
        }

2972
        names[count] = NULL;
2973

2974 2975 2976
        if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
                                            NULL) < 0) {
            goto cleanup;
2977 2978
        }

2979 2980
        ++count;

2981 2982 2983 2984 2985
        if (count >= maxnames) {
            break;
        }
    }

M
Matthias Bolte 已提交
2986
    success = true;
2987

M
Matthias Bolte 已提交
2988 2989 2990 2991 2992
  cleanup:
    if (! success) {
        for (i = 0; i < count; ++i) {
            VIR_FREE(names[i]);
        }
2993

M
Matthias Bolte 已提交
2994
        count = -1;
2995 2996
    }

M
Matthias Bolte 已提交
2997 2998
    esxVI_String_Free(&propertyNameList);
    esxVI_ObjectContent_Free(&virtualMachineList);
2999

M
Matthias Bolte 已提交
3000
    return count;
3001 3002 3003 3004 3005 3006 3007
}



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

3010
    if (esxVI_EnsureSession(priv->primary) < 0) {
3011 3012 3013
        return -1;
    }

3014
    return esxVI_LookupNumberOfDomainsByPowerState
3015
             (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
3016 3017 3018 3019 3020
}



static int
3021
esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
3022
{
M
Matthias Bolte 已提交
3023
    int result = -1;
M
Matthias Bolte 已提交
3024
    esxPrivate *priv = domain->conn->privateData;
3025 3026 3027
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;
3028
    int id = -1;
3029 3030
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3031
    char *taskInfoErrorMessage = NULL;
3032

3033 3034
    virCheckFlags(0, -1);

3035
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3036
        return -1;
3037 3038
    }

3039
    if (esxVI_String_AppendValueToList(&propertyNameList,
3040
                                       "runtime.powerState") < 0 ||
3041
        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3042
          (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
3043
           priv->parsedUri->autoAnswer) < 0 ||
3044 3045
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
        esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
M
Matthias Bolte 已提交
3046
        goto cleanup;
3047 3048 3049
    }

    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3050 3051
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not powered off"));
M
Matthias Bolte 已提交
3052
        goto cleanup;
3053 3054
    }

3055
    if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
3056
                             &task) < 0 ||
3057
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3058
                                    esxVI_Occurrence_RequiredItem,
3059
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3060
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3061
        goto cleanup;
3062 3063 3064
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3065 3066
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3067
        goto cleanup;
3068 3069
    }

3070
    domain->id = id;
M
Matthias Bolte 已提交
3071 3072
    result = 0;

3073 3074 3075 3076
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);
    esxVI_ManagedObjectReference_Free(&task);
3077
    VIR_FREE(taskInfoErrorMessage);
3078 3079 3080 3081

    return result;
}

3082 3083


3084 3085 3086 3087 3088
static int
esxDomainCreate(virDomainPtr domain)
{
    return esxDomainCreateWithFlags(domain, 0);
}
3089

3090 3091


M
Matthias Bolte 已提交
3092
static virDomainPtr
3093
esxDomainDefineXML(virConnectPtr conn, const char *xml)
M
Matthias Bolte 已提交
3094
{
M
Matthias Bolte 已提交
3095
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
3096 3097
    virDomainDefPtr def = NULL;
    char *vmx = NULL;
3098 3099
    int i;
    virDomainDiskDefPtr disk = NULL;
M
Matthias Bolte 已提交
3100
    esxVI_ObjectContent *virtualMachine = NULL;
3101 3102
    int virtualHW_version;
    virVMXContext ctx;
3103
    esxVMX_Data data;
M
Matthias Bolte 已提交
3104 3105
    char *datastoreName = NULL;
    char *directoryName = NULL;
3106
    char *escapedName = NULL;
M
Matthias Bolte 已提交
3107 3108 3109 3110 3111 3112 3113 3114
    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;
3115
    char *taskInfoErrorMessage = NULL;
M
Matthias Bolte 已提交
3116 3117
    virDomainPtr domain = NULL;

3118 3119
    memset(&data, 0, sizeof (data));

3120
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3121
        return NULL;
M
Matthias Bolte 已提交
3122 3123 3124
    }

    /* Parse domain XML */
M
Matthias Bolte 已提交
3125
    def = virDomainDefParseString(priv->caps, xml, 1 << VIR_DOMAIN_VIRT_VMWARE,
M
Matthias Bolte 已提交
3126 3127 3128
                                  VIR_DOMAIN_XML_INACTIVE);

    if (def == NULL) {
M
Matthias Bolte 已提交
3129
        return NULL;
M
Matthias Bolte 已提交
3130 3131 3132
    }

    /* Check if an existing domain should be edited */
3133
    if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
M
Matthias Bolte 已提交
3134
                                         &virtualMachine,
M
Matthias Bolte 已提交
3135
                                         esxVI_Occurrence_OptionalItem) < 0) {
M
Matthias Bolte 已提交
3136
        goto cleanup;
M
Matthias Bolte 已提交
3137 3138
    }

3139 3140 3141 3142 3143 3144 3145
    if (virtualMachine == NULL &&
        esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
                                         &virtualMachine,
                                         esxVI_Occurrence_OptionalItem) < 0) {
        goto cleanup;
    }

M
Matthias Bolte 已提交
3146 3147
    if (virtualMachine != NULL) {
        /* FIXME */
3148 3149 3150
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Domain already exists, editing existing domains is not "
                    "supported yet"));
M
Matthias Bolte 已提交
3151
        goto cleanup;
M
Matthias Bolte 已提交
3152 3153 3154
    }

    /* Build VMX from domain XML */
3155 3156 3157 3158 3159 3160 3161
    virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
                          (priv->primary->productVersion);

    if (virtualHW_version < 0) {
        goto cleanup;
    }

3162
    data.ctx = priv->primary;
3163
    data.datastorePathWithoutFileName = NULL;
3164 3165 3166 3167 3168 3169

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

3170
    vmx = virVMXFormatConfig(&ctx, priv->caps, def, virtualHW_version);
M
Matthias Bolte 已提交
3171 3172

    if (vmx == NULL) {
M
Matthias Bolte 已提交
3173
        goto cleanup;
M
Matthias Bolte 已提交
3174 3175
    }

3176 3177 3178 3179 3180 3181 3182
    /*
     * 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 已提交
3183
    if (def->ndisks < 1) {
3184 3185 3186
        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 已提交
3187
        goto cleanup;
3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198
    }

    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) {
3199 3200 3201
        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 已提交
3202
        goto cleanup;
M
Matthias Bolte 已提交
3203 3204
    }

3205
    if (disk->src == NULL) {
3206 3207 3208
        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 已提交
3209
        goto cleanup;
M
Matthias Bolte 已提交
3210 3211
    }

3212
    if (esxUtil_ParseDatastorePath(disk->src, &datastoreName, &directoryName,
3213
                                   NULL) < 0) {
M
Matthias Bolte 已提交
3214
        goto cleanup;
M
Matthias Bolte 已提交
3215 3216
    }

3217
    if (! virFileHasSuffix(disk->src, ".vmdk")) {
3218
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3219 3220
                  _("Expecting source '%s' of first file-based harddisk to "
                    "be a VMDK image"), disk->src);
M
Matthias Bolte 已提交
3221
        goto cleanup;
M
Matthias Bolte 已提交
3222 3223
    }

3224
    virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
M
Matthias Bolte 已提交
3225 3226 3227 3228 3229 3230 3231
                      conn->uri->server, conn->uri->port);

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

3232 3233 3234 3235 3236 3237 3238
    escapedName = esxUtil_EscapeDatastoreItem(def->name);

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

    virBufferURIEncodeString(&buffer, escapedName);
M
Matthias Bolte 已提交
3239
    virBufferAddLit(&buffer, ".vmx?dcPath=");
3240
    virBufferURIEncodeString(&buffer, priv->primary->datacenter->name);
M
Matthias Bolte 已提交
3241 3242 3243 3244
    virBufferAddLit(&buffer, "&dsName=");
    virBufferURIEncodeString(&buffer, datastoreName);

    if (virBufferError(&buffer)) {
3245
        virReportOOMError();
M
Matthias Bolte 已提交
3246
        goto cleanup;
M
Matthias Bolte 已提交
3247 3248 3249 3250
    }

    url = virBufferContentAndReset(&buffer);

3251 3252 3253 3254 3255 3256
    /* Check, if VMX file already exists */
    /* FIXME */

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

3257
    if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0) {
3258 3259 3260 3261
        goto cleanup;
    }

    /* Register the domain */
M
Matthias Bolte 已提交
3262 3263
    if (directoryName != NULL) {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s/%s.vmx", datastoreName,
3264
                        directoryName, escapedName) < 0) {
3265
            virReportOOMError();
M
Matthias Bolte 已提交
3266
            goto cleanup;
M
Matthias Bolte 已提交
3267 3268 3269
        }
    } else {
        if (virAsprintf(&datastoreRelatedPath, "[%s] %s.vmx", datastoreName,
3270
                        escapedName) < 0) {
3271
            virReportOOMError();
M
Matthias Bolte 已提交
3272
            goto cleanup;
M
Matthias Bolte 已提交
3273 3274 3275
        }
    }

3276
    if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
M
Matthias Bolte 已提交
3277
                              datastoreRelatedPath, NULL, esxVI_Boolean_False,
3278 3279 3280 3281
                              priv->primary->computeResource->resourcePool,
                              priv->primary->hostSystem->_reference,
                              &task) < 0 ||
        esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3282
                                    esxVI_Occurrence_OptionalItem,
3283
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3284
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3285
        goto cleanup;
M
Matthias Bolte 已提交
3286 3287 3288
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3289 3290
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3291
        goto cleanup;
M
Matthias Bolte 已提交
3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302
    }

    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 已提交
3303 3304 3305 3306
    if (url == NULL) {
        virBufferFreeAndReset(&buffer);
    }

M
Matthias Bolte 已提交
3307 3308 3309 3310
    virDomainDefFree(def);
    VIR_FREE(vmx);
    VIR_FREE(datastoreName);
    VIR_FREE(directoryName);
3311
    VIR_FREE(escapedName);
M
Matthias Bolte 已提交
3312 3313 3314 3315 3316 3317 3318
    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);
3319
    VIR_FREE(taskInfoErrorMessage);
M
Matthias Bolte 已提交
3320 3321 3322 3323 3324 3325

    return domain;
}



3326
static int
3327 3328
esxDomainUndefineFlags(virDomainPtr domain,
                       unsigned int flags)
3329
{
M
Matthias Bolte 已提交
3330
    int result = -1;
M
Matthias Bolte 已提交
3331
    esxPrivate *priv = domain->conn->privateData;
3332
    esxVI_Context *ctx = NULL;
3333 3334 3335 3336
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

3337 3338 3339 3340
    /* No managed save, so we explicitly reject
     * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
     * ESX, so we can trivially ignore that flag.  */
    virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
3341

3342 3343 3344 3345 3346 3347
    if (priv->vCenter != NULL) {
        ctx = priv->vCenter;
    } else {
        ctx = priv->host;
    }

3348
    if (esxVI_EnsureSession(ctx) < 0) {
M
Matthias Bolte 已提交
3349
        return -1;
3350 3351
    }

3352
    if (esxVI_String_AppendValueToList(&propertyNameList,
3353
                                       "runtime.powerState") < 0 ||
3354 3355
        esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
                                         &virtualMachine,
M
Matthias Bolte 已提交
3356
                                         esxVI_Occurrence_RequiredItem) < 0 ||
3357
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
3358
        goto cleanup;
3359 3360 3361 3362
    }

    if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
        powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3363 3364
        ESX_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
                  _("Domain is not suspended or powered off"));
M
Matthias Bolte 已提交
3365
        goto cleanup;
3366 3367
    }

3368
    if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0) {
M
Matthias Bolte 已提交
3369
        goto cleanup;
3370 3371
    }

M
Matthias Bolte 已提交
3372 3373
    result = 0;

3374 3375 3376 3377 3378 3379 3380 3381
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_String_Free(&propertyNameList);

    return result;
}


3382 3383 3384 3385 3386
static int
esxDomainUndefine(virDomainPtr domain)
{
    return esxDomainUndefineFlags(domain, 0);
}
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 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566
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;
}



3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
/*
 * 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:
 *
3577
 * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3578
 *
3579
 *   The amount of CPU resource that is guaranteed to be available to the domain.
3580 3581
 *
 *
3582
 * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3583
 *
3584 3585
 *   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
3586 3587 3588 3589
 *   utilization of the domain is unlimited. If the limit is not set to -1, it
 *   must be greater than or equal to the reservation.
 *
 *
3590
 * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3591 3592 3593 3594 3595 3596
 *
 *   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'.
 */
3597
static char *
3598
esxDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams)
3599 3600 3601 3602
{
    char *type = strdup("allocation");

    if (type == NULL) {
3603
        virReportOOMError();
3604
        return NULL;
3605 3606
    }

3607 3608 3609
    if (nparams != NULL) {
        *nparams = 3; /* reservation, limit, shares */
    }
3610 3611 3612 3613 3614 3615 3616

    return type;
}



static int
3617 3618 3619
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int *nparams,
                                     unsigned int flags)
3620
{
M
Matthias Bolte 已提交
3621
    int result = -1;
M
Matthias Bolte 已提交
3622
    esxPrivate *priv = domain->conn->privateData;
3623 3624 3625 3626 3627 3628 3629
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    unsigned int mask = 0;
    int i = 0;

3630 3631
    virCheckFlags(0, -1);

3632
    if (*nparams < 3) {
3633 3634
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Parameter array must have space for 3 items"));
M
Matthias Bolte 已提交
3635
        return -1;
3636 3637
    }

3638
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3639
        return -1;
3640 3641
    }

3642
    if (esxVI_String_AppendValueListToList(&propertyNameList,
3643 3644 3645
                                           "config.cpuAllocation.reservation\0"
                                           "config.cpuAllocation.limit\0"
                                           "config.cpuAllocation.shares\0") < 0 ||
3646
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3647
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
3648
                                         esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
3649
        goto cleanup;
3650 3651 3652 3653 3654 3655
    }

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

3660
            params[i].type = VIR_TYPED_PARAM_LLONG;
3661

3662
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3663
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3664
                goto cleanup;
3665 3666 3667 3668 3669 3670 3671
            }

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

3676
            params[i].type = VIR_TYPED_PARAM_LLONG;
3677

3678
            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3679
                                         esxVI_Type_Long) < 0) {
M
Matthias Bolte 已提交
3680
                goto cleanup;
3681 3682 3683 3684 3685 3686 3687
            }

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

3692
            params[i].type = VIR_TYPED_PARAM_INT;
3693

3694
            if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3695
                                                 &sharesInfo) < 0) {
M
Matthias Bolte 已提交
3696
                goto cleanup;
3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716
            }

            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:
3717
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
3718
                          _("Shares level has unknown value %d"),
3719
                          (int)sharesInfo->level);
M
Matthias Bolte 已提交
3720
                goto cleanup;
3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
            }

            esxVI_SharesInfo_Free(&sharesInfo);

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

    *nparams = i;
M
Matthias Bolte 已提交
3733
    result = 0;
3734 3735 3736 3737 3738 3739 3740 3741

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

    return result;
}

3742 3743 3744 3745 3746 3747
static int
esxDomainGetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int *nparams)
{
    return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
}
3748 3749 3750


static int
3751 3752 3753
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
                                     virTypedParameterPtr params, int nparams,
                                     unsigned int flags)
3754
{
M
Matthias Bolte 已提交
3755
    int result = -1;
M
Matthias Bolte 已提交
3756
    esxPrivate *priv = domain->conn->privateData;
3757 3758 3759 3760 3761
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineConfigSpec *spec = NULL;
    esxVI_SharesInfo *sharesInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3762
    char *taskInfoErrorMessage = NULL;
3763 3764
    int i;

3765 3766
    virCheckFlags(0, -1);

3767
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
3768
        return -1;
3769 3770
    }

3771
    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3772
          (priv->primary, domain->uuid, NULL, &virtualMachine,
3773
           priv->parsedUri->autoAnswer) < 0 ||
3774 3775
        esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
        esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
M
Matthias Bolte 已提交
3776
        goto cleanup;
3777 3778 3779 3780
    }

    for (i = 0; i < nparams; ++i) {
        if (STREQ (params[i].field, "reservation") &&
3781
            params[i].type == VIR_TYPED_PARAM_LLONG) {
3782
            if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0) {
M
Matthias Bolte 已提交
3783
                goto cleanup;
3784 3785 3786
            }

            if (params[i].value.l < 0) {
3787
                ESX_ERROR(VIR_ERR_INVALID_ARG,
3788 3789
                          _("Could not set reservation to %lld MHz, expecting "
                            "positive value"), params[i].value.l);
M
Matthias Bolte 已提交
3790
                goto cleanup;
3791 3792 3793 3794
            }

            spec->cpuAllocation->reservation->value = params[i].value.l;
        } else if (STREQ (params[i].field, "limit") &&
3795
                   params[i].type == VIR_TYPED_PARAM_LLONG) {
3796
            if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0) {
M
Matthias Bolte 已提交
3797
                goto cleanup;
3798 3799 3800
            }

            if (params[i].value.l < -1) {
3801
                ESX_ERROR(VIR_ERR_INVALID_ARG,
3802 3803
                          _("Could not set limit to %lld MHz, expecting "
                            "positive value or -1 (unlimited)"),
3804
                          params[i].value.l);
M
Matthias Bolte 已提交
3805
                goto cleanup;
3806 3807 3808 3809
            }

            spec->cpuAllocation->limit->value = params[i].value.l;
        } else if (STREQ (params[i].field, "shares") &&
3810
                   params[i].type == VIR_TYPED_PARAM_INT) {
3811 3812
            if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
                esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
M
Matthias Bolte 已提交
3813
                goto cleanup;
3814 3815 3816 3817
            }

            spec->cpuAllocation->shares = sharesInfo;

3818
            if (params[i].value.i >= 0) {
3819
                spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3820
                spec->cpuAllocation->shares->shares->value = params[i].value.i;
3821
            } else {
3822
                switch (params[i].value.i) {
3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840
                  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:
3841
                    ESX_ERROR(VIR_ERR_INVALID_ARG,
3842 3843
                              _("Could not set shares to %d, expecting positive "
                                "value or -1 (low), -2 (normal) or -3 (high)"),
3844
                              params[i].value.i);
M
Matthias Bolte 已提交
3845
                    goto cleanup;
3846 3847 3848
                }
            }
        } else {
3849
            ESX_ERROR(VIR_ERR_INVALID_ARG, _("Unknown field '%s'"),
3850
                      params[i].field);
M
Matthias Bolte 已提交
3851
            goto cleanup;
3852 3853 3854
        }
    }

3855
    if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3856
                              &task) < 0 ||
3857
        esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3858
                                    esxVI_Occurrence_RequiredItem,
3859
                                    priv->parsedUri->autoAnswer, &taskInfoState,
3860
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
3861
        goto cleanup;
3862 3863 3864
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
3865 3866 3867
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not change scheduler parameters: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
3868
        goto cleanup;
3869 3870
    }

M
Matthias Bolte 已提交
3871 3872
    result = 0;

3873 3874 3875 3876
  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
3877
    VIR_FREE(taskInfoErrorMessage);
3878 3879 3880 3881

    return result;
}

3882 3883 3884 3885 3886 3887
static int
esxDomainSetSchedulerParameters(virDomainPtr domain,
                                virTypedParameterPtr params, int nparams)
{
    return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
}
3888

E
Eric Blake 已提交
3889 3890 3891 3892 3893 3894
/* The subset of migration flags we are able to support.  */
#define ESX_MIGRATION_FLAGS                     \
    (VIR_MIGRATE_PERSIST_DEST |                 \
     VIR_MIGRATE_UNDEFINE_SOURCE |              \
     VIR_MIGRATE_LIVE |                         \
     VIR_MIGRATE_PAUSED)
3895 3896 3897 3898 3899

static int
esxDomainMigratePrepare(virConnectPtr dconn,
                        char **cookie ATTRIBUTE_UNUSED,
                        int *cookielen ATTRIBUTE_UNUSED,
3900 3901
                        const char *uri_in ATTRIBUTE_UNUSED,
                        char **uri_out,
E
Eric Blake 已提交
3902
                        unsigned long flags,
3903 3904 3905
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
3906
    esxPrivate *priv = dconn->privateData;
3907

E
Eric Blake 已提交
3908 3909
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

3910
    if (uri_in == NULL) {
3911 3912 3913 3914
        if (virAsprintf(uri_out, "vpxmigr://%s/%s/%s",
                        priv->vCenter->ipAddress,
                        priv->vCenter->computeResource->resourcePool->value,
                        priv->vCenter->hostSystem->_reference->value) < 0) {
3915
            virReportOOMError();
3916
            return -1;
3917 3918 3919
        }
    }

3920
    return 0;
3921 3922 3923 3924 3925 3926 3927 3928 3929
}



static int
esxDomainMigratePerform(virDomainPtr domain,
                        const char *cookie ATTRIBUTE_UNUSED,
                        int cookielen ATTRIBUTE_UNUSED,
                        const char *uri,
E
Eric Blake 已提交
3930
                        unsigned long flags,
3931 3932 3933
                        const char *dname,
                        unsigned long bandwidth ATTRIBUTE_UNUSED)
{
M
Matthias Bolte 已提交
3934
    int result = -1;
M
Matthias Bolte 已提交
3935
    esxPrivate *priv = domain->conn->privateData;
3936 3937 3938 3939
    xmlURIPtr parsedUri = NULL;
    char *saveptr;
    char *path_resourcePool;
    char *path_hostSystem;
3940
    esxVI_ObjectContent *virtualMachine = NULL;
3941 3942
    esxVI_ManagedObjectReference resourcePool;
    esxVI_ManagedObjectReference hostSystem;
3943 3944 3945
    esxVI_Event *eventList = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
3946
    char *taskInfoErrorMessage = NULL;
3947

E
Eric Blake 已提交
3948 3949
    virCheckFlags(ESX_MIGRATION_FLAGS, -1);

M
Matthias Bolte 已提交
3950
    if (priv->vCenter == NULL) {
3951 3952
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Migration not possible without a vCenter"));
M
Matthias Bolte 已提交
3953
        return -1;
3954 3955 3956
    }

    if (dname != NULL) {
3957 3958
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Renaming domains on migration not supported"));
M
Matthias Bolte 已提交
3959
        return -1;
3960 3961
    }

3962
    if (esxVI_EnsureSession(priv->vCenter) < 0) {
M
Matthias Bolte 已提交
3963
        return -1;
3964 3965
    }

3966 3967
    /* Parse migration URI */
    parsedUri = xmlParseURI(uri);
3968

3969
    if (parsedUri == NULL) {
3970
        virReportOOMError();
M
Matthias Bolte 已提交
3971
        return -1;
3972 3973
    }

3974 3975 3976
    if (parsedUri->scheme == NULL || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                  _("Only vpxmigr:// migration URIs are supported"));
M
Matthias Bolte 已提交
3977
        goto cleanup;
3978 3979
    }

3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992
    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 已提交
3993
        goto cleanup;
3994 3995
    }

3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008
    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,
4009
           priv->parsedUri->autoAnswer) < 0) {
M
Matthias Bolte 已提交
4010
        goto cleanup;
4011 4012 4013
    }

    /* Validate the purposed migration */
4014
    if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
4015 4016
                                esxVI_VirtualMachinePowerState_Undefined, NULL,
                                &resourcePool, &hostSystem, &eventList) < 0) {
M
Matthias Bolte 已提交
4017
        goto cleanup;
4018 4019 4020 4021 4022 4023 4024 4025
    }

    if (eventList != NULL) {
        /*
         * FIXME: Need to report the complete list of events. Limit reporting
         *        to the first event for now.
         */
        if (eventList->fullFormattedMessage != NULL) {
4026
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
4027 4028
                      _("Could not migrate domain, validation reported a "
                        "problem: %s"), eventList->fullFormattedMessage);
4029
        } else {
4030 4031 4032
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                      _("Could not migrate domain, validation reported a "
                        "problem"));
4033 4034
        }

M
Matthias Bolte 已提交
4035
        goto cleanup;
4036 4037 4038
    }

    /* Perform the purposed migration */
4039 4040
    if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
                             &resourcePool, &hostSystem,
4041 4042 4043
                             esxVI_VirtualMachineMovePriority_DefaultPriority,
                             esxVI_VirtualMachinePowerState_Undefined,
                             &task) < 0 ||
4044
        esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
4045
                                    esxVI_Occurrence_RequiredItem,
4046
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4047
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4048
        goto cleanup;
4049 4050 4051
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4052
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
4053
                  _("Could not migrate domain, migration task finished with "
4054 4055
                    "an error: %s"),
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
4056
        goto cleanup;
4057 4058
    }

M
Matthias Bolte 已提交
4059 4060
    result = 0;

4061
  cleanup:
4062
    xmlFreeURI(parsedUri);
4063 4064 4065
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_Event_Free(&eventList);
    esxVI_ManagedObjectReference_Free(&task);
4066
    VIR_FREE(taskInfoErrorMessage);
4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077

    return result;
}



static virDomainPtr
esxDomainMigrateFinish(virConnectPtr dconn, const char *dname,
                       const char *cookie ATTRIBUTE_UNUSED,
                       int cookielen ATTRIBUTE_UNUSED,
                       const char *uri ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
4078
                       unsigned long flags)
4079
{
E
Eric Blake 已提交
4080 4081
    virCheckFlags(ESX_MIGRATION_FLAGS, NULL);

4082 4083 4084 4085 4086
    return esxDomainLookupByName(dconn, dname);
}



M
Matthias Bolte 已提交
4087 4088 4089 4090
static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)
{
    unsigned long long result = 0;
M
Matthias Bolte 已提交
4091
    esxPrivate *priv = conn->privateData;
M
Matthias Bolte 已提交
4092 4093 4094 4095 4096
    esxVI_String *propertyNameList = NULL;
    esxVI_ObjectContent *resourcePool = NULL;
    esxVI_DynamicProperty *dynamicProperty = NULL;
    esxVI_ResourcePoolResourceUsage *resourcePoolResourceUsage = NULL;

4097
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4098
        return 0;
M
Matthias Bolte 已提交
4099 4100 4101
    }

    /* Get memory usage of resource pool */
4102
    if (esxVI_String_AppendValueToList(&propertyNameList,
M
Matthias Bolte 已提交
4103
                                       "runtime.memory") < 0 ||
4104 4105
        esxVI_LookupObjectContentByType(priv->primary,
                                        priv->primary->computeResource->resourcePool,
4106
                                        "ResourcePool", propertyNameList,
4107 4108
                                        &resourcePool,
                                        esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4109
        goto cleanup;
M
Matthias Bolte 已提交
4110 4111 4112 4113 4114 4115
    }

    for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
         dynamicProperty = dynamicProperty->_next) {
        if (STREQ(dynamicProperty->name, "runtime.memory")) {
            if (esxVI_ResourcePoolResourceUsage_CastFromAnyType
4116
                  (dynamicProperty->val, &resourcePoolResourceUsage) < 0) {
M
Matthias Bolte 已提交
4117
                goto cleanup;
M
Matthias Bolte 已提交
4118 4119 4120 4121 4122 4123 4124 4125 4126
            }

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

    if (resourcePoolResourceUsage == NULL) {
4127 4128
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Could not retrieve memory usage of resource pool"));
M
Matthias Bolte 已提交
4129
        goto cleanup;
M
Matthias Bolte 已提交
4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143
    }

    result = resourcePoolResourceUsage->unreservedForVm->value;

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

    return result;
}



4144 4145 4146
static int
esxIsEncrypted(virConnectPtr conn)
{
M
Matthias Bolte 已提交
4147
    esxPrivate *priv = conn->privateData;
4148

4149
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160
        return 1;
    } else {
        return 0;
    }
}



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

4163
    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174
        return 1;
    } else {
        return 0;
    }
}



static int
esxDomainIsActive(virDomainPtr domain)
{
M
Matthias Bolte 已提交
4175
    int result = -1;
M
Matthias Bolte 已提交
4176
    esxPrivate *priv = domain->conn->privateData;
4177 4178 4179 4180
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_String *propertyNameList = NULL;
    esxVI_VirtualMachinePowerState powerState;

4181
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4182
        return -1;
4183 4184
    }

4185
    if (esxVI_String_AppendValueToList(&propertyNameList,
4186
                                       "runtime.powerState") < 0 ||
4187
        esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4188
                                         propertyNameList, &virtualMachine,
M
Matthias Bolte 已提交
4189
                                         esxVI_Occurrence_RequiredItem) < 0 ||
4190
        esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
M
Matthias Bolte 已提交
4191
        goto cleanup;
4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215
    }

    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 已提交
4216 4217


4218 4219 4220 4221 4222
static int
esxDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
{
    return 0;
}
4223

M
Matthias Bolte 已提交
4224 4225


4226 4227
static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
4228
                           unsigned int flags)
4229 4230 4231 4232 4233 4234 4235 4236
{
    esxPrivate *priv = domain->conn->privateData;
    virDomainSnapshotDefPtr def = NULL;
    esxVI_ObjectContent *virtualMachine = NULL;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4237
    char *taskInfoErrorMessage = NULL;
4238 4239
    virDomainSnapshotPtr snapshot = NULL;

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

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

4247
    def = virDomainSnapshotDefParseString(xmlDesc, NULL, 0, 0);
4248 4249

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

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

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

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

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

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

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

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

    return snapshot;
}



static char *
4308 4309
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
4310 4311 4312 4313 4314 4315 4316 4317 4318
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotDef def;
    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
    char *xml = NULL;

4319 4320
    virCheckFlags(0, NULL);

M
Matthias Bolte 已提交
4321
    memset(&def, 0, sizeof (def));
4322

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

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

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

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

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

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

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

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return xml;
}



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

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

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

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

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

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



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

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

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

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

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

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



4443 4444 4445 4446 4447 4448 4449 4450
static int
esxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    int count = -1;
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    bool recurse;
4451
    bool leaves;
4452 4453

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

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

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

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

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

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return count;
}



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

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

    recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4506
    leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535

    if (names == NULL || nameslen < 0) {
        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
        return -1;
    }

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

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

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

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

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return result;
}



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

4555 4556
    virCheckFlags(0, NULL);

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

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

    snapshot = virGetDomainSnapshot(domain, name);

  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);

    return snapshot;
}



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

4585
    virCheckFlags(0, -1);
4586

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

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

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

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



E
Eric Blake 已提交
4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646
static virDomainSnapshotPtr
esxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
{
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

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

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

    if (!snapshotTreeParent) {
        ESX_ERROR(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                  _("snapshot '%s' does not have a parent"),
                  snapshotTree->name);
        goto cleanup;
    }

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

cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);

    return parent;
}



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

4654
    virCheckFlags(0, NULL);
4655

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

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

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

    esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);

    return snapshot;
}



static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4678
    int result = -1;
4679 4680 4681 4682 4683
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4684
    char *taskInfoErrorMessage = NULL;
4685

4686
    virCheckFlags(0, -1);
4687

4688
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4689
        return -1;
4690 4691
    }

4692
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4693 4694
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4695
                                    &snapshotTree, NULL,
4696
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4697
        goto cleanup;
4698 4699
    }

4700
    if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4701
                                    &task) < 0 ||
4702
        esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4703
                                    esxVI_Occurrence_RequiredItem,
4704
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4705
                                    &taskInfoErrorMessage) < 0) {
M
Matthias Bolte 已提交
4706
        goto cleanup;
4707 4708 4709 4710
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
4711 4712
                  _("Could not revert to snapshot '%s': %s"), snapshot->name,
                  taskInfoErrorMessage);
M
Matthias Bolte 已提交
4713
        goto cleanup;
4714 4715
    }

M
Matthias Bolte 已提交
4716 4717
    result = 0;

4718 4719 4720
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4721
    VIR_FREE(taskInfoErrorMessage);
4722 4723 4724 4725 4726 4727 4728 4729 4730

    return result;
}



static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
{
M
Matthias Bolte 已提交
4731
    int result = -1;
4732 4733 4734 4735 4736 4737
    esxPrivate *priv = snapshot->domain->conn->privateData;
    esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
    esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
    esxVI_Boolean removeChildren = esxVI_Boolean_False;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
4738
    char *taskInfoErrorMessage = NULL;
4739

4740 4741
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4742

4743
    if (esxVI_EnsureSession(priv->primary) < 0) {
M
Matthias Bolte 已提交
4744
        return -1;
4745 4746 4747 4748 4749 4750
    }

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

4751
    if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4752 4753
                                         &rootSnapshotList) < 0 ||
        esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4754
                                    &snapshotTree, NULL,
4755
                                    esxVI_Occurrence_RequiredItem) < 0) {
M
Matthias Bolte 已提交
4756
        goto cleanup;
4757 4758
    }

4759 4760 4761 4762 4763 4764 4765
    /* ESX snapshots do not require any libvirt metadata, making this
     * flag trivial once we know we have a valid snapshot.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
        result = 0;
        goto cleanup;
    }

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

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

M
Matthias Bolte 已提交
4782 4783
    result = 0;

4784 4785 4786
  cleanup:
    esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
    esxVI_ManagedObjectReference_Free(&task);
4787
    VIR_FREE(taskInfoErrorMessage);
4788 4789 4790 4791 4792 4793

    return result;
}



4794
static int
4795
esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4796 4797 4798 4799 4800 4801 4802 4803
                             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;
4804
    char *taskInfoErrorMessage = NULL;
4805 4806 4807 4808 4809 4810 4811 4812 4813 4814
    int i;

    virCheckFlags(0, -1);

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

    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
          (priv->primary, domain->uuid, NULL, &virtualMachine,
4815
           priv->parsedUri->autoAnswer) < 0 ||
4816 4817 4818 4819 4820 4821 4822
        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) &&
4823
            params[i].type == VIR_TYPED_PARAM_ULLONG) {
4824 4825 4826 4827 4828
            if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0) {
                goto cleanup;
            }

            spec->memoryAllocation->reservation->value =
4829
              VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840
        } 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,
4841
                                    priv->parsedUri->autoAnswer, &taskInfoState,
4842
                                    &taskInfoErrorMessage) < 0) {
4843 4844 4845 4846
        goto cleanup;
    }

    if (taskInfoState != esxVI_TaskInfoState_Success) {
4847 4848 4849
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not change memory parameters: %s"),
                  taskInfoErrorMessage);
4850 4851 4852 4853 4854 4855 4856 4857 4858
        goto cleanup;
    }

    result = 0;

  cleanup:
    esxVI_ObjectContent_Free(&virtualMachine);
    esxVI_VirtualMachineConfigSpec_Free(&spec);
    esxVI_ManagedObjectReference_Free(&task);
4859
    VIR_FREE(taskInfoErrorMessage);
4860 4861 4862 4863 4864 4865 4866

    return result;
}



static int
4867
esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910
                             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;
    }

4911
    params[0].type = VIR_TYPED_PARAM_ULLONG;
4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926
    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;
}



4927
static virDriver esxDriver = {
4928 4929
    .no = VIR_DRV_ESX,
    .name = "ESX",
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947
    .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 */
4948
    .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969
    .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 */
4970
    .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
4971 4972 4973 4974
    .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
4975
    .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
4976
    .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
4977
    .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990
    .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 */
4991 4992
    .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
4993 4994
    .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
E
Eric Blake 已提交
4995
    .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
4996 4997 4998
    .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
4999 5000 5001 5002 5003 5004 5005
};



int
esxRegister(void)
{
5006 5007 5008 5009 5010
    if (virRegisterDriver(&esxDriver) < 0 ||
        esxInterfaceRegister() < 0 ||
        esxNetworkRegister() < 0 ||
        esxStorageRegister() < 0 ||
        esxDeviceRegister() < 0 ||
M
Matthias Bolte 已提交
5011 5012
        esxSecretRegister() < 0 ||
        esxNWFilterRegister() < 0) {
5013 5014
        return -1;
    }
5015 5016 5017

    return 0;
}