1 /*
2  * esx_driver.c: core driver functions for managing VMware ESX hosts
3  *
4  * Copyright (C) 2010-2015 Red Hat, Inc.
5  * Copyright (C) 2009-2014 Matthias Bolte <matthias.bolte@googlemail.com>
6  * Copyright (C) 2009 Maximilian Wilhelm <max@rfc2324.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library.  If not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include <config.h>
25 
26 #include "internal.h"
27 #include "virdomainobjlist.h"
28 #include "snapshot_conf.h"
29 #include "virauth.h"
30 #include "viralloc.h"
31 #include "virfile.h"
32 #include "virlog.h"
33 #include "viruuid.h"
34 #include "vmx.h"
35 #include "virtypedparam.h"
36 #include "esx_driver.h"
37 #include "esx_interface_driver.h"
38 #include "esx_network_driver.h"
39 #include "esx_storage_driver.h"
40 #include "esx_private.h"
41 #include "esx_vi.h"
42 #include "esx_vi_methods.h"
43 #include "esx_util.h"
44 #include "esx_stream.h"
45 #include "virstring.h"
46 #include "viruri.h"
47 
48 #define VIR_FROM_THIS VIR_FROM_ESX
49 
50 VIR_LOG_INIT("esx.esx_driver");
51 
52 static int esxDomainGetMaxVcpus(virDomainPtr domain);
53 
54 typedef struct _esxVMX_Data esxVMX_Data;
55 
56 struct _esxVMX_Data {
57     esxVI_Context *ctx;
58     char *datastorePathWithoutFileName;
59 };
60 
61 
62 
63 static void
esxFreePrivate(esxPrivate ** priv)64 esxFreePrivate(esxPrivate **priv)
65 {
66     if (!priv || !(*priv))
67         return;
68 
69     esxVI_Context_Free(&(*priv)->host);
70     esxVI_Context_Free(&(*priv)->vCenter);
71     esxUtil_FreeParsedUri(&(*priv)->parsedUri);
72     virObjectUnref((*priv)->caps);
73     virObjectUnref((*priv)->xmlopt);
74     g_free(*priv);
75 }
76 
77 
78 
79 /*
80  * Parse a file name from a .vmx file and convert it to datastore path format
81  * if possible. A .vmx file can contain file names in various formats:
82  *
83  * - A single name referencing a file in the same directory as the .vmx file:
84  *
85  *     test1.vmdk
86  *
87  * - An absolute file name referencing a file in a datastore that is mounted at
88  *   /vmfs/volumes/<datastore>:
89  *
90  *     /vmfs/volumes/b24b7a78-9d82b4f5/test1/test1.vmdk
91  *     /vmfs/volumes/datastore1/test1/test1.vmdk
92  *
93  *   The actual mount directory is /vmfs/volumes/b24b7a78-9d82b4f5, the second
94  *   form is a symlink to it using the datastore name. This is the typical
95  *   setup on an ESX(i) server.
96  *
97  * - With GSX installed on Windows there are also Windows style file names
98  *   including UNC file names:
99  *
100  *     C:\Virtual Machines\test1\test1.vmdk
101  *     \\nas1\storage1\test1\test1.vmdk
102  *
103  * - There might also be absolute file names referencing files outside of a
104  *   datastore:
105  *
106  *     /usr/lib/vmware/isoimages/linux.iso
107  *
108  *   Such file names are left as is and are not converted to datastore path
109  *   format because this is not possible.
110  *
111  * The datastore path format typically looks like this:
112  *
113  *  [datastore1] test1/test1.vmdk
114  *
115  * Firstly this functions checks if the given file name contains a separator.
116  * If it doesn't then the referenced file is in the same directory as the .vmx
117  * file. The datastore name and directory of the .vmx file are passed to this
118  * function via the opaque parameter by the caller of virVMXParseConfig.
119  *
120  * Otherwise query for all known datastores and their mount directories. Then
121  * try to find a datastore with a mount directory that is a prefix to the given
122  * file name. This mechanism covers the Windows style file names too.
123  *
124  * The symlinks using the datastore name (/vmfs/volumes/datastore1) are an
125  * exception and need special handling. Parse the datastore name and use it
126  * to lookup the datastore by name to verify that it exists.
127  */
128 static int
esxParseVMXFileName(const char * fileName,void * opaque,char ** out,bool allow_missing)129 esxParseVMXFileName(const char *fileName,
130                     void *opaque,
131                     char **out,
132                     bool allow_missing)
133 {
134     esxVMX_Data *data = opaque;
135     esxVI_String *propertyNameList = NULL;
136     esxVI_ObjectContent *datastoreList = NULL;
137     esxVI_ObjectContent *datastore = NULL;
138     esxVI_DatastoreHostMount *hostMount = NULL;
139     char *datastoreName;
140     char *tmp;
141     char *saveptr;
142     g_autofree char *strippedFileName = NULL;
143     g_autofree char *copyOfFileName = NULL;
144     char *directoryAndFileName;
145     int ret = -1;
146 
147     *out = NULL;
148 
149     if (!strchr(fileName, '/') && !strchr(fileName, '\\')) {
150         /* Plain file name, use same directory as for the .vmx file */
151         *out = g_strdup_printf("%s/%s", data->datastorePathWithoutFileName,
152                                fileName);
153         return 0;
154     }
155 
156     if (esxVI_String_AppendValueToList(&propertyNameList,
157                                        "summary.name") < 0 ||
158         esxVI_LookupDatastoreList(data->ctx, propertyNameList,
159                                   &datastoreList) < 0) {
160         return -1;
161     }
162 
163     /* Search for datastore by mount path */
164     for (datastore = datastoreList; datastore;
165          datastore = datastore->_next) {
166         esxVI_DatastoreHostMount_Free(&hostMount);
167         datastoreName = NULL;
168 
169         if (esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
170                                            &hostMount,
171                                            esxVI_Occurrence_RequiredItem) < 0 ||
172             esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
173                                  esxVI_Occurrence_RequiredItem) < 0) {
174             goto cleanup;
175         }
176 
177         tmp = (char *)STRSKIP(fileName, hostMount->mountInfo->path);
178 
179         if (!tmp)
180             continue;
181 
182         /* Found a match. Strip leading separators */
183         while (*tmp == '/' || *tmp == '\\')
184             ++tmp;
185 
186         strippedFileName = g_strdup(tmp);
187 
188         tmp = strippedFileName;
189 
190         /* Convert \ to / */
191         while (*tmp != '\0') {
192             if (*tmp == '\\')
193                 *tmp = '/';
194 
195             ++tmp;
196         }
197 
198         *out = g_strdup_printf("[%s] %s", datastoreName, strippedFileName);
199 
200         break;
201     }
202 
203     /* Fallback to direct datastore name match */
204     if (!*out && STRPREFIX(fileName, "/vmfs/volumes/")) {
205         copyOfFileName = g_strdup(fileName);
206 
207         /* Expected format: '/vmfs/volumes/<datastore>/<path>' */
208         if (!(tmp = STRSKIP(copyOfFileName, "/vmfs/volumes/")) ||
209             !(datastoreName = strtok_r(tmp, "/", &saveptr))    ||
210             !(directoryAndFileName = strtok_r(NULL, "", &saveptr))) {
211             virReportError(VIR_ERR_INTERNAL_ERROR,
212                            _("File name '%s' doesn't have expected format "
213                              "'/vmfs/volumes/<datastore>/<path>'"), fileName);
214             goto cleanup;
215         }
216 
217         esxVI_ObjectContent_Free(&datastoreList);
218 
219         if (esxVI_LookupDatastoreByName(data->ctx, datastoreName,
220                                         NULL, &datastoreList,
221                                         esxVI_Occurrence_OptionalItem) < 0) {
222             goto cleanup;
223         }
224 
225         if (!datastoreList) {
226             if (allow_missing) {
227                 ret = 0;
228             } else {
229                 virReportError(VIR_ERR_INTERNAL_ERROR,
230                                _("File name '%s' refers to non-existing datastore '%s'"),
231                                fileName, datastoreName);
232             }
233             goto cleanup;
234         }
235 
236         *out = g_strdup_printf("[%s] %s", datastoreName, directoryAndFileName);
237     }
238 
239     /* If it's an absolute path outside of a datastore just use it as is */
240     if (!*out && *fileName == '/') {
241         /* FIXME: need to deal with Windows paths here too */
242         *out = g_strdup(fileName);
243     }
244 
245     if (!*out) {
246         virReportError(VIR_ERR_INTERNAL_ERROR,
247                        _("Could not handle file name '%s'"), fileName);
248         goto cleanup;
249     }
250 
251     ret = 0;
252  cleanup:
253     esxVI_String_Free(&propertyNameList);
254     esxVI_ObjectContent_Free(&datastoreList);
255     esxVI_DatastoreHostMount_Free(&hostMount);
256 
257     return ret;
258 }
259 
260 
261 
262 /*
263  * This function does the inverse of esxParseVMXFileName. It takes a file name
264  * in datastore path format or in absolute format and converts it to a file
265  * name that can be used in a .vmx file.
266  *
267  * The datastore path format and the formats found in a .vmx file are described
268  * in the documentation of esxParseVMXFileName.
269  *
270  * Firstly parse the datastore path. Then use the datastore name to lookup the
271  * datastore and its mount path. Finally concatenate the mount path, directory
272  * and file name to an absolute path and return it. Detect the separator type
273  * based on the mount path.
274  */
275 static char *
esxFormatVMXFileName(const char * fileName,void * opaque)276 esxFormatVMXFileName(const char *fileName, void *opaque)
277 {
278     g_autofree char *tmpResult = NULL;
279     char *result = NULL;
280     esxVMX_Data *data = opaque;
281     g_autofree char *datastoreName = NULL;
282     g_autofree char *directoryAndFileName = NULL;
283     esxVI_ObjectContent *datastore = NULL;
284     esxVI_DatastoreHostMount *hostMount = NULL;
285     char separator = '/';
286     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
287     char *tmp;
288     size_t length;
289 
290     if (*fileName == '[') {
291         /* Parse datastore path and lookup datastore */
292         if (esxUtil_ParseDatastorePath(fileName, &datastoreName, NULL,
293                                        &directoryAndFileName) < 0) {
294             goto cleanup;
295         }
296 
297         if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
298                                         esxVI_Occurrence_RequiredItem) < 0 ||
299             esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
300                                            &hostMount,
301                                            esxVI_Occurrence_RequiredItem) < 0) {
302             goto cleanup;
303         }
304 
305         /* Detect separator type */
306         if (strchr(hostMount->mountInfo->path, '\\'))
307             separator = '\\';
308 
309         /* Strip trailing separators */
310         length = strlen(hostMount->mountInfo->path);
311 
312         while (length > 0 && hostMount->mountInfo->path[length - 1] == separator)
313             --length;
314 
315         /* Format as <mount>[/<directory>]/<file>, convert / to \ when necessary */
316         virBufferAdd(&buffer, hostMount->mountInfo->path, length);
317 
318         if (separator != '/') {
319             tmp = directoryAndFileName;
320 
321             while (*tmp != '\0') {
322                 if (*tmp == '/')
323                     *tmp = separator;
324 
325                 ++tmp;
326             }
327         }
328 
329         virBufferAddChar(&buffer, separator);
330         virBufferAdd(&buffer, directoryAndFileName, -1);
331 
332         tmpResult = virBufferContentAndReset(&buffer);
333     } else if (*fileName == '/') {
334         /* FIXME: need to deal with Windows paths here too */
335         tmpResult = g_strdup(fileName);
336     } else {
337         virReportError(VIR_ERR_INTERNAL_ERROR,
338                        _("Could not handle file name '%s'"), fileName);
339         goto cleanup;
340     }
341 
342     /* FIXME: Check if referenced path/file really exists */
343 
344     result = g_steal_pointer(&tmpResult);
345 
346  cleanup:
347     esxVI_ObjectContent_Free(&datastore);
348     esxVI_DatastoreHostMount_Free(&hostMount);
349     return result;
350 }
351 
352 
353 
354 static int
esxAutodetectSCSIControllerModel(virDomainDiskDef * def,int * model,void * opaque)355 esxAutodetectSCSIControllerModel(virDomainDiskDef *def, int *model,
356                                  void *opaque)
357 {
358     int result = -1;
359     esxVMX_Data *data = opaque;
360     esxVI_FileInfo *fileInfo = NULL;
361     esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
362     const char *src = virDomainDiskGetSource(def);
363 
364     if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK ||
365         def->bus != VIR_DOMAIN_DISK_BUS_SCSI ||
366         virDomainDiskGetType(def) != VIR_STORAGE_TYPE_FILE ||
367         !src || !STRPREFIX(src, "[")) {
368         /*
369          * This isn't a file-based SCSI disk device with a datastore related
370          * source path => do nothing.
371          */
372         return 0;
373     }
374 
375     if (esxVI_LookupFileInfoByDatastorePath(data->ctx, src,
376                                             false, &fileInfo,
377                                             esxVI_Occurrence_RequiredItem) < 0) {
378         goto cleanup;
379     }
380 
381     vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
382 
383     if (!vmDiskFileInfo || !vmDiskFileInfo->controllerType) {
384         virReportError(VIR_ERR_INTERNAL_ERROR,
385                        _("Could not lookup controller model for '%s'"), src);
386         goto cleanup;
387     }
388 
389     if (STRCASEEQ(vmDiskFileInfo->controllerType,
390                   "VirtualBusLogicController")) {
391         *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
392     } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
393                          "VirtualLsiLogicController")) {
394         *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
395     } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
396                          "VirtualLsiLogicSASController")) {
397         *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068;
398     } else if (STRCASEEQ(vmDiskFileInfo->controllerType,
399                          "ParaVirtualSCSIController")) {
400         *model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI;
401     } else {
402         virReportError(VIR_ERR_INTERNAL_ERROR,
403                        _("Found unexpected controller model '%s' for disk '%s'"),
404                        vmDiskFileInfo->controllerType, src);
405         goto cleanup;
406     }
407 
408     result = 0;
409 
410  cleanup:
411     esxVI_FileInfo_Free(&fileInfo);
412 
413     return result;
414 }
415 
416 
417 
418 static esxVI_Boolean
esxSupportsLongMode(esxPrivate * priv)419 esxSupportsLongMode(esxPrivate *priv)
420 {
421     esxVI_String *propertyNameList = NULL;
422     esxVI_ObjectContent *hostSystem = NULL;
423     esxVI_DynamicProperty *dynamicProperty = NULL;
424     esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL;
425     esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL;
426     esxVI_ParsedHostCpuIdInfo parsedHostCpuIdInfo;
427     char edxLongModeBit = '?';
428 
429     if (priv->supportsLongMode != esxVI_Boolean_Undefined)
430         return priv->supportsLongMode;
431 
432     if (esxVI_EnsureSession(priv->primary) < 0)
433         return esxVI_Boolean_Undefined;
434 
435     if (esxVI_String_AppendValueToList(&propertyNameList,
436                                        "hardware.cpuFeature") < 0 ||
437         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
438                                          &hostSystem) < 0) {
439         goto cleanup;
440     }
441 
442     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
443          dynamicProperty = dynamicProperty->_next) {
444         if (STREQ(dynamicProperty->name, "hardware.cpuFeature")) {
445             if (esxVI_HostCpuIdInfo_CastListFromAnyType
446                   (dynamicProperty->val, &hostCpuIdInfoList) < 0) {
447                 goto cleanup;
448             }
449 
450             for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo;
451                  hostCpuIdInfo = hostCpuIdInfo->_next) {
452                 if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */
453                     if (esxVI_ParseHostCpuIdInfo(&parsedHostCpuIdInfo,
454                                                  hostCpuIdInfo) < 0) {
455                         goto cleanup;
456                     }
457 
458                     edxLongModeBit = parsedHostCpuIdInfo.edx[29];
459 
460                     if (edxLongModeBit == '1') {
461                         priv->supportsLongMode = esxVI_Boolean_True;
462                     } else if (edxLongModeBit == '0') {
463                         priv->supportsLongMode = esxVI_Boolean_False;
464                     } else {
465                         virReportError(VIR_ERR_INTERNAL_ERROR,
466                                        _("Bit 29 (Long Mode) of HostSystem property "
467                                          "'hardware.cpuFeature[].edx' with value '%s' "
468                                          "has unexpected value '%c', expecting '0' "
469                                          "or '1'"), hostCpuIdInfo->edx, edxLongModeBit);
470                         goto cleanup;
471                     }
472 
473                     break;
474                 }
475             }
476 
477             break;
478         } else {
479             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
480         }
481     }
482 
483  cleanup:
484     /*
485      * If we goto cleanup in case of an error then priv->supportsLongMode
486      * is still esxVI_Boolean_Undefined, therefore we don't need to set it.
487      */
488     esxVI_String_Free(&propertyNameList);
489     esxVI_ObjectContent_Free(&hostSystem);
490     esxVI_HostCpuIdInfo_Free(&hostCpuIdInfoList);
491 
492     return priv->supportsLongMode;
493 }
494 
495 
496 
497 static int
esxLookupHostSystemBiosUuid(esxPrivate * priv,unsigned char * uuid)498 esxLookupHostSystemBiosUuid(esxPrivate *priv, unsigned char *uuid)
499 {
500     int result = -1;
501     esxVI_String *propertyNameList = NULL;
502     esxVI_ObjectContent *hostSystem = NULL;
503     char *uuid_string = NULL;
504 
505     if (esxVI_EnsureSession(priv->primary) < 0)
506         return -1;
507 
508     if (esxVI_String_AppendValueToList(&propertyNameList,
509                                        "hardware.systemInfo.uuid") < 0 ||
510         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
511                                          &hostSystem) < 0 ||
512         esxVI_GetStringValue(hostSystem, "hardware.systemInfo.uuid",
513                              &uuid_string, esxVI_Occurrence_RequiredItem) < 0) {
514         goto cleanup;
515     }
516 
517     if (strlen(uuid_string) > 0) {
518         if (virUUIDParse(uuid_string, uuid) < 0) {
519             VIR_WARN("Could not parse host UUID from string '%s'", uuid_string);
520 
521             /* HostSystem has an invalid UUID, ignore it */
522             memset(uuid, 0, VIR_UUID_BUFLEN);
523         }
524     } else {
525         /* HostSystem has an empty UUID */
526         memset(uuid, 0, VIR_UUID_BUFLEN);
527     }
528 
529     result = 0;
530 
531  cleanup:
532     esxVI_String_Free(&propertyNameList);
533     esxVI_ObjectContent_Free(&hostSystem);
534 
535     return result;
536 }
537 
538 
539 static virCaps *
esxCapsInit(esxPrivate * priv)540 esxCapsInit(esxPrivate *priv)
541 {
542     esxVI_Boolean supportsLongMode = esxSupportsLongMode(priv);
543     virCaps *caps = NULL;
544     virCapsGuest *guest = NULL;
545 
546     if (supportsLongMode == esxVI_Boolean_Undefined)
547         return NULL;
548 
549     if (supportsLongMode == esxVI_Boolean_True) {
550         caps = virCapabilitiesNew(VIR_ARCH_X86_64, true, true);
551     } else {
552         caps = virCapabilitiesNew(VIR_ARCH_I686, true, true);
553     }
554 
555     if (!caps)
556         return NULL;
557 
558     virCapabilitiesAddHostMigrateTransport(caps, "vpxmigr");
559 
560 
561     if (esxLookupHostSystemBiosUuid(priv, caps->host.host_uuid) < 0)
562         goto failure;
563 
564     /* i686 */
565     guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
566                                     VIR_ARCH_I686,
567                                     NULL, NULL, 0,
568                                     NULL);
569 
570     virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VMWARE,
571                                   NULL, NULL, 0, NULL);
572 
573     /* x86_64 */
574     if (supportsLongMode == esxVI_Boolean_True) {
575         guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
576                                         VIR_ARCH_X86_64,
577                                         NULL, NULL,
578                                         0, NULL);
579 
580         virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VMWARE,
581                                       NULL, NULL, 0, NULL);
582     }
583 
584     return caps;
585 
586  failure:
587     virObjectUnref(caps);
588 
589     return NULL;
590 }
591 
592 
593 
594 static int
esxConnectToHost(esxPrivate * priv,virConnectPtr conn,virConnectAuthPtr auth,char ** vCenterIPAddress)595 esxConnectToHost(esxPrivate *priv,
596                  virConnectPtr conn,
597                  virConnectAuthPtr auth,
598                  char **vCenterIPAddress)
599 {
600     int result = -1;
601     g_autofree char *ipAddress = NULL;
602     g_autofree char *username = NULL;
603     g_autofree char *password = NULL;
604     g_autofree char *url = NULL;
605     esxVI_String *propertyNameList = NULL;
606     esxVI_ObjectContent *hostSystem = NULL;
607     esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;
608     esxVI_ProductLine expectedProductLine = STRCASEEQ(conn->uri->scheme, "esx")
609         ? esxVI_ProductLine_ESX
610         : esxVI_ProductLine_GSX;
611 
612     ESX_VI_CHECK_ARG_LIST(vCenterIPAddress);
613 
614     if (esxUtil_ResolveHostname(conn->uri->server, &ipAddress) < 0)
615         return -1;
616 
617     if (conn->uri->user) {
618         username = g_strdup(conn->uri->user);
619     } else {
620         if (!(username = virAuthGetUsername(conn, auth, "esx", "root",
621                                             conn->uri->server)))
622             goto cleanup;
623     }
624 
625     if (!(password = virAuthGetPassword(conn, auth, "esx", username,
626                                         conn->uri->server)))
627         goto cleanup;
628 
629     url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport,
630                           conn->uri->server, conn->uri->port);
631 
632     if (esxVI_Context_Alloc(&priv->host) < 0 ||
633         esxVI_Context_Connect(priv->host, url, ipAddress, username, password,
634                               priv->parsedUri) < 0 ||
635         esxVI_Context_LookupManagedObjects(priv->host) < 0) {
636         goto cleanup;
637     }
638 
639     if (priv->host->productLine != expectedProductLine) {
640         virReportError(VIR_ERR_INTERNAL_ERROR,
641                        _("Expecting '%s' to be a %s host but found a %s host"),
642                        conn->uri->server,
643                        esxVI_ProductLineToDisplayName(expectedProductLine),
644                        esxVI_ProductLineToDisplayName(priv->host->productLine));
645         goto cleanup;
646     }
647 
648     /* Query the host for maintenance mode and vCenter IP address */
649     if (esxVI_String_AppendValueListToList(&propertyNameList,
650                                            "runtime.inMaintenanceMode\0"
651                                            "summary.managementServerIp\0") < 0 ||
652         esxVI_LookupHostSystemProperties(priv->host, propertyNameList,
653                                          &hostSystem) < 0 ||
654         esxVI_GetBoolean(hostSystem, "runtime.inMaintenanceMode",
655                          &inMaintenanceMode,
656                          esxVI_Occurrence_RequiredItem) < 0 ||
657         esxVI_GetStringValue(hostSystem, "summary.managementServerIp",
658                              vCenterIPAddress,
659                              esxVI_Occurrence_OptionalItem) < 0) {
660         goto cleanup;
661     }
662 
663     /* Warn if host is in maintenance mode */
664     if (inMaintenanceMode == esxVI_Boolean_True)
665         VIR_WARN("The server is in maintenance mode");
666 
667     *vCenterIPAddress = g_strdup(*vCenterIPAddress);
668 
669     result = 0;
670 
671  cleanup:
672     esxVI_String_Free(&propertyNameList);
673     esxVI_ObjectContent_Free(&hostSystem);
674 
675     return result;
676 }
677 
678 
679 
680 static int
esxConnectToVCenter(esxPrivate * priv,virConnectPtr conn,virConnectAuthPtr auth,const char * hostname,const char * hostSystemIPAddress)681 esxConnectToVCenter(esxPrivate *priv,
682                     virConnectPtr conn,
683                     virConnectAuthPtr auth,
684                     const char *hostname,
685                     const char *hostSystemIPAddress)
686 {
687     g_autofree char *ipAddress = NULL;
688     g_autofree char *username = NULL;
689     g_autofree char *password = NULL;
690     g_autofree char *url = NULL;
691 
692     if (!hostSystemIPAddress &&
693         (!priv->parsedUri->path || STREQ(priv->parsedUri->path, "/"))) {
694         virReportError(VIR_ERR_INVALID_ARG, "%s",
695                        _("Path has to specify the datacenter and compute resource"));
696         return -1;
697     }
698 
699     if (esxUtil_ResolveHostname(hostname, &ipAddress) < 0)
700         return -1;
701 
702     if (conn->uri->user) {
703         username = g_strdup(conn->uri->user);
704     } else {
705         if (!(username = virAuthGetUsername(conn, auth, "esx", "administrator",
706                                             hostname)))
707             return -1;
708     }
709 
710     if (!(password = virAuthGetPassword(conn, auth, "esx", username, hostname)))
711         return -1;
712 
713     url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport, hostname,
714                           conn->uri->port);
715 
716     if (esxVI_Context_Alloc(&priv->vCenter) < 0 ||
717         esxVI_Context_Connect(priv->vCenter, url, ipAddress, username,
718                               password, priv->parsedUri) < 0) {
719         return -1;
720     }
721 
722     if (priv->vCenter->productLine != esxVI_ProductLine_VPX) {
723         virReportError(VIR_ERR_INTERNAL_ERROR,
724                        _("Expecting '%s' to be a %s host but found a %s host"),
725                        hostname,
726                        esxVI_ProductLineToDisplayName(esxVI_ProductLine_VPX),
727                        esxVI_ProductLineToDisplayName(priv->vCenter->productLine));
728         return -1;
729     }
730 
731     if (hostSystemIPAddress) {
732         if (esxVI_Context_LookupManagedObjectsByHostSystemIp(priv->vCenter, hostSystemIPAddress) < 0)
733             return -1;
734     } else {
735         if (esxVI_Context_LookupManagedObjectsByPath(priv->vCenter,
736                                                      priv->parsedUri->path) < 0) {
737             return -1;
738         }
739     }
740 
741     return 0;
742 }
743 
744 
745 
746 /*
747  * URI format: {vpx|esx|gsx}://[<username>@]<hostname>[:<port>]/[<path>][?<query parameter>...]
748  *             <path> = [<folder>/...]<datacenter>/[<folder>/...]<computeresource>[/<hostsystem>]
749  *
750  * If no port is specified the default port is set dependent on the scheme and
751  * transport parameter:
752  * - vpx+http  80
753  * - vpx+https 443
754  * - esx+http  80
755  * - esx+https 443
756  * - gsx+http  8222
757  * - gsx+https 8333
758  *
759  * For a vpx:// connection <path> references a host managed by the vCenter.
760  * In case the host is part of a cluster then <computeresource> is the cluster
761  * name. Otherwise <computeresource> and <hostsystem> are equal and the later
762  * can be omitted. As datacenters and computeresources can be organized in
763  * folders those have to be included in <path>.
764  *
765  * Optional query parameters:
766  * - transport={http|https}
767  * - vcenter={<vcenter>|*}             only useful for an esx:// connection
768  * - no_verify={0|1}
769  * - auto_answer={0|1}
770  * - proxy=[{http|socks|socks4|socks4a|socks5}://]<hostname>[:<port>]
771  *
772  * If no transport parameter is specified https is used.
773  *
774  * The vcenter parameter is only necessary for migration, because the vCenter
775  * server is in charge to initiate a migration between two ESX hosts. The
776  * vcenter parameter can be set to an explicitly hostname or to *. If set to *,
777  * the driver will check if the ESX host is managed by a vCenter and connect to
778  * it. If the ESX host is not managed by a vCenter an error is reported.
779  *
780  * If the no_verify parameter is set to 1, this disables libcurl client checks
781  * of the server's certificate. The default value is 0.
782  *
783  * If the auto_answer parameter is set to 1, the driver will respond to all
784  * virtual machine questions with the default answer, otherwise virtual machine
785  * questions will be reported as errors. The default value is 0.
786  *
787  * The proxy parameter allows to specify a proxy for to be used by libcurl.
788  * The default for the optional <type> part is http and socks is synonymous for
789  * socks5. The optional <port> part allows to override the default port 1080.
790  */
791 static virDrvOpenStatus
esxConnectOpen(virConnectPtr conn,virConnectAuthPtr auth,virConf * conf G_GNUC_UNUSED,unsigned int flags)792 esxConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
793                virConf *conf G_GNUC_UNUSED,
794                unsigned int flags)
795 {
796     virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
797     esxPrivate *priv = NULL;
798     g_autofree char *potentialVCenterIPAddress = NULL;
799     g_autofree char *vCenterIPAddress = NULL;
800 
801     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
802 
803     if (STRCASENEQ(conn->uri->scheme, "vpx") &&
804         STRNEQ(conn->uri->path, "/")) {
805         VIR_WARN("Ignoring unexpected path '%s' for non-vpx scheme '%s'",
806                  conn->uri->path, conn->uri->scheme);
807     }
808 
809     /* Allocate per-connection private data */
810     priv = g_new0(esxPrivate, 1);
811 
812     if (esxUtil_ParseUri(&priv->parsedUri, conn->uri) < 0)
813         goto cleanup;
814 
815     priv->maxVcpus = -1;
816     priv->supportsVMotion = esxVI_Boolean_Undefined;
817     priv->supportsLongMode = esxVI_Boolean_Undefined;
818     priv->supportsScreenshot = esxVI_Boolean_Undefined;
819     priv->usedCpuTimeCounterId = -1;
820 
821     /*
822      * Set the port dependent on the transport protocol if no port is
823      * specified. This allows us to rely on the port parameter being
824      * correctly set when building URIs later on, without the need to
825      * distinguish between the situations port == 0 and port != 0
826      */
827     if (conn->uri->port == 0) {
828         if (STRCASEEQ(conn->uri->scheme, "vpx") ||
829             STRCASEEQ(conn->uri->scheme, "esx")) {
830             if (STRCASEEQ(priv->parsedUri->transport, "https")) {
831                 conn->uri->port = 443;
832             } else {
833                 conn->uri->port = 80;
834             }
835         } else { /* GSX */
836             if (STRCASEEQ(priv->parsedUri->transport, "https")) {
837                 conn->uri->port = 8333;
838             } else {
839                 conn->uri->port = 8222;
840             }
841         }
842     }
843 
844     if (STRCASEEQ(conn->uri->scheme, "esx") ||
845         STRCASEEQ(conn->uri->scheme, "gsx")) {
846         /* Connect to host */
847         if (esxConnectToHost(priv, conn, auth,
848                              &potentialVCenterIPAddress) < 0) {
849             goto cleanup;
850         }
851 
852         /* Connect to vCenter */
853         if (priv->parsedUri->vCenter) {
854             if (STREQ(priv->parsedUri->vCenter, "*")) {
855                 if (!potentialVCenterIPAddress) {
856                     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
857                                    _("This host is not managed by a vCenter"));
858                     goto cleanup;
859                 }
860 
861                 vCenterIPAddress = g_strdup(potentialVCenterIPAddress);
862             } else {
863                 if (esxUtil_ResolveHostname(priv->parsedUri->vCenter,
864                                             &vCenterIPAddress) < 0) {
865                     goto cleanup;
866                 }
867 
868                 if (potentialVCenterIPAddress &&
869                     STRNEQ(vCenterIPAddress, potentialVCenterIPAddress)) {
870                     virReportError(VIR_ERR_INTERNAL_ERROR,
871                                    _("This host is managed by a vCenter with IP "
872                                      "address %s, but a mismatching vCenter '%s' "
873                                      "(%s) has been specified"),
874                                    potentialVCenterIPAddress, priv->parsedUri->vCenter,
875                                    vCenterIPAddress);
876                     goto cleanup;
877                 }
878             }
879 
880             if (esxConnectToVCenter(priv, conn, auth,
881                                     vCenterIPAddress,
882                                     priv->host->ipAddress) < 0) {
883                 goto cleanup;
884             }
885         }
886 
887         priv->primary = priv->host;
888     } else { /* VPX */
889         /* Connect to vCenter */
890         if (esxConnectToVCenter(priv, conn, auth,
891                                 conn->uri->server,
892                                 NULL) < 0) {
893             goto cleanup;
894         }
895 
896         priv->primary = priv->vCenter;
897     }
898 
899     /* Setup capabilities */
900     priv->caps = esxCapsInit(priv);
901 
902     if (!priv->caps)
903         goto cleanup;
904 
905     if (!(priv->xmlopt = virVMXDomainXMLConfInit(priv->caps)))
906         goto cleanup;
907 
908     conn->privateData = g_steal_pointer(&priv);
909     result = VIR_DRV_OPEN_SUCCESS;
910 
911  cleanup:
912     esxFreePrivate(&priv);
913     return result;
914 }
915 
916 
917 
918 static int
esxConnectClose(virConnectPtr conn)919 esxConnectClose(virConnectPtr conn)
920 {
921     esxPrivate *priv = conn->privateData;
922     int result = 0;
923 
924     if (priv->host) {
925         if (esxVI_EnsureSession(priv->host) < 0 ||
926             esxVI_Logout(priv->host) < 0) {
927             result = -1;
928         }
929     }
930 
931     if (priv->vCenter) {
932         if (esxVI_EnsureSession(priv->vCenter) < 0 ||
933             esxVI_Logout(priv->vCenter) < 0) {
934             result = -1;
935         }
936     }
937 
938     esxFreePrivate(&priv);
939 
940     conn->privateData = NULL;
941 
942     return result;
943 }
944 
945 
946 
947 static esxVI_Boolean
esxSupportsVMotion(esxPrivate * priv)948 esxSupportsVMotion(esxPrivate *priv)
949 {
950     esxVI_String *propertyNameList = NULL;
951     esxVI_ObjectContent *hostSystem = NULL;
952 
953     if (priv->supportsVMotion != esxVI_Boolean_Undefined)
954         return priv->supportsVMotion;
955 
956     if (esxVI_EnsureSession(priv->primary) < 0)
957         return esxVI_Boolean_Undefined;
958 
959     if (esxVI_String_AppendValueToList(&propertyNameList,
960                                        "capability.vmotionSupported") < 0 ||
961         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
962                                          &hostSystem) < 0 ||
963         esxVI_GetBoolean(hostSystem, "capability.vmotionSupported",
964                          &priv->supportsVMotion,
965                          esxVI_Occurrence_RequiredItem) < 0) {
966         goto cleanup;
967     }
968 
969  cleanup:
970     /*
971      * If we goto cleanup in case of an error then priv->supportsVMotion is
972      * still esxVI_Boolean_Undefined, therefore we don't need to set it.
973      */
974     esxVI_String_Free(&propertyNameList);
975     esxVI_ObjectContent_Free(&hostSystem);
976 
977     return priv->supportsVMotion;
978 }
979 
980 
981 
982 static esxVI_Boolean
esxSupportsScreenshot(esxPrivate * priv)983 esxSupportsScreenshot(esxPrivate *priv)
984 {
985     esxVI_String *propertyNameList = NULL;
986     esxVI_ObjectContent *hostSystem = NULL;
987 
988     if (priv->supportsScreenshot != esxVI_Boolean_Undefined)
989         return priv->supportsScreenshot;
990 
991     if (esxVI_EnsureSession(priv->primary) < 0)
992         return esxVI_Boolean_Undefined;
993 
994     if (esxVI_String_AppendValueToList(&propertyNameList,
995                                        "capability.screenshotSupported") < 0 ||
996         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
997                                          &hostSystem) < 0 ||
998         esxVI_GetBoolean(hostSystem, "capability.screenshotSupported",
999                          &priv->supportsScreenshot,
1000                          esxVI_Occurrence_RequiredItem) < 0)
1001         goto cleanup;
1002 
1003  cleanup:
1004     /*
1005      * If we goto cleanup in case of an error then priv->supportsScreenshot is
1006      * still esxVI_Boolean_Undefined, therefore we don't need to set it.
1007      */
1008     esxVI_String_Free(&propertyNameList);
1009     esxVI_ObjectContent_Free(&hostSystem);
1010 
1011     return priv->supportsScreenshot;
1012 }
1013 
1014 
1015 
1016 static int
esxConnectSupportsFeature(virConnectPtr conn,int feature)1017 esxConnectSupportsFeature(virConnectPtr conn, int feature)
1018 {
1019     esxPrivate *priv = conn->privateData;
1020     esxVI_Boolean supportsVMotion = esxVI_Boolean_Undefined;
1021 
1022     switch ((virDrvFeature) feature) {
1023       case VIR_DRV_FEATURE_MIGRATION_V1:
1024         supportsVMotion = esxSupportsVMotion(priv);
1025 
1026         if (supportsVMotion == esxVI_Boolean_Undefined)
1027             return -1;
1028 
1029         /* Migration is only possible via a vCenter and if VMotion is enabled */
1030         return priv->vCenter &&
1031                supportsVMotion == esxVI_Boolean_True ? 1 : 0;
1032 
1033     case VIR_DRV_FEATURE_NETWORK_UPDATE_HAS_CORRECT_ORDER:
1034         return 1;
1035 
1036     case VIR_DRV_FEATURE_FD_PASSING:
1037     case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1038     case VIR_DRV_FEATURE_MIGRATION_DIRECT:
1039     case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1040     case VIR_DRV_FEATURE_MIGRATION_P2P:
1041     case VIR_DRV_FEATURE_MIGRATION_PARAMS:
1042     case VIR_DRV_FEATURE_MIGRATION_V2:
1043     case VIR_DRV_FEATURE_MIGRATION_V3:
1044     case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
1045     case VIR_DRV_FEATURE_REMOTE:
1046     case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
1047     case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
1048     case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1049     case VIR_DRV_FEATURE_XML_MIGRATABLE:
1050     default:
1051         return 0;
1052     }
1053 }
1054 
1055 
1056 
1057 static const char *
esxConnectGetType(virConnectPtr conn G_GNUC_UNUSED)1058 esxConnectGetType(virConnectPtr conn G_GNUC_UNUSED)
1059 {
1060     return "ESX";
1061 }
1062 
1063 
1064 
1065 static int
esxConnectGetVersion(virConnectPtr conn,unsigned long * version)1066 esxConnectGetVersion(virConnectPtr conn, unsigned long *version)
1067 {
1068     esxPrivate *priv = conn->privateData;
1069 
1070     *version = priv->primary->productVersion;
1071 
1072     return 0;
1073 }
1074 
1075 
1076 
1077 static char *
esxConnectGetHostname(virConnectPtr conn)1078 esxConnectGetHostname(virConnectPtr conn)
1079 {
1080     esxPrivate *priv = conn->privateData;
1081     esxVI_String *propertyNameList = NULL;
1082     esxVI_ObjectContent *hostSystem = NULL;
1083     esxVI_DynamicProperty *dynamicProperty = NULL;
1084     const char *hostName = NULL;
1085     const char *domainName = NULL;
1086     char *complete = NULL;
1087 
1088     if (esxVI_EnsureSession(priv->primary) < 0)
1089         return NULL;
1090 
1091     if (esxVI_String_AppendValueListToList
1092           (&propertyNameList,
1093            "config.network.dnsConfig.hostName\0"
1094            "config.network.dnsConfig.domainName\0") < 0 ||
1095         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1096                                          &hostSystem) < 0) {
1097         goto cleanup;
1098     }
1099 
1100     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
1101          dynamicProperty = dynamicProperty->_next) {
1102         if (STREQ(dynamicProperty->name,
1103                   "config.network.dnsConfig.hostName")) {
1104             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1105                                          esxVI_Type_String) < 0) {
1106                 goto cleanup;
1107             }
1108 
1109             hostName = dynamicProperty->val->string;
1110         } else if (STREQ(dynamicProperty->name,
1111                          "config.network.dnsConfig.domainName")) {
1112             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1113                                          esxVI_Type_String) < 0) {
1114                 goto cleanup;
1115             }
1116 
1117             domainName = dynamicProperty->val->string;
1118         } else {
1119             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
1120         }
1121     }
1122 
1123     if (!hostName || strlen(hostName) < 1) {
1124         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1125                        _("Missing or empty 'hostName' property"));
1126         goto cleanup;
1127     }
1128 
1129     if (!domainName || strlen(domainName) < 1) {
1130         complete = g_strdup(hostName);
1131     } else {
1132         complete = g_strdup_printf("%s.%s", hostName, domainName);
1133     }
1134 
1135  cleanup:
1136     esxVI_String_Free(&propertyNameList);
1137     esxVI_ObjectContent_Free(&hostSystem);
1138 
1139     return complete;
1140 }
1141 
1142 
1143 
1144 static int
esxNodeGetInfo(virConnectPtr conn,virNodeInfoPtr nodeinfo)1145 esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
1146 {
1147     int result = -1;
1148     esxPrivate *priv = conn->privateData;
1149     esxVI_String *propertyNameList = NULL;
1150     esxVI_ObjectContent *hostSystem = NULL;
1151     esxVI_DynamicProperty *dynamicProperty = NULL;
1152     int64_t cpuInfo_hz = 0;
1153     int16_t cpuInfo_numCpuCores = 0;
1154     int16_t cpuInfo_numCpuPackages = 0;
1155     int16_t cpuInfo_numCpuThreads = 0;
1156     int64_t memorySize = 0;
1157     int32_t numaInfo_numNodes = 0;
1158     char *ptr = NULL;
1159 
1160     memset(nodeinfo, 0, sizeof(*nodeinfo));
1161 
1162     if (esxVI_EnsureSession(priv->primary) < 0)
1163         return -1;
1164 
1165     if (esxVI_String_AppendValueListToList(&propertyNameList,
1166                                            "hardware.cpuInfo.hz\0"
1167                                            "hardware.cpuInfo.numCpuCores\0"
1168                                            "hardware.cpuInfo.numCpuPackages\0"
1169                                            "hardware.cpuInfo.numCpuThreads\0"
1170                                            "hardware.memorySize\0"
1171                                            "hardware.numaInfo.numNodes\0"
1172                                            "summary.hardware.cpuModel\0") < 0 ||
1173         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
1174                                          &hostSystem) < 0) {
1175         goto cleanup;
1176     }
1177 
1178     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
1179          dynamicProperty = dynamicProperty->_next) {
1180         if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) {
1181             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1182                                          esxVI_Type_Long) < 0) {
1183                 goto cleanup;
1184             }
1185 
1186             cpuInfo_hz = dynamicProperty->val->int64;
1187         } else if (STREQ(dynamicProperty->name,
1188                          "hardware.cpuInfo.numCpuCores")) {
1189             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1190                                          esxVI_Type_Short) < 0) {
1191                 goto cleanup;
1192             }
1193 
1194             cpuInfo_numCpuCores = dynamicProperty->val->int16;
1195         } else if (STREQ(dynamicProperty->name,
1196                          "hardware.cpuInfo.numCpuPackages")) {
1197             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1198                                          esxVI_Type_Short) < 0) {
1199                 goto cleanup;
1200             }
1201 
1202             cpuInfo_numCpuPackages = dynamicProperty->val->int16;
1203         } else if (STREQ(dynamicProperty->name,
1204                          "hardware.cpuInfo.numCpuThreads")) {
1205             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1206                                          esxVI_Type_Short) < 0) {
1207                 goto cleanup;
1208             }
1209 
1210             cpuInfo_numCpuThreads = dynamicProperty->val->int16;
1211         } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) {
1212             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1213                                          esxVI_Type_Long) < 0) {
1214                 goto cleanup;
1215             }
1216 
1217             memorySize = dynamicProperty->val->int64;
1218         } else if (STREQ(dynamicProperty->name,
1219                          "hardware.numaInfo.numNodes")) {
1220             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1221                                          esxVI_Type_Int) < 0) {
1222                 goto cleanup;
1223             }
1224 
1225             numaInfo_numNodes = dynamicProperty->val->int32;
1226         } else if (STREQ(dynamicProperty->name,
1227                          "summary.hardware.cpuModel")) {
1228             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1229                                          esxVI_Type_String) < 0) {
1230                 goto cleanup;
1231             }
1232 
1233             ptr = dynamicProperty->val->string;
1234 
1235             /* Strip the string to fit more relevant information in 32 chars */
1236             while (*ptr != '\0') {
1237                 if (STRPREFIX(ptr, "  ")) {
1238                     memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
1239                     continue;
1240                 } else if (STRPREFIX(ptr, "(R)") || STRPREFIX(ptr, "(C)")) {
1241                     memmove(ptr, ptr + 3, strlen(ptr + 3) + 1);
1242                     continue;
1243                 } else if (STRPREFIX(ptr, "(TM)")) {
1244                     memmove(ptr, ptr + 4, strlen(ptr + 4) + 1);
1245                     continue;
1246                 }
1247 
1248                 ++ptr;
1249             }
1250 
1251             /* Make sure the string fits in mode */
1252             dynamicProperty->val->string[sizeof(nodeinfo->model) - 1] = '\0';
1253             if (virStrcpyStatic(nodeinfo->model, dynamicProperty->val->string) < 0) {
1254                 virReportError(VIR_ERR_INTERNAL_ERROR,
1255                                _("CPU Model %s too long for destination"),
1256                                dynamicProperty->val->string);
1257                 goto cleanup;
1258             }
1259         } else {
1260             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
1261         }
1262     }
1263 
1264     nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */
1265     nodeinfo->cpus = cpuInfo_numCpuCores;
1266     nodeinfo->mhz = cpuInfo_hz / (1000 * 1000); /* Scale from hz to mhz */
1267     nodeinfo->nodes = numaInfo_numNodes;
1268     nodeinfo->sockets = cpuInfo_numCpuPackages;
1269     nodeinfo->cores = cpuInfo_numCpuPackages > 0
1270                         ? cpuInfo_numCpuCores / cpuInfo_numCpuPackages
1271                         : 0;
1272     nodeinfo->threads = cpuInfo_numCpuCores > 0
1273                           ? cpuInfo_numCpuThreads / cpuInfo_numCpuCores
1274                           : 0;
1275 
1276     result = 0;
1277 
1278  cleanup:
1279     esxVI_String_Free(&propertyNameList);
1280     esxVI_ObjectContent_Free(&hostSystem);
1281 
1282     return result;
1283 }
1284 
1285 
1286 
1287 static char *
esxConnectGetCapabilities(virConnectPtr conn)1288 esxConnectGetCapabilities(virConnectPtr conn)
1289 {
1290     esxPrivate *priv = conn->privateData;
1291 
1292     return virCapabilitiesFormatXML(priv->caps);
1293 }
1294 
1295 
1296 
1297 static int
esxConnectListDomains(virConnectPtr conn,int * ids,int maxids)1298 esxConnectListDomains(virConnectPtr conn, int *ids, int maxids)
1299 {
1300     bool success = false;
1301     esxPrivate *priv = conn->privateData;
1302     esxVI_ObjectContent *virtualMachineList = NULL;
1303     esxVI_ObjectContent *virtualMachine = NULL;
1304     esxVI_String *propertyNameList = NULL;
1305     esxVI_VirtualMachinePowerState powerState;
1306     int count = 0;
1307 
1308     if (maxids == 0)
1309         return 0;
1310 
1311     if (esxVI_EnsureSession(priv->primary) < 0)
1312         return -1;
1313 
1314     if (esxVI_String_AppendValueToList(&propertyNameList,
1315                                        "runtime.powerState") < 0 ||
1316         esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
1317                                        &virtualMachineList) < 0) {
1318         goto cleanup;
1319     }
1320 
1321     for (virtualMachine = virtualMachineList; virtualMachine;
1322          virtualMachine = virtualMachine->_next) {
1323         if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1324                                               &powerState) < 0) {
1325             goto cleanup;
1326         }
1327 
1328         if (powerState != esxVI_VirtualMachinePowerState_PoweredOn)
1329             continue;
1330 
1331         if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value,
1332                                                 &ids[count]) < 0 ||
1333             ids[count] <= 0) {
1334             virReportError(VIR_ERR_INTERNAL_ERROR,
1335                            _("Failed to parse positive integer from '%s'"),
1336                            virtualMachine->obj->value);
1337             goto cleanup;
1338         }
1339 
1340         count++;
1341 
1342         if (count >= maxids)
1343             break;
1344     }
1345 
1346     success = true;
1347 
1348  cleanup:
1349     esxVI_String_Free(&propertyNameList);
1350     esxVI_ObjectContent_Free(&virtualMachineList);
1351 
1352     return success ? count : -1;
1353 }
1354 
1355 
1356 
1357 static int
esxConnectNumOfDomains(virConnectPtr conn)1358 esxConnectNumOfDomains(virConnectPtr conn)
1359 {
1360     esxPrivate *priv = conn->privateData;
1361 
1362     if (esxVI_EnsureSession(priv->primary) < 0)
1363         return -1;
1364 
1365     return esxVI_LookupNumberOfDomainsByPowerState
1366              (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, false);
1367 }
1368 
1369 
1370 
1371 static virDomainPtr
esxDomainLookupByID(virConnectPtr conn,int id)1372 esxDomainLookupByID(virConnectPtr conn, int id)
1373 {
1374     esxPrivate *priv = conn->privateData;
1375     esxVI_String *propertyNameList = NULL;
1376     esxVI_ObjectContent *virtualMachineList = NULL;
1377     esxVI_ObjectContent *virtualMachine = NULL;
1378     esxVI_VirtualMachinePowerState powerState;
1379     int id_candidate = -1;
1380     unsigned char uuid_candidate[VIR_UUID_BUFLEN];
1381     virDomainPtr domain = NULL;
1382 
1383     if (esxVI_EnsureSession(priv->primary) < 0)
1384         return NULL;
1385 
1386     if (esxVI_String_AppendValueListToList(&propertyNameList,
1387                                            "configStatus\0"
1388                                            "name\0"
1389                                            "runtime.powerState\0"
1390                                            "config.uuid\0") < 0 ||
1391         esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
1392                                        &virtualMachineList) < 0) {
1393         goto cleanup;
1394     }
1395 
1396     for (virtualMachine = virtualMachineList; virtualMachine;
1397          virtualMachine = virtualMachine->_next) {
1398         g_autofree char *name_candidate = NULL;
1399 
1400         if (esxVI_GetVirtualMachinePowerState(virtualMachine,
1401                                               &powerState) < 0) {
1402             goto cleanup;
1403         }
1404 
1405         /* Only running/suspended domains have an ID != -1 */
1406         if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
1407             continue;
1408 
1409         if (esxVI_GetVirtualMachineIdentity(virtualMachine,
1410                                             &id_candidate, &name_candidate,
1411                                             uuid_candidate) < 0) {
1412             goto cleanup;
1413         }
1414 
1415         if (id != id_candidate)
1416             continue;
1417 
1418         domain = virGetDomain(conn, name_candidate, uuid_candidate, id);
1419 
1420         if (!domain)
1421             goto cleanup;
1422 
1423         break;
1424     }
1425 
1426     if (!domain)
1427         virReportError(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
1428 
1429  cleanup:
1430     esxVI_String_Free(&propertyNameList);
1431     esxVI_ObjectContent_Free(&virtualMachineList);
1432     return domain;
1433 }
1434 
1435 
1436 
1437 static virDomainPtr
esxDomainLookupByUUID(virConnectPtr conn,const unsigned char * uuid)1438 esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
1439 {
1440     esxPrivate *priv = conn->privateData;
1441     esxVI_String *propertyNameList = NULL;
1442     esxVI_ObjectContent *virtualMachine = NULL;
1443     esxVI_VirtualMachinePowerState powerState;
1444     int id = -1;
1445     g_autofree char *name = NULL;
1446     virDomainPtr domain = NULL;
1447 
1448     if (esxVI_EnsureSession(priv->primary) < 0)
1449         return NULL;
1450 
1451     if (esxVI_String_AppendValueListToList(&propertyNameList,
1452                                            "name\0"
1453                                            "runtime.powerState\0") < 0 ||
1454         esxVI_LookupVirtualMachineByUuid(priv->primary, uuid, propertyNameList,
1455                                          &virtualMachine,
1456                                          esxVI_Occurrence_RequiredItem) < 0 ||
1457         esxVI_GetVirtualMachineIdentity(virtualMachine, &id, &name, NULL) < 0 ||
1458         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1459         goto cleanup;
1460     }
1461 
1462     /* Only running/suspended virtual machines have an ID != -1 */
1463     if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
1464         id = -1;
1465 
1466     domain = virGetDomain(conn, name, uuid, id);
1467 
1468  cleanup:
1469     esxVI_String_Free(&propertyNameList);
1470     esxVI_ObjectContent_Free(&virtualMachine);
1471     return domain;
1472 }
1473 
1474 
1475 
1476 static virDomainPtr
esxDomainLookupByName(virConnectPtr conn,const char * name)1477 esxDomainLookupByName(virConnectPtr conn, const char *name)
1478 {
1479     esxPrivate *priv = conn->privateData;
1480     esxVI_String *propertyNameList = NULL;
1481     esxVI_ObjectContent *virtualMachine = NULL;
1482     esxVI_VirtualMachinePowerState powerState;
1483     int id = -1;
1484     unsigned char uuid[VIR_UUID_BUFLEN];
1485     virDomainPtr domain = NULL;
1486 
1487     if (esxVI_EnsureSession(priv->primary) < 0)
1488         return NULL;
1489 
1490     if (esxVI_String_AppendValueListToList(&propertyNameList,
1491                                            "configStatus\0"
1492                                            "runtime.powerState\0"
1493                                            "config.uuid\0") < 0 ||
1494         esxVI_LookupVirtualMachineByName(priv->primary, name, propertyNameList,
1495                                          &virtualMachine,
1496                                          esxVI_Occurrence_RequiredItem) < 0) {
1497         goto cleanup;
1498     }
1499 
1500     if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, uuid) < 0 ||
1501         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1502         goto cleanup;
1503     }
1504 
1505     /* Only running/suspended virtual machines have an ID != -1 */
1506     if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
1507         id = -1;
1508 
1509     domain = virGetDomain(conn, name, uuid, id);
1510 
1511  cleanup:
1512     esxVI_String_Free(&propertyNameList);
1513     esxVI_ObjectContent_Free(&virtualMachine);
1514 
1515     return domain;
1516 }
1517 
1518 
1519 
1520 static int
esxDomainSuspend(virDomainPtr domain)1521 esxDomainSuspend(virDomainPtr domain)
1522 {
1523     int result = -1;
1524     esxPrivate *priv = domain->conn->privateData;
1525     esxVI_ObjectContent *virtualMachine = NULL;
1526     esxVI_String *propertyNameList = NULL;
1527     esxVI_VirtualMachinePowerState powerState;
1528     esxVI_ManagedObjectReference *task = NULL;
1529     esxVI_TaskInfoState taskInfoState;
1530     g_autofree char *taskInfoErrorMessage = NULL;
1531 
1532     if (esxVI_EnsureSession(priv->primary) < 0)
1533         return -1;
1534 
1535     if (esxVI_String_AppendValueToList(&propertyNameList,
1536                                        "runtime.powerState") < 0 ||
1537         esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1538           (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1539            priv->parsedUri->autoAnswer) < 0 ||
1540         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1541         goto cleanup;
1542     }
1543 
1544     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1545         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1546                        _("Domain is not powered on"));
1547         goto cleanup;
1548     }
1549 
1550     if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
1551         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1552                                     esxVI_Occurrence_RequiredItem,
1553                                     priv->parsedUri->autoAnswer, &taskInfoState,
1554                                     &taskInfoErrorMessage) < 0) {
1555         goto cleanup;
1556     }
1557 
1558     if (taskInfoState != esxVI_TaskInfoState_Success) {
1559         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
1560                        taskInfoErrorMessage);
1561         goto cleanup;
1562     }
1563 
1564     result = 0;
1565 
1566  cleanup:
1567     esxVI_ObjectContent_Free(&virtualMachine);
1568     esxVI_String_Free(&propertyNameList);
1569     esxVI_ManagedObjectReference_Free(&task);
1570     return result;
1571 }
1572 
1573 
1574 
1575 static int
esxDomainResume(virDomainPtr domain)1576 esxDomainResume(virDomainPtr domain)
1577 {
1578     int result = -1;
1579     esxPrivate *priv = domain->conn->privateData;
1580     esxVI_ObjectContent *virtualMachine = NULL;
1581     esxVI_String *propertyNameList = NULL;
1582     esxVI_VirtualMachinePowerState powerState;
1583     esxVI_ManagedObjectReference *task = NULL;
1584     esxVI_TaskInfoState taskInfoState;
1585     g_autofree char *taskInfoErrorMessage = NULL;
1586 
1587     if (esxVI_EnsureSession(priv->primary) < 0)
1588         return -1;
1589 
1590     if (esxVI_String_AppendValueToList(&propertyNameList,
1591                                        "runtime.powerState") < 0 ||
1592         esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1593           (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1594            priv->parsedUri->autoAnswer) < 0 ||
1595         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1596         goto cleanup;
1597     }
1598 
1599     if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
1600         virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not suspended"));
1601         goto cleanup;
1602     }
1603 
1604     if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
1605                              &task) < 0 ||
1606         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1607                                     esxVI_Occurrence_RequiredItem,
1608                                     priv->parsedUri->autoAnswer, &taskInfoState,
1609                                     &taskInfoErrorMessage) < 0) {
1610         goto cleanup;
1611     }
1612 
1613     if (taskInfoState != esxVI_TaskInfoState_Success) {
1614         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
1615                        taskInfoErrorMessage);
1616         goto cleanup;
1617     }
1618 
1619     result = 0;
1620 
1621  cleanup:
1622     esxVI_ObjectContent_Free(&virtualMachine);
1623     esxVI_String_Free(&propertyNameList);
1624     esxVI_ManagedObjectReference_Free(&task);
1625     return result;
1626 }
1627 
1628 
1629 
1630 static int
esxDomainShutdownFlags(virDomainPtr domain,unsigned int flags)1631 esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
1632 {
1633     int result = -1;
1634     esxPrivate *priv = domain->conn->privateData;
1635     esxVI_ObjectContent *virtualMachine = NULL;
1636     esxVI_String *propertyNameList = NULL;
1637     esxVI_VirtualMachinePowerState powerState;
1638 
1639     virCheckFlags(0, -1);
1640 
1641     if (esxVI_EnsureSession(priv->primary) < 0)
1642         return -1;
1643 
1644     if (esxVI_String_AppendValueToList(&propertyNameList,
1645                                        "runtime.powerState") < 0 ||
1646         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1647                                          propertyNameList, &virtualMachine,
1648                                          esxVI_Occurrence_RequiredItem) < 0 ||
1649         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1650         goto cleanup;
1651     }
1652 
1653     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1654         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1655                        _("Domain is not powered on"));
1656         goto cleanup;
1657     }
1658 
1659     if (esxVI_ShutdownGuest(priv->primary, virtualMachine->obj) < 0)
1660         goto cleanup;
1661 
1662     result = 0;
1663 
1664  cleanup:
1665     esxVI_ObjectContent_Free(&virtualMachine);
1666     esxVI_String_Free(&propertyNameList);
1667 
1668     return result;
1669 }
1670 
1671 
1672 static int
esxDomainShutdown(virDomainPtr domain)1673 esxDomainShutdown(virDomainPtr domain)
1674 {
1675     return esxDomainShutdownFlags(domain, 0);
1676 }
1677 
1678 
1679 static int
esxDomainReboot(virDomainPtr domain,unsigned int flags)1680 esxDomainReboot(virDomainPtr domain, unsigned int flags)
1681 {
1682     int result = -1;
1683     esxPrivate *priv = domain->conn->privateData;
1684     esxVI_ObjectContent *virtualMachine = NULL;
1685     esxVI_String *propertyNameList = NULL;
1686     esxVI_VirtualMachinePowerState powerState;
1687 
1688     virCheckFlags(0, -1);
1689 
1690     if (esxVI_EnsureSession(priv->primary) < 0)
1691         return -1;
1692 
1693     if (esxVI_String_AppendValueToList(&propertyNameList,
1694                                        "runtime.powerState") < 0 ||
1695         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1696                                          propertyNameList, &virtualMachine,
1697                                          esxVI_Occurrence_RequiredItem) < 0 ||
1698         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1699         goto cleanup;
1700     }
1701 
1702     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1703         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1704                        _("Domain is not powered on"));
1705         goto cleanup;
1706     }
1707 
1708     if (esxVI_RebootGuest(priv->primary, virtualMachine->obj) < 0)
1709         goto cleanup;
1710 
1711     result = 0;
1712 
1713  cleanup:
1714     esxVI_ObjectContent_Free(&virtualMachine);
1715     esxVI_String_Free(&propertyNameList);
1716 
1717     return result;
1718 }
1719 
1720 
1721 
1722 static int
esxDomainDestroyFlags(virDomainPtr domain,unsigned int flags)1723 esxDomainDestroyFlags(virDomainPtr domain,
1724                       unsigned int flags)
1725 {
1726     int result = -1;
1727     esxPrivate *priv = domain->conn->privateData;
1728     esxVI_Context *ctx = NULL;
1729     esxVI_ObjectContent *virtualMachine = NULL;
1730     esxVI_String *propertyNameList = NULL;
1731     esxVI_VirtualMachinePowerState powerState;
1732     esxVI_ManagedObjectReference *task = NULL;
1733     esxVI_TaskInfoState taskInfoState;
1734     g_autofree char *taskInfoErrorMessage = NULL;
1735 
1736     virCheckFlags(0, -1);
1737 
1738     if (priv->vCenter) {
1739         ctx = priv->vCenter;
1740     } else {
1741         ctx = priv->host;
1742     }
1743 
1744     if (esxVI_EnsureSession(ctx) < 0)
1745         return -1;
1746 
1747     if (esxVI_String_AppendValueToList(&propertyNameList,
1748                                        "runtime.powerState") < 0 ||
1749         esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1750           (ctx, domain->uuid, propertyNameList, &virtualMachine,
1751            priv->parsedUri->autoAnswer) < 0 ||
1752         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1753         goto cleanup;
1754     }
1755 
1756     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
1757         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1758                        _("Domain is not powered on"));
1759         goto cleanup;
1760     }
1761 
1762     if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
1763         esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
1764                                     esxVI_Occurrence_RequiredItem,
1765                                     priv->parsedUri->autoAnswer, &taskInfoState,
1766                                     &taskInfoErrorMessage) < 0) {
1767         goto cleanup;
1768     }
1769 
1770     if (taskInfoState != esxVI_TaskInfoState_Success) {
1771         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
1772                        taskInfoErrorMessage);
1773         goto cleanup;
1774     }
1775 
1776     domain->id = -1;
1777     result = 0;
1778 
1779  cleanup:
1780     esxVI_ObjectContent_Free(&virtualMachine);
1781     esxVI_String_Free(&propertyNameList);
1782     esxVI_ManagedObjectReference_Free(&task);
1783     return result;
1784 }
1785 
1786 
1787 static int
esxDomainDestroy(virDomainPtr dom)1788 esxDomainDestroy(virDomainPtr dom)
1789 {
1790     return esxDomainDestroyFlags(dom, 0);
1791 }
1792 
1793 
1794 static char *
esxDomainGetOSType(virDomainPtr domain G_GNUC_UNUSED)1795 esxDomainGetOSType(virDomainPtr domain G_GNUC_UNUSED)
1796 {
1797     return g_strdup("hvm");
1798 }
1799 
1800 
1801 
1802 static unsigned long long
esxDomainGetMaxMemory(virDomainPtr domain)1803 esxDomainGetMaxMemory(virDomainPtr domain)
1804 {
1805     esxPrivate *priv = domain->conn->privateData;
1806     esxVI_String *propertyNameList = NULL;
1807     esxVI_ObjectContent *virtualMachine = NULL;
1808     esxVI_DynamicProperty *dynamicProperty = NULL;
1809     unsigned long memoryMB = 0;
1810 
1811     if (esxVI_EnsureSession(priv->primary) < 0)
1812         return 0;
1813 
1814     if (esxVI_String_AppendValueToList(&propertyNameList,
1815                                        "config.hardware.memoryMB") < 0 ||
1816         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
1817                                          propertyNameList, &virtualMachine,
1818                                          esxVI_Occurrence_RequiredItem) < 0) {
1819         goto cleanup;
1820     }
1821 
1822     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
1823          dynamicProperty = dynamicProperty->_next) {
1824         if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
1825             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
1826                                          esxVI_Type_Int) < 0) {
1827                 goto cleanup;
1828             }
1829 
1830             if (dynamicProperty->val->int32 < 0) {
1831                 virReportError(VIR_ERR_INTERNAL_ERROR,
1832                                _("Got invalid memory size %d"),
1833                                dynamicProperty->val->int32);
1834             } else {
1835                 memoryMB = dynamicProperty->val->int32;
1836             }
1837 
1838             break;
1839         } else {
1840             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
1841         }
1842     }
1843 
1844  cleanup:
1845     esxVI_String_Free(&propertyNameList);
1846     esxVI_ObjectContent_Free(&virtualMachine);
1847 
1848     return memoryMB * 1024; /* Scale from megabyte to kilobyte */
1849 }
1850 
1851 
1852 
1853 static int
esxDomainSetMaxMemory(virDomainPtr domain,unsigned long memory)1854 esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
1855 {
1856     int result = -1;
1857     esxPrivate *priv = domain->conn->privateData;
1858     esxVI_String *propertyNameList = NULL;
1859     esxVI_ObjectContent *virtualMachine = NULL;
1860     esxVI_VirtualMachinePowerState powerState;
1861     esxVI_VirtualMachineConfigSpec *spec = NULL;
1862     esxVI_ManagedObjectReference *task = NULL;
1863     esxVI_TaskInfoState taskInfoState;
1864     g_autofree char *taskInfoErrorMessage = NULL;
1865 
1866     if (esxVI_EnsureSession(priv->primary) < 0)
1867         return -1;
1868 
1869     if (esxVI_String_AppendValueToList(&propertyNameList,
1870                                        "runtime.powerState") < 0 ||
1871         esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1872           (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
1873            priv->parsedUri->autoAnswer) < 0 ||
1874         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
1875         goto cleanup;
1876     }
1877 
1878     if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
1879         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1880                        _("Domain is not powered off"));
1881         goto cleanup;
1882     }
1883 
1884     if (esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
1885         esxVI_Long_Alloc(&spec->memoryMB) < 0) {
1886         goto cleanup;
1887     }
1888 
1889     /* max-memory must be a multiple of 4096 kilobyte */
1890     spec->memoryMB->value =
1891       VIR_DIV_UP(memory, 4096) * 4; /* Scale from kilobytes to megabytes */
1892 
1893     if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
1894                               &task) < 0 ||
1895         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1896                                     esxVI_Occurrence_RequiredItem,
1897                                     priv->parsedUri->autoAnswer, &taskInfoState,
1898                                     &taskInfoErrorMessage) < 0) {
1899         goto cleanup;
1900     }
1901 
1902     if (taskInfoState != esxVI_TaskInfoState_Success) {
1903         virReportError(VIR_ERR_INTERNAL_ERROR,
1904                        _("Could not set max-memory to %lu kilobytes: %s"), memory,
1905                        taskInfoErrorMessage);
1906         goto cleanup;
1907     }
1908 
1909     result = 0;
1910 
1911  cleanup:
1912     esxVI_String_Free(&propertyNameList);
1913     esxVI_ObjectContent_Free(&virtualMachine);
1914     esxVI_VirtualMachineConfigSpec_Free(&spec);
1915     esxVI_ManagedObjectReference_Free(&task);
1916     return result;
1917 }
1918 
1919 
1920 
1921 static int
esxDomainSetMemoryFlags(virDomainPtr domain,unsigned long memory,unsigned int flags)1922 esxDomainSetMemoryFlags(virDomainPtr domain,
1923                         unsigned long memory,
1924                         unsigned int flags)
1925 {
1926     int result = -1;
1927     esxPrivate *priv = domain->conn->privateData;
1928     esxVI_ObjectContent *virtualMachine = NULL;
1929     esxVI_VirtualMachineConfigSpec *spec = NULL;
1930     esxVI_ManagedObjectReference *task = NULL;
1931     esxVI_TaskInfoState taskInfoState;
1932     g_autofree char *taskInfoErrorMessage = NULL;
1933 
1934     virCheckFlags(0, -1);
1935 
1936     if (esxVI_EnsureSession(priv->primary) < 0)
1937         return -1;
1938 
1939     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
1940           (priv->primary, domain->uuid, NULL, &virtualMachine,
1941            priv->parsedUri->autoAnswer) < 0 ||
1942         esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
1943         esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0 ||
1944         esxVI_Long_Alloc(&spec->memoryAllocation->limit) < 0) {
1945         goto cleanup;
1946     }
1947 
1948     spec->memoryAllocation->limit->value =
1949       VIR_DIV_UP(memory, 1024); /* Scale from kilobytes to megabytes */
1950 
1951     if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
1952                               &task) < 0 ||
1953         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
1954                                     esxVI_Occurrence_RequiredItem,
1955                                     priv->parsedUri->autoAnswer, &taskInfoState,
1956                                     &taskInfoErrorMessage) < 0) {
1957         goto cleanup;
1958     }
1959 
1960     if (taskInfoState != esxVI_TaskInfoState_Success) {
1961         virReportError(VIR_ERR_INTERNAL_ERROR,
1962                        _("Could not set memory to %lu kilobytes: %s"), memory,
1963                        taskInfoErrorMessage);
1964         goto cleanup;
1965     }
1966 
1967     result = 0;
1968 
1969  cleanup:
1970     esxVI_ObjectContent_Free(&virtualMachine);
1971     esxVI_VirtualMachineConfigSpec_Free(&spec);
1972     esxVI_ManagedObjectReference_Free(&task);
1973     return result;
1974 }
1975 
1976 
1977 static int
esxDomainSetMemory(virDomainPtr domain,unsigned long memory)1978 esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
1979 {
1980     return esxDomainSetMemoryFlags(domain, memory, 0);
1981 }
1982 
1983 
1984 /*
1985  * libvirt exposed virtual CPU usage in absolute time, ESX doesn't provide this
1986  * information in this format. It exposes it in 20 seconds slots, but it's hard
1987  * to get a reliable absolute time from this. Therefore, disable the code that
1988  * queries the performance counters here for now, but keep it as example for how
1989  * to query a selected performance counter for its values.
1990  */
1991 #define ESX_QUERY_FOR_USED_CPU_TIME 0
1992 
1993 static int
esxDomainGetInfo(virDomainPtr domain,virDomainInfoPtr info)1994 esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
1995 {
1996     int result = -1;
1997     esxPrivate *priv = domain->conn->privateData;
1998     esxVI_String *propertyNameList = NULL;
1999     esxVI_ObjectContent *virtualMachine = NULL;
2000     esxVI_DynamicProperty *dynamicProperty = NULL;
2001     esxVI_VirtualMachinePowerState powerState;
2002     int64_t memory_limit = -1;
2003 #if ESX_QUERY_FOR_USED_CPU_TIME
2004     esxVI_PerfMetricId *perfMetricId = NULL;
2005     esxVI_PerfMetricId *perfMetricIdList = NULL;
2006     esxVI_Int *counterId = NULL;
2007     esxVI_Int *counterIdList = NULL;
2008     esxVI_PerfCounterInfo *perfCounterInfo = NULL;
2009     esxVI_PerfCounterInfo *perfCounterInfoList = NULL;
2010     esxVI_PerfQuerySpec *querySpec = NULL;
2011     esxVI_PerfEntityMetricBase *perfEntityMetricBase = NULL;
2012     esxVI_PerfEntityMetricBase *perfEntityMetricBaseList = NULL;
2013     esxVI_PerfEntityMetric *perfEntityMetric = NULL;
2014     esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL;
2015     esxVI_Long *value = NULL;
2016 #endif
2017 
2018     memset(info, 0, sizeof(*info));
2019 
2020     if (esxVI_EnsureSession(priv->primary) < 0)
2021         return -1;
2022 
2023     if (esxVI_String_AppendValueListToList(&propertyNameList,
2024                                            "runtime.powerState\0"
2025                                            "config.hardware.memoryMB\0"
2026                                            "config.hardware.numCPU\0"
2027                                            "config.memoryAllocation.limit\0") < 0 ||
2028         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2029                                          propertyNameList, &virtualMachine,
2030                                          esxVI_Occurrence_RequiredItem) < 0) {
2031         goto cleanup;
2032     }
2033 
2034     info->state = VIR_DOMAIN_NOSTATE;
2035 
2036     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2037          dynamicProperty = dynamicProperty->_next) {
2038         if (STREQ(dynamicProperty->name, "runtime.powerState")) {
2039             if (esxVI_VirtualMachinePowerState_CastFromAnyType
2040                   (dynamicProperty->val, &powerState) < 0) {
2041                 goto cleanup;
2042             }
2043 
2044             info->state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
2045                             (powerState);
2046         } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) {
2047             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2048                                          esxVI_Type_Int) < 0) {
2049                 goto cleanup;
2050             }
2051 
2052             info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */
2053         } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) {
2054             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2055                                          esxVI_Type_Int) < 0) {
2056                 goto cleanup;
2057             }
2058 
2059             info->nrVirtCpu = dynamicProperty->val->int32;
2060         } else if (STREQ(dynamicProperty->name,
2061                          "config.memoryAllocation.limit")) {
2062             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2063                                          esxVI_Type_Long) < 0) {
2064                 goto cleanup;
2065             }
2066 
2067             memory_limit = dynamicProperty->val->int64;
2068 
2069             if (memory_limit > 0)
2070                 memory_limit *= 1024; /* Scale from megabyte to kilobyte */
2071         } else {
2072             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
2073         }
2074     }
2075 
2076     /* memory_limit < 0 means no memory limit is set */
2077     info->memory = memory_limit < 0 ? info->maxMem : memory_limit;
2078 
2079 #if ESX_QUERY_FOR_USED_CPU_TIME
2080     /* Verify the cached 'used CPU time' performance counter ID */
2081     /* FIXME: Currently no host for a vpx:// connection */
2082     if (priv->host) {
2083         if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
2084             if (esxVI_Int_Alloc(&counterId) < 0)
2085                 goto cleanup;
2086 
2087             counterId->value = priv->usedCpuTimeCounterId;
2088 
2089             if (esxVI_Int_AppendToList(&counterIdList, counterId) < 0)
2090                 goto cleanup;
2091 
2092             if (esxVI_QueryPerfCounter(priv->host, counterIdList,
2093                                        &perfCounterInfo) < 0) {
2094                 goto cleanup;
2095             }
2096 
2097             if (STRNEQ(perfCounterInfo->groupInfo->key, "cpu") ||
2098                 STRNEQ(perfCounterInfo->nameInfo->key, "used") ||
2099                 STRNEQ(perfCounterInfo->unitInfo->key, "millisecond")) {
2100                 VIR_DEBUG("Cached usedCpuTimeCounterId %d is invalid",
2101                           priv->usedCpuTimeCounterId);
2102 
2103                 priv->usedCpuTimeCounterId = -1;
2104             }
2105 
2106             esxVI_Int_Free(&counterIdList);
2107             esxVI_PerfCounterInfo_Free(&perfCounterInfo);
2108         }
2109 
2110         /*
2111          * Query the PerformanceManager for the 'used CPU time' performance
2112          * counter ID and cache it, if it's not already cached.
2113          */
2114         if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId < 0) {
2115             if (esxVI_QueryAvailablePerfMetric(priv->host, virtualMachine->obj,
2116                                                NULL, NULL, NULL,
2117                                                &perfMetricIdList) < 0) {
2118                 goto cleanup;
2119             }
2120 
2121             for (perfMetricId = perfMetricIdList; perfMetricId;
2122                  perfMetricId = perfMetricId->_next) {
2123                 VIR_DEBUG("perfMetricId counterId %d, instance '%s'",
2124                           perfMetricId->counterId->value, perfMetricId->instance);
2125 
2126                 counterId = NULL;
2127 
2128                 if (esxVI_Int_DeepCopy(&counterId, perfMetricId->counterId) < 0 ||
2129                     esxVI_Int_AppendToList(&counterIdList, counterId) < 0) {
2130                     goto cleanup;
2131                 }
2132             }
2133 
2134             if (esxVI_QueryPerfCounter(priv->host, counterIdList,
2135                                        &perfCounterInfoList) < 0) {
2136                 goto cleanup;
2137             }
2138 
2139             for (perfCounterInfo = perfCounterInfoList; perfCounterInfo;
2140                  perfCounterInfo = perfCounterInfo->_next) {
2141                 VIR_DEBUG("perfCounterInfo key %d, nameInfo '%s', groupInfo '%s', "
2142                           "unitInfo '%s', rollupType %d, statsType %d",
2143                           perfCounterInfo->key->value,
2144                           perfCounterInfo->nameInfo->key,
2145                           perfCounterInfo->groupInfo->key,
2146                           perfCounterInfo->unitInfo->key,
2147                           perfCounterInfo->rollupType,
2148                           perfCounterInfo->statsType);
2149 
2150                 if (STREQ(perfCounterInfo->groupInfo->key, "cpu") &&
2151                     STREQ(perfCounterInfo->nameInfo->key, "used") &&
2152                     STREQ(perfCounterInfo->unitInfo->key, "millisecond")) {
2153                     priv->usedCpuTimeCounterId = perfCounterInfo->key->value;
2154                     break;
2155                 }
2156             }
2157 
2158             if (priv->usedCpuTimeCounterId < 0)
2159                 VIR_WARN("Could not find 'used CPU time' performance counter");
2160         }
2161 
2162         /*
2163          * Query the PerformanceManager for the 'used CPU time' performance
2164          * counter value.
2165          */
2166         if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) {
2167             VIR_DEBUG("usedCpuTimeCounterId %d BEGIN", priv->usedCpuTimeCounterId);
2168 
2169             if (esxVI_PerfQuerySpec_Alloc(&querySpec) < 0 ||
2170                 esxVI_Int_Alloc(&querySpec->maxSample) < 0 ||
2171                 esxVI_PerfMetricId_Alloc(&querySpec->metricId) < 0 ||
2172                 esxVI_Int_Alloc(&querySpec->metricId->counterId) < 0) {
2173                 goto cleanup;
2174             }
2175 
2176             querySpec->entity = virtualMachine->obj;
2177             querySpec->maxSample->value = 1;
2178             querySpec->metricId->counterId->value = priv->usedCpuTimeCounterId;
2179             querySpec->metricId->instance = (char *)"";
2180             querySpec->format = (char *)"normal";
2181 
2182             if (esxVI_QueryPerf(priv->host, querySpec,
2183                                 &perfEntityMetricBaseList) < 0) {
2184                 goto cleanup;
2185             }
2186 
2187             for (perfEntityMetricBase = perfEntityMetricBaseList;
2188                  perfEntityMetricBase;
2189                  perfEntityMetricBase = perfEntityMetricBase->_next) {
2190                 VIR_DEBUG("perfEntityMetric ...");
2191 
2192                 perfEntityMetric =
2193                   esxVI_PerfEntityMetric_DynamicCast(perfEntityMetricBase);
2194 
2195                 if (!perfEntityMetric) {
2196                     virReportError(VIR_ERR_INTERNAL_ERROR,
2197                                    _("QueryPerf returned object with unexpected type '%s'"),
2198                                    esxVI_Type_ToString(perfEntityMetricBase->_type));
2199                     goto cleanup;
2200                 }
2201 
2202                 perfMetricIntSeries =
2203                   esxVI_PerfMetricIntSeries_DynamicCast(perfEntityMetric->value);
2204 
2205                 if (!perfMetricIntSeries) {
2206                     virReportError(VIR_ERR_INTERNAL_ERROR,
2207                                    _("QueryPerf returned object with unexpected type '%s'"),
2208                                    esxVI_Type_ToString(perfEntityMetric->value->_type));
2209                     goto cleanup;
2210                 }
2211 
2212                 for (; perfMetricIntSeries;
2213                      perfMetricIntSeries = perfMetricIntSeries->_next) {
2214                     VIR_DEBUG("perfMetricIntSeries ...");
2215 
2216                     for (value = perfMetricIntSeries->value;
2217                          value;
2218                          value = value->_next) {
2219                         VIR_DEBUG("value %lld", (long long int)value->value);
2220                     }
2221                 }
2222             }
2223 
2224             VIR_DEBUG("usedCpuTimeCounterId %d END", priv->usedCpuTimeCounterId);
2225 
2226             /*
2227              * FIXME: Cannot map between relative used-cpu-time and absolute
2228              *        info->cpuTime
2229              */
2230         }
2231     }
2232 #endif
2233 
2234     result = 0;
2235 
2236  cleanup:
2237 #if ESX_QUERY_FOR_USED_CPU_TIME
2238     /*
2239      * Remove values owned by data structures to prevent them from being freed
2240      * by the call to esxVI_PerfQuerySpec_Free().
2241      */
2242     if (querySpec) {
2243         querySpec->entity = NULL;
2244         querySpec->format = NULL;
2245 
2246         if (querySpec->metricId)
2247             querySpec->metricId->instance = NULL;
2248     }
2249 #endif
2250 
2251     esxVI_String_Free(&propertyNameList);
2252     esxVI_ObjectContent_Free(&virtualMachine);
2253 #if ESX_QUERY_FOR_USED_CPU_TIME
2254     esxVI_PerfMetricId_Free(&perfMetricIdList);
2255     esxVI_Int_Free(&counterIdList);
2256     esxVI_PerfCounterInfo_Free(&perfCounterInfoList);
2257     esxVI_PerfQuerySpec_Free(&querySpec);
2258     esxVI_PerfEntityMetricBase_Free(&perfEntityMetricBaseList);
2259 #endif
2260 
2261     return result;
2262 }
2263 
2264 
2265 
2266 static int
esxDomainGetState(virDomainPtr domain,int * state,int * reason,unsigned int flags)2267 esxDomainGetState(virDomainPtr domain,
2268                   int *state,
2269                   int *reason,
2270                   unsigned int flags)
2271 {
2272     int result = -1;
2273     esxPrivate *priv = domain->conn->privateData;
2274     esxVI_String *propertyNameList = NULL;
2275     esxVI_ObjectContent *virtualMachine = NULL;
2276     esxVI_VirtualMachinePowerState powerState;
2277 
2278     virCheckFlags(0, -1);
2279 
2280     if (esxVI_EnsureSession(priv->primary) < 0)
2281         return -1;
2282 
2283     if (esxVI_String_AppendValueToList(&propertyNameList,
2284                                        "runtime.powerState") < 0 ||
2285         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2286                                          propertyNameList, &virtualMachine,
2287                                          esxVI_Occurrence_RequiredItem) < 0 ||
2288         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
2289         goto cleanup;
2290     }
2291 
2292     *state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState);
2293 
2294     if (reason)
2295         *reason = 0;
2296 
2297     result = 0;
2298 
2299  cleanup:
2300     esxVI_String_Free(&propertyNameList);
2301     esxVI_ObjectContent_Free(&virtualMachine);
2302 
2303     return result;
2304 }
2305 
2306 
2307 
2308 static char *
esxDomainScreenshot(virDomainPtr domain,virStreamPtr stream,unsigned int screen,unsigned int flags)2309 esxDomainScreenshot(virDomainPtr domain, virStreamPtr stream,
2310                     unsigned int screen, unsigned int flags)
2311 {
2312     char *mimeType = NULL;
2313     esxPrivate *priv = domain->conn->privateData;
2314     esxVI_Boolean supportsScreenshot = esxVI_Boolean_Undefined;
2315     esxVI_String *propertyNameList = NULL;
2316     esxVI_ObjectContent *virtualMachine = NULL;
2317     esxVI_VirtualMachinePowerState powerState;
2318     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
2319     char *url = NULL;
2320 
2321     virCheckFlags(0, NULL);
2322 
2323     if (screen != 0) {
2324         virReportError(VIR_ERR_INVALID_ARG, "%s",
2325                        _("Screen cannot be selected"));
2326         return NULL;
2327     }
2328 
2329     supportsScreenshot = esxSupportsScreenshot(priv);
2330 
2331     if (supportsScreenshot == esxVI_Boolean_Undefined)
2332         return NULL;
2333 
2334     if (supportsScreenshot != esxVI_Boolean_True) {
2335         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2336                        _("Screenshot feature is unsupported"));
2337         return NULL;
2338     }
2339 
2340     if (esxVI_EnsureSession(priv->primary) < 0)
2341         return NULL;
2342 
2343     if (esxVI_String_AppendValueToList(&propertyNameList,
2344                                        "runtime.powerState") < 0 ||
2345         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2346                                          propertyNameList, &virtualMachine,
2347                                          esxVI_Occurrence_RequiredItem) < 0 ||
2348         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0)
2349         goto cleanup;
2350 
2351     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
2352         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2353                        _("Domain is not powered on"));
2354         goto cleanup;
2355     }
2356 
2357     /* Build URL */
2358     virBufferAsprintf(&buffer, "%s://%s:%d/screen?id=", priv->parsedUri->transport,
2359                       domain->conn->uri->server, domain->conn->uri->port);
2360     virBufferURIEncodeString(&buffer, virtualMachine->obj->value);
2361 
2362     url = virBufferContentAndReset(&buffer);
2363 
2364     if (esxStreamOpenDownload(stream, priv, url, 0, 0) < 0)
2365         goto cleanup;
2366 
2367     mimeType = g_strdup("image/png");
2368 
2369  cleanup:
2370 
2371     esxVI_String_Free(&propertyNameList);
2372     esxVI_ObjectContent_Free(&virtualMachine);
2373 
2374     return mimeType;
2375 }
2376 
2377 
2378 
2379 static int
esxDomainSetVcpusFlags(virDomainPtr domain,unsigned int nvcpus,unsigned int flags)2380 esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
2381                        unsigned int flags)
2382 {
2383     int result = -1;
2384     esxPrivate *priv = domain->conn->privateData;
2385     int maxVcpus;
2386     esxVI_ObjectContent *virtualMachine = NULL;
2387     esxVI_VirtualMachineConfigSpec *spec = NULL;
2388     esxVI_ManagedObjectReference *task = NULL;
2389     esxVI_TaskInfoState taskInfoState;
2390     g_autofree char *taskInfoErrorMessage = NULL;
2391 
2392     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE, -1);
2393 
2394     if (nvcpus < 1) {
2395         virReportError(VIR_ERR_INVALID_ARG, "%s",
2396                        _("Requested number of virtual CPUs must at least be 1"));
2397         return -1;
2398     }
2399 
2400     if (esxVI_EnsureSession(priv->primary) < 0)
2401         return -1;
2402 
2403     maxVcpus = esxDomainGetMaxVcpus(domain);
2404 
2405     if (maxVcpus < 0)
2406         return -1;
2407 
2408     if (nvcpus > maxVcpus) {
2409         virReportError(VIR_ERR_INVALID_ARG,
2410                        _("Requested number of virtual CPUs is greater than max "
2411                          "allowable number of virtual CPUs for the domain: %d > %d"),
2412                        nvcpus, maxVcpus);
2413         return -1;
2414     }
2415 
2416     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2417           (priv->primary, domain->uuid, NULL, &virtualMachine,
2418            priv->parsedUri->autoAnswer) < 0 ||
2419         esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
2420         esxVI_Int_Alloc(&spec->numCPUs) < 0) {
2421         goto cleanup;
2422     }
2423 
2424     spec->numCPUs->value = nvcpus;
2425 
2426     if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
2427                               &task) < 0 ||
2428         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2429                                     esxVI_Occurrence_RequiredItem,
2430                                     priv->parsedUri->autoAnswer, &taskInfoState,
2431                                     &taskInfoErrorMessage) < 0) {
2432         goto cleanup;
2433     }
2434 
2435     if (taskInfoState != esxVI_TaskInfoState_Success) {
2436         virReportError(VIR_ERR_INTERNAL_ERROR,
2437                        _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
2438                        taskInfoErrorMessage);
2439         goto cleanup;
2440     }
2441 
2442     result = 0;
2443 
2444  cleanup:
2445     esxVI_ObjectContent_Free(&virtualMachine);
2446     esxVI_VirtualMachineConfigSpec_Free(&spec);
2447     esxVI_ManagedObjectReference_Free(&task);
2448     return result;
2449 }
2450 
2451 
2452 
2453 static int
esxDomainSetVcpus(virDomainPtr domain,unsigned int nvcpus)2454 esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
2455 {
2456     return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2457 }
2458 
2459 
2460 
2461 static int
esxDomainGetVcpusFlags(virDomainPtr domain,unsigned int flags)2462 esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
2463 {
2464     esxPrivate *priv = domain->conn->privateData;
2465     esxVI_String *propertyNameList = NULL;
2466     esxVI_ObjectContent *hostSystem = NULL;
2467     esxVI_DynamicProperty *dynamicProperty = NULL;
2468 
2469     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2470                   VIR_DOMAIN_VCPU_MAXIMUM, -1);
2471 
2472     if (priv->maxVcpus > 0)
2473         return priv->maxVcpus;
2474 
2475     priv->maxVcpus = -1;
2476 
2477     if (esxVI_EnsureSession(priv->primary) < 0)
2478         return -1;
2479 
2480     if (esxVI_String_AppendValueToList(&propertyNameList,
2481                                        "capability.maxSupportedVcpus") < 0 ||
2482         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
2483                                          &hostSystem) < 0) {
2484         goto cleanup;
2485     }
2486 
2487     for (dynamicProperty = hostSystem->propSet; dynamicProperty;
2488          dynamicProperty = dynamicProperty->_next) {
2489         if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) {
2490             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2491                                          esxVI_Type_Int) < 0) {
2492                 goto cleanup;
2493             }
2494 
2495             priv->maxVcpus = dynamicProperty->val->int32;
2496             break;
2497         } else {
2498             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
2499         }
2500     }
2501 
2502  cleanup:
2503     esxVI_String_Free(&propertyNameList);
2504     esxVI_ObjectContent_Free(&hostSystem);
2505 
2506     return priv->maxVcpus;
2507 }
2508 
2509 
2510 
2511 static int
esxDomainGetMaxVcpus(virDomainPtr domain)2512 esxDomainGetMaxVcpus(virDomainPtr domain)
2513 {
2514     return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
2515                                            VIR_DOMAIN_VCPU_MAXIMUM));
2516 }
2517 
2518 
2519 
2520 static char *
esxDomainGetXMLDesc(virDomainPtr domain,unsigned int flags)2521 esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
2522 {
2523     esxPrivate *priv = domain->conn->privateData;
2524     esxVI_String *propertyNameList = NULL;
2525     esxVI_ObjectContent *virtualMachine = NULL;
2526     esxVI_VirtualMachinePowerState powerState;
2527     int id;
2528     g_autofree char *moref = NULL;
2529     char *vmPathName = NULL;
2530     g_autofree char *datastoreName = NULL;
2531     g_autofree char *directoryName = NULL;
2532     g_autofree char *directoryAndFileName = NULL;
2533     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
2534     g_autofree char *url = NULL;
2535     g_autofree char *vmx = NULL;
2536     virVMXContext ctx;
2537     esxVMX_Data data;
2538     virDomainDef *def = NULL;
2539     char *xml = NULL;
2540 
2541     virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
2542 
2543     memset(&data, 0, sizeof(data));
2544 
2545     if (esxVI_EnsureSession(priv->primary) < 0)
2546         return NULL;
2547 
2548     if (esxVI_String_AppendValueListToList(&propertyNameList,
2549                                            "config.files.vmPathName\0"
2550                                            "runtime.powerState\0") < 0 ||
2551         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
2552                                          propertyNameList, &virtualMachine,
2553                                          esxVI_Occurrence_RequiredItem) < 0 ||
2554         esxVI_GetVirtualMachineMORef(virtualMachine, &moref) < 0 ||
2555         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
2556         esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0 ||
2557         esxVI_GetStringValue(virtualMachine, "config.files.vmPathName",
2558                              &vmPathName, esxVI_Occurrence_RequiredItem) < 0) {
2559         goto cleanup;
2560     }
2561 
2562     if (esxUtil_ParseDatastorePath(vmPathName, &datastoreName, &directoryName,
2563                                    &directoryAndFileName) < 0) {
2564         goto cleanup;
2565     }
2566 
2567     virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
2568                       domain->conn->uri->server, domain->conn->uri->port);
2569     virBufferURIEncodeString(&buffer, directoryAndFileName);
2570     virBufferAddLit(&buffer, "?dcPath=");
2571     virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
2572     virBufferAddLit(&buffer, "&dsName=");
2573     virBufferURIEncodeString(&buffer, datastoreName);
2574 
2575     url = virBufferContentAndReset(&buffer);
2576 
2577     if (esxVI_CURL_Download(priv->primary->curl, url, &vmx, 0, NULL) < 0)
2578         goto cleanup;
2579 
2580     data.ctx = priv->primary;
2581 
2582     if (!directoryName) {
2583         data.datastorePathWithoutFileName = g_strdup_printf("[%s]", datastoreName);
2584     } else {
2585         data.datastorePathWithoutFileName = g_strdup_printf("[%s] %s",
2586                                                             datastoreName, directoryName);
2587     }
2588 
2589     ctx.opaque = &data;
2590     ctx.parseFileName = esxParseVMXFileName;
2591     ctx.formatFileName = NULL;
2592     ctx.autodetectSCSIControllerModel = NULL;
2593     ctx.datacenterPath = priv->primary->datacenterPath;
2594     ctx.moref = moref;
2595 
2596     def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, vmx);
2597 
2598     if (def) {
2599         if (powerState != esxVI_VirtualMachinePowerState_PoweredOff)
2600             def->id = id;
2601 
2602         xml = virDomainDefFormat(def, priv->xmlopt,
2603                                  virDomainDefFormatConvertXMLFlags(flags));
2604     }
2605 
2606  cleanup:
2607     esxVI_String_Free(&propertyNameList);
2608     esxVI_ObjectContent_Free(&virtualMachine);
2609     g_free(data.datastorePathWithoutFileName);
2610     virDomainDefFree(def);
2611 
2612     return xml;
2613 }
2614 
2615 
2616 
2617 static char *
esxConnectDomainXMLFromNative(virConnectPtr conn,const char * nativeFormat,const char * nativeConfig,unsigned int flags)2618 esxConnectDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat,
2619                               const char *nativeConfig,
2620                               unsigned int flags)
2621 {
2622     esxPrivate *priv = conn->privateData;
2623     virVMXContext ctx;
2624     esxVMX_Data data;
2625     virDomainDef *def = NULL;
2626     char *xml = NULL;
2627 
2628     virCheckFlags(0, NULL);
2629 
2630     memset(&data, 0, sizeof(data));
2631 
2632     if (STRNEQ(nativeFormat, VMX_CONFIG_FORMAT_ARGV)) {
2633         virReportError(VIR_ERR_INVALID_ARG,
2634                        _("Unsupported config format '%s'"), nativeFormat);
2635         return NULL;
2636     }
2637 
2638     data.ctx = priv->primary;
2639     data.datastorePathWithoutFileName = (char *)"[?] ?";
2640 
2641     ctx.opaque = &data;
2642     ctx.parseFileName = esxParseVMXFileName;
2643     ctx.formatFileName = NULL;
2644     ctx.autodetectSCSIControllerModel = NULL;
2645     ctx.datacenterPath = NULL;
2646     ctx.moref = NULL;
2647 
2648     def = virVMXParseConfig(&ctx, priv->xmlopt, priv->caps, nativeConfig);
2649 
2650     if (def)
2651         xml = virDomainDefFormat(def, priv->xmlopt,
2652                                  VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2653 
2654     virDomainDefFree(def);
2655 
2656     return xml;
2657 }
2658 
2659 
2660 
2661 static char *
esxConnectDomainXMLToNative(virConnectPtr conn,const char * nativeFormat,const char * domainXml,unsigned int flags)2662 esxConnectDomainXMLToNative(virConnectPtr conn, const char *nativeFormat,
2663                             const char *domainXml,
2664                             unsigned int flags)
2665 {
2666     esxPrivate *priv = conn->privateData;
2667     int virtualHW_version;
2668     virVMXContext ctx;
2669     esxVMX_Data data;
2670     virDomainDef *def = NULL;
2671     char *vmx = NULL;
2672 
2673     virCheckFlags(0, NULL);
2674 
2675     memset(&data, 0, sizeof(data));
2676 
2677     if (STRNEQ(nativeFormat, VMX_CONFIG_FORMAT_ARGV)) {
2678         virReportError(VIR_ERR_INVALID_ARG,
2679                        _("Unsupported config format '%s'"), nativeFormat);
2680         return NULL;
2681     }
2682 
2683     virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
2684                           (priv->primary->productLine, priv->primary->productVersion);
2685 
2686     if (virtualHW_version < 0)
2687         return NULL;
2688 
2689     def = virDomainDefParseString(domainXml, priv->xmlopt,
2690                                   NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE);
2691 
2692     if (!def)
2693         return NULL;
2694 
2695     data.ctx = priv->primary;
2696     data.datastorePathWithoutFileName = NULL;
2697 
2698     ctx.opaque = &data;
2699     ctx.parseFileName = NULL;
2700     ctx.formatFileName = esxFormatVMXFileName;
2701     ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
2702     ctx.datacenterPath = NULL;
2703     ctx.moref = NULL;
2704 
2705     vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
2706 
2707     virDomainDefFree(def);
2708 
2709     return vmx;
2710 }
2711 
2712 
2713 
2714 static int
esxConnectListDefinedDomains(virConnectPtr conn,char ** const names,int maxnames)2715 esxConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
2716 {
2717     bool success = false;
2718     esxPrivate *priv = conn->privateData;
2719     esxVI_String *propertyNameList = NULL;
2720     esxVI_ObjectContent *virtualMachineList = NULL;
2721     esxVI_ObjectContent *virtualMachine = NULL;
2722     esxVI_VirtualMachinePowerState powerState;
2723     int count = 0;
2724     size_t i;
2725 
2726     if (maxnames == 0)
2727         return 0;
2728 
2729     if (esxVI_EnsureSession(priv->primary) < 0)
2730         return -1;
2731 
2732     if (esxVI_String_AppendValueListToList(&propertyNameList,
2733                                            "name\0"
2734                                            "runtime.powerState\0") < 0 ||
2735         esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
2736                                        &virtualMachineList) < 0) {
2737         goto cleanup;
2738     }
2739 
2740     for (virtualMachine = virtualMachineList; virtualMachine;
2741          virtualMachine = virtualMachine->_next) {
2742         if (esxVI_GetVirtualMachinePowerState(virtualMachine,
2743                                               &powerState) < 0) {
2744             goto cleanup;
2745         }
2746 
2747         if (powerState == esxVI_VirtualMachinePowerState_PoweredOn)
2748             continue;
2749 
2750         names[count] = NULL;
2751 
2752         if (esxVI_GetVirtualMachineIdentity(virtualMachine, NULL, &names[count],
2753                                             NULL) < 0) {
2754             goto cleanup;
2755         }
2756 
2757         ++count;
2758 
2759         if (count >= maxnames)
2760             break;
2761     }
2762 
2763     success = true;
2764 
2765  cleanup:
2766     if (! success) {
2767         for (i = 0; i < count; ++i)
2768             VIR_FREE(names[i]);
2769 
2770         count = -1;
2771     }
2772 
2773     esxVI_String_Free(&propertyNameList);
2774     esxVI_ObjectContent_Free(&virtualMachineList);
2775 
2776     return count;
2777 }
2778 
2779 
2780 
2781 static int
esxConnectNumOfDefinedDomains(virConnectPtr conn)2782 esxConnectNumOfDefinedDomains(virConnectPtr conn)
2783 {
2784     esxPrivate *priv = conn->privateData;
2785 
2786     if (esxVI_EnsureSession(priv->primary) < 0)
2787         return -1;
2788 
2789     return esxVI_LookupNumberOfDomainsByPowerState
2790              (priv->primary, esxVI_VirtualMachinePowerState_PoweredOn, true);
2791 }
2792 
2793 
2794 
2795 static int
esxDomainCreateWithFlags(virDomainPtr domain,unsigned int flags)2796 esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
2797 {
2798     int result = -1;
2799     esxPrivate *priv = domain->conn->privateData;
2800     esxVI_ObjectContent *virtualMachine = NULL;
2801     esxVI_String *propertyNameList = NULL;
2802     esxVI_VirtualMachinePowerState powerState;
2803     int id = -1;
2804     esxVI_ManagedObjectReference *task = NULL;
2805     esxVI_TaskInfoState taskInfoState;
2806     g_autofree char *taskInfoErrorMessage = NULL;
2807 
2808     virCheckFlags(0, -1);
2809 
2810     if (esxVI_EnsureSession(priv->primary) < 0)
2811         return -1;
2812 
2813     if (esxVI_String_AppendValueToList(&propertyNameList,
2814                                        "runtime.powerState") < 0 ||
2815         esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2816           (priv->primary, domain->uuid, propertyNameList, &virtualMachine,
2817            priv->parsedUri->autoAnswer) < 0 ||
2818         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0 ||
2819         esxVI_GetVirtualMachineIdentity(virtualMachine, &id, NULL, NULL) < 0) {
2820         goto cleanup;
2821     }
2822 
2823     if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
2824         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2825                        _("Domain is not powered off"));
2826         goto cleanup;
2827     }
2828 
2829     if (esxVI_PowerOnVM_Task(priv->primary, virtualMachine->obj, NULL,
2830                              &task) < 0 ||
2831         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
2832                                     esxVI_Occurrence_RequiredItem,
2833                                     priv->parsedUri->autoAnswer, &taskInfoState,
2834                                     &taskInfoErrorMessage) < 0) {
2835         goto cleanup;
2836     }
2837 
2838     if (taskInfoState != esxVI_TaskInfoState_Success) {
2839         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
2840                        taskInfoErrorMessage);
2841         goto cleanup;
2842     }
2843 
2844     domain->id = id;
2845     result = 0;
2846 
2847  cleanup:
2848     esxVI_ObjectContent_Free(&virtualMachine);
2849     esxVI_String_Free(&propertyNameList);
2850     esxVI_ManagedObjectReference_Free(&task);
2851 
2852     return result;
2853 }
2854 
2855 
2856 
2857 static int
esxDomainCreate(virDomainPtr domain)2858 esxDomainCreate(virDomainPtr domain)
2859 {
2860     return esxDomainCreateWithFlags(domain, 0);
2861 }
2862 
2863 
2864 
2865 static virDomainPtr
esxDomainDefineXMLFlags(virConnectPtr conn,const char * xml,unsigned int flags)2866 esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
2867 {
2868     esxPrivate *priv = conn->privateData;
2869     virDomainDef *def = NULL;
2870     g_autofree char *vmx = NULL;
2871     size_t i;
2872     virDomainDiskDef *disk = NULL;
2873     esxVI_ObjectContent *virtualMachine = NULL;
2874     int virtualHW_version;
2875     virVMXContext ctx;
2876     esxVMX_Data data;
2877     g_autofree char *datastoreName = NULL;
2878     g_autofree char *directoryName = NULL;
2879     g_autofree char *escapedName = NULL;
2880     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
2881     g_autofree char *url = NULL;
2882     g_autofree char *datastoreRelatedPath = NULL;
2883     esxVI_String *propertyNameList = NULL;
2884     esxVI_ObjectContent *hostSystem = NULL;
2885     esxVI_ManagedObjectReference *resourcePool = NULL;
2886     esxVI_ManagedObjectReference *task = NULL;
2887     esxVI_TaskInfoState taskInfoState;
2888     g_autofree char *taskInfoErrorMessage = NULL;
2889     virDomainPtr domain = NULL;
2890     const char *src;
2891     unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
2892 
2893     virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
2894 
2895     if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2896         parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2897 
2898     memset(&data, 0, sizeof(data));
2899 
2900     if (esxVI_EnsureSession(priv->primary) < 0)
2901         return NULL;
2902 
2903     /* Parse domain XML */
2904     def = virDomainDefParseString(xml, priv->xmlopt,
2905                                   NULL, parse_flags);
2906 
2907     if (!def)
2908         return NULL;
2909 
2910     if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
2911         goto cleanup;
2912 
2913     /* Check if an existing domain should be edited */
2914     if (esxVI_LookupVirtualMachineByUuid(priv->primary, def->uuid, NULL,
2915                                          &virtualMachine,
2916                                          esxVI_Occurrence_OptionalItem) < 0) {
2917         goto cleanup;
2918     }
2919 
2920     if (!virtualMachine &&
2921         esxVI_LookupVirtualMachineByName(priv->primary, def->name, NULL,
2922                                          &virtualMachine,
2923                                          esxVI_Occurrence_OptionalItem) < 0) {
2924         goto cleanup;
2925     }
2926 
2927     if (virtualMachine) {
2928         /* FIXME */
2929         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2930                        _("Domain already exists, editing existing domains is not "
2931                          "supported yet"));
2932         goto cleanup;
2933     }
2934 
2935     /* Build VMX from domain XML */
2936     virtualHW_version = esxVI_ProductVersionToDefaultVirtualHWVersion
2937                           (priv->primary->productLine, priv->primary->productVersion);
2938 
2939     if (virtualHW_version < 0)
2940         goto cleanup;
2941 
2942     data.ctx = priv->primary;
2943     data.datastorePathWithoutFileName = NULL;
2944 
2945     ctx.opaque = &data;
2946     ctx.parseFileName = NULL;
2947     ctx.formatFileName = esxFormatVMXFileName;
2948     ctx.autodetectSCSIControllerModel = esxAutodetectSCSIControllerModel;
2949     ctx.datacenterPath = NULL;
2950     ctx.moref = NULL;
2951 
2952     vmx = virVMXFormatConfig(&ctx, priv->xmlopt, def, virtualHW_version);
2953 
2954     if (!vmx)
2955         goto cleanup;
2956 
2957     /*
2958      * Build VMX datastore URL. Use the source of the first file-based harddisk
2959      * to deduce the datastore and path for the VMX file. Don't just use the
2960      * first disk, because it may be CDROM disk and ISO images are normally not
2961      * located in the virtual machine's directory. This approach to deduce the
2962      * datastore isn't perfect but should work in the majority of cases.
2963      */
2964     if (def->ndisks < 1) {
2965         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2966                        _("Domain XML doesn't contain any disks, cannot deduce "
2967                          "datastore and path for VMX file"));
2968         goto cleanup;
2969     }
2970 
2971     for (i = 0; i < def->ndisks; ++i) {
2972         if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
2973             virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_FILE) {
2974             disk = def->disks[i];
2975             break;
2976         }
2977     }
2978 
2979     if (!disk) {
2980         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2981                        _("Domain XML doesn't contain any file-based harddisks, "
2982                          "cannot deduce datastore and path for VMX file"));
2983         goto cleanup;
2984     }
2985 
2986     src = virDomainDiskGetSource(disk);
2987     if (!src) {
2988         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2989                        _("First file-based harddisk has no source, cannot deduce "
2990                          "datastore and path for VMX file"));
2991         goto cleanup;
2992     }
2993 
2994     if (esxUtil_ParseDatastorePath(src, &datastoreName, &directoryName,
2995                                    NULL) < 0) {
2996         goto cleanup;
2997     }
2998 
2999     if (!virStringHasCaseSuffix(src, ".vmdk")) {
3000         virReportError(VIR_ERR_INTERNAL_ERROR,
3001                        _("Expecting source '%s' of first file-based harddisk to "
3002                          "be a VMDK image"), src);
3003         goto cleanup;
3004     }
3005 
3006     virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport,
3007                       conn->uri->server, conn->uri->port);
3008 
3009     if (directoryName) {
3010         virBufferURIEncodeString(&buffer, directoryName);
3011         virBufferAddChar(&buffer, '/');
3012     }
3013 
3014     escapedName = esxUtil_EscapeDatastoreItem(def->name);
3015 
3016     if (!escapedName)
3017         goto cleanup;
3018 
3019     virBufferURIEncodeString(&buffer, escapedName);
3020     virBufferAddLit(&buffer, ".vmx?dcPath=");
3021     virBufferURIEncodeString(&buffer, priv->primary->datacenterPath);
3022     virBufferAddLit(&buffer, "&dsName=");
3023     virBufferURIEncodeString(&buffer, datastoreName);
3024 
3025     url = virBufferContentAndReset(&buffer);
3026 
3027     /* Check, if VMX file already exists */
3028     /* FIXME */
3029 
3030     /* Upload VMX file */
3031     VIR_DEBUG("Uploading .vmx config, url='%s' vmx='%s'", url, vmx);
3032 
3033     if (esxVI_CURL_Upload(priv->primary->curl, url, vmx) < 0)
3034         goto cleanup;
3035 
3036     /* Register the domain */
3037     if (directoryName) {
3038         datastoreRelatedPath = g_strdup_printf("[%s] %s/%s.vmx", datastoreName,
3039                                                directoryName, escapedName);
3040     } else {
3041         datastoreRelatedPath = g_strdup_printf("[%s] %s.vmx", datastoreName,
3042                                                escapedName);
3043     }
3044 
3045     if (esxVI_RegisterVM_Task(priv->primary, priv->primary->datacenter->vmFolder,
3046                               datastoreRelatedPath, NULL, esxVI_Boolean_False,
3047                               priv->primary->computeResource->resourcePool,
3048                               priv->primary->hostSystem->_reference,
3049                               &task) < 0 ||
3050         esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
3051                                     esxVI_Occurrence_OptionalItem,
3052                                     priv->parsedUri->autoAnswer, &taskInfoState,
3053                                     &taskInfoErrorMessage) < 0) {
3054         goto cleanup;
3055     }
3056 
3057     if (taskInfoState != esxVI_TaskInfoState_Success) {
3058         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
3059                        taskInfoErrorMessage);
3060         goto cleanup;
3061     }
3062 
3063     domain = virGetDomain(conn, def->name, def->uuid, -1);
3064 
3065     /* FIXME: Add proper rollback in case of an error */
3066 
3067  cleanup:
3068     virDomainDefFree(def);
3069     esxVI_ObjectContent_Free(&virtualMachine);
3070     esxVI_String_Free(&propertyNameList);
3071     esxVI_ObjectContent_Free(&hostSystem);
3072     esxVI_ManagedObjectReference_Free(&resourcePool);
3073     esxVI_ManagedObjectReference_Free(&task);
3074     return domain;
3075 }
3076 
3077 static virDomainPtr
esxDomainDefineXML(virConnectPtr conn,const char * xml)3078 esxDomainDefineXML(virConnectPtr conn, const char *xml)
3079 {
3080     return esxDomainDefineXMLFlags(conn, xml, 0);
3081 }
3082 
3083 static int
esxDomainUndefineFlags(virDomainPtr domain,unsigned int flags)3084 esxDomainUndefineFlags(virDomainPtr domain,
3085                        unsigned int flags)
3086 {
3087     int result = -1;
3088     esxPrivate *priv = domain->conn->privateData;
3089     esxVI_Context *ctx = NULL;
3090     esxVI_ObjectContent *virtualMachine = NULL;
3091     esxVI_String *propertyNameList = NULL;
3092     esxVI_VirtualMachinePowerState powerState;
3093 
3094     /* No managed save, so we explicitly reject
3095      * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
3096      * ESX, so we can trivially ignore that flag.  */
3097     virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
3098 
3099     if (priv->vCenter) {
3100         ctx = priv->vCenter;
3101     } else {
3102         ctx = priv->host;
3103     }
3104 
3105     if (esxVI_EnsureSession(ctx) < 0)
3106         return -1;
3107 
3108     if (esxVI_String_AppendValueToList(&propertyNameList,
3109                                        "runtime.powerState") < 0 ||
3110         esxVI_LookupVirtualMachineByUuid(ctx, domain->uuid, propertyNameList,
3111                                          &virtualMachine,
3112                                          esxVI_Occurrence_RequiredItem) < 0 ||
3113         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
3114         goto cleanup;
3115     }
3116 
3117     if (powerState != esxVI_VirtualMachinePowerState_Suspended &&
3118         powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3119         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3120                        _("Domain is not suspended or powered off"));
3121         goto cleanup;
3122     }
3123 
3124     if (esxVI_UnregisterVM(ctx, virtualMachine->obj) < 0)
3125         goto cleanup;
3126 
3127     result = 0;
3128 
3129  cleanup:
3130     esxVI_ObjectContent_Free(&virtualMachine);
3131     esxVI_String_Free(&propertyNameList);
3132 
3133     return result;
3134 }
3135 
3136 
3137 static int
esxDomainUndefine(virDomainPtr domain)3138 esxDomainUndefine(virDomainPtr domain)
3139 {
3140     return esxDomainUndefineFlags(domain, 0);
3141 }
3142 
3143 static int
esxDomainGetAutostart(virDomainPtr domain,int * autostart)3144 esxDomainGetAutostart(virDomainPtr domain, int *autostart)
3145 {
3146     int result = -1;
3147     esxPrivate *priv = domain->conn->privateData;
3148     esxVI_AutoStartDefaults *defaults = NULL;
3149     esxVI_String *propertyNameList = NULL;
3150     esxVI_AutoStartPowerInfo *powerInfo = NULL;
3151     esxVI_AutoStartPowerInfo *powerInfoList = NULL;
3152     esxVI_ObjectContent *virtualMachine = NULL;
3153 
3154     *autostart = 0;
3155 
3156     if (esxVI_EnsureSession(priv->primary) < 0)
3157         return -1;
3158 
3159     /* Check general autostart config */
3160     if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0)
3161         goto cleanup;
3162 
3163     if (defaults->enabled != esxVI_Boolean_True) {
3164         /* Autostart is disabled in general, exit early here */
3165         result = 0;
3166         goto cleanup;
3167     }
3168 
3169     /* Check specific autostart config */
3170     if (esxVI_LookupAutoStartPowerInfoList(priv->primary, &powerInfoList) < 0)
3171         goto cleanup;
3172 
3173     if (!powerInfoList) {
3174         /* powerInfo list is empty, exit early here */
3175         result = 0;
3176         goto cleanup;
3177     }
3178 
3179     if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3180                                          NULL, &virtualMachine,
3181                                          esxVI_Occurrence_RequiredItem) < 0) {
3182         goto cleanup;
3183     }
3184 
3185     for (powerInfo = powerInfoList; powerInfo;
3186          powerInfo = powerInfo->_next) {
3187         if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
3188             if (STRCASEEQ(powerInfo->startAction, "powerOn"))
3189                 *autostart = 1;
3190 
3191             break;
3192         }
3193     }
3194 
3195     result = 0;
3196 
3197  cleanup:
3198     esxVI_String_Free(&propertyNameList);
3199     esxVI_AutoStartDefaults_Free(&defaults);
3200     esxVI_AutoStartPowerInfo_Free(&powerInfoList);
3201     esxVI_ObjectContent_Free(&virtualMachine);
3202 
3203     return result;
3204 }
3205 
3206 
3207 
3208 static int
esxDomainSetAutostart(virDomainPtr domain,int autostart)3209 esxDomainSetAutostart(virDomainPtr domain, int autostart)
3210 {
3211     int result = -1;
3212     esxPrivate *priv = domain->conn->privateData;
3213     esxVI_ObjectContent *virtualMachine = NULL;
3214     esxVI_HostAutoStartManagerConfig *spec = NULL;
3215     esxVI_AutoStartDefaults *defaults = NULL;
3216     esxVI_AutoStartPowerInfo *powerInfoList = NULL;
3217     esxVI_AutoStartPowerInfo *powerInfo = NULL;
3218     esxVI_AutoStartPowerInfo *newPowerInfo = NULL;
3219 
3220     if (esxVI_EnsureSession(priv->primary) < 0)
3221         return -1;
3222 
3223     if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3224                                          NULL, &virtualMachine,
3225                                          esxVI_Occurrence_RequiredItem) < 0 ||
3226         esxVI_HostAutoStartManagerConfig_Alloc(&spec) < 0) {
3227         goto cleanup;
3228     }
3229 
3230     if (autostart) {
3231         /*
3232          * There is a general autostart option that affects the autostart
3233          * behavior of all domains. If it's disabled then no domain does
3234          * autostart. If it's enabled then the autostart behavior depends on
3235          * the per-domain autostart config.
3236          */
3237         if (esxVI_LookupAutoStartDefaults(priv->primary, &defaults) < 0)
3238             goto cleanup;
3239 
3240         if (defaults->enabled != esxVI_Boolean_True) {
3241             /*
3242              * Autostart is disabled in general. Check if no other domain is
3243              * in the list of autostarted domains, so it's safe to enable the
3244              * general autostart option without affecting the autostart
3245              * behavior of other domains.
3246              */
3247             if (esxVI_LookupAutoStartPowerInfoList(priv->primary,
3248                                                    &powerInfoList) < 0) {
3249                 goto cleanup;
3250             }
3251 
3252             for (powerInfo = powerInfoList; powerInfo;
3253                  powerInfo = powerInfo->_next) {
3254                 if (STRNEQ(powerInfo->key->value, virtualMachine->obj->value)) {
3255                     virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3256                                    _("Cannot enable general autostart option "
3257                                      "without affecting other domains"));
3258                     goto cleanup;
3259                 }
3260             }
3261 
3262             /* Enable autostart in general */
3263             if (esxVI_AutoStartDefaults_Alloc(&spec->defaults) < 0)
3264                 goto cleanup;
3265 
3266             spec->defaults->enabled = esxVI_Boolean_True;
3267         }
3268     }
3269 
3270     if (esxVI_AutoStartPowerInfo_Alloc(&newPowerInfo) < 0 ||
3271         esxVI_Int_Alloc(&newPowerInfo->startOrder) < 0 ||
3272         esxVI_Int_Alloc(&newPowerInfo->startDelay) < 0 ||
3273         esxVI_Int_Alloc(&newPowerInfo->stopDelay) < 0 ||
3274         esxVI_AutoStartPowerInfo_AppendToList(&spec->powerInfo,
3275                                               newPowerInfo) < 0) {
3276         esxVI_AutoStartPowerInfo_Free(&newPowerInfo);
3277         goto cleanup;
3278     }
3279 
3280     newPowerInfo->key = virtualMachine->obj;
3281     newPowerInfo->startOrder->value = -1; /* no specific start order */
3282     newPowerInfo->startDelay->value = -1; /* use system default */
3283     newPowerInfo->waitForHeartbeat = esxVI_AutoStartWaitHeartbeatSetting_SystemDefault;
3284     newPowerInfo->startAction = autostart ? (char *)"powerOn" : (char *)"none";
3285     newPowerInfo->stopDelay->value = -1; /* use system default */
3286     newPowerInfo->stopAction = (char *)"none";
3287 
3288     if (esxVI_ReconfigureAutostart
3289           (priv->primary,
3290            priv->primary->hostSystem->configManager->autoStartManager,
3291            spec) < 0) {
3292         goto cleanup;
3293     }
3294 
3295     result = 0;
3296 
3297  cleanup:
3298     if (newPowerInfo) {
3299         newPowerInfo->key = NULL;
3300         newPowerInfo->startAction = NULL;
3301         newPowerInfo->stopAction = NULL;
3302     }
3303 
3304     esxVI_ObjectContent_Free(&virtualMachine);
3305     esxVI_HostAutoStartManagerConfig_Free(&spec);
3306     esxVI_AutoStartDefaults_Free(&defaults);
3307     esxVI_AutoStartPowerInfo_Free(&powerInfoList);
3308 
3309     return result;
3310 }
3311 
3312 
3313 
3314 /*
3315  * The scheduler interface exposes basically the CPU ResourceAllocationInfo:
3316  *
3317  * - https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.ResourceAllocationInfo.html
3318  * - https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.SharesInfo.html
3319  * - https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.SharesInfo.Level.html
3320  *
3321  *
3322  * Available parameters:
3323  *
3324  * - reservation (VIR_TYPED_PARAM_LLONG >= 0, in megaherz)
3325  *
3326  *   The amount of CPU resource that is guaranteed to be available to the domain.
3327  *
3328  *
3329  * - limit (VIR_TYPED_PARAM_LLONG >= 0, or -1, in megaherz)
3330  *
3331  *   The CPU utilization of the domain will be limited to this value, even if
3332  *   more CPU resources are available. If the limit is set to -1, the CPU
3333  *   utilization of the domain is unlimited. If the limit is not set to -1, it
3334  *   must be greater than or equal to the reservation.
3335  *
3336  *
3337  * - shares (VIR_TYPED_PARAM_INT >= 0, or in {-1, -2, -3}, no unit)
3338  *
3339  *   Shares are used to determine relative CPU allocation between domains. In
3340  *   general, a domain with more shares gets proportionally more of the CPU
3341  *   resource. The special values -1, -2 and -3 represent the predefined
3342  *   SharesLevel 'low', 'normal' and 'high'.
3343  */
3344 static char *
esxDomainGetSchedulerType(virDomainPtr domain G_GNUC_UNUSED,int * nparams)3345 esxDomainGetSchedulerType(virDomainPtr domain G_GNUC_UNUSED, int *nparams)
3346 {
3347     char *type;
3348 
3349     type = g_strdup("allocation");
3350 
3351     if (nparams)
3352         *nparams = 3; /* reservation, limit, shares */
3353 
3354     return type;
3355 }
3356 
3357 
3358 
3359 static int
esxDomainGetSchedulerParametersFlags(virDomainPtr domain,virTypedParameterPtr params,int * nparams,unsigned int flags)3360 esxDomainGetSchedulerParametersFlags(virDomainPtr domain,
3361                                      virTypedParameterPtr params, int *nparams,
3362                                      unsigned int flags)
3363 {
3364     int result = -1;
3365     esxPrivate *priv = domain->conn->privateData;
3366     esxVI_String *propertyNameList = NULL;
3367     esxVI_ObjectContent *virtualMachine = NULL;
3368     esxVI_DynamicProperty *dynamicProperty = NULL;
3369     esxVI_SharesInfo *sharesInfo = NULL;
3370     unsigned int mask = 0;
3371     size_t i = 0;
3372 
3373     virCheckFlags(0, -1);
3374 
3375     if (esxVI_EnsureSession(priv->primary) < 0)
3376         return -1;
3377 
3378     if (esxVI_String_AppendValueListToList(&propertyNameList,
3379                                            "config.cpuAllocation.reservation\0"
3380                                            "config.cpuAllocation.limit\0"
3381                                            "config.cpuAllocation.shares\0") < 0 ||
3382         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3383                                          propertyNameList, &virtualMachine,
3384                                          esxVI_Occurrence_RequiredItem) < 0) {
3385         goto cleanup;
3386     }
3387 
3388     for (dynamicProperty = virtualMachine->propSet;
3389          dynamicProperty && mask != 7 && i < 3 && i < *nparams;
3390          dynamicProperty = dynamicProperty->_next) {
3391         if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") &&
3392             ! (mask & (1 << 0))) {
3393             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3394                                          esxVI_Type_Long) < 0) {
3395                 goto cleanup;
3396             }
3397             if (virTypedParameterAssign(&params[i],
3398                                         VIR_DOMAIN_SCHEDULER_RESERVATION,
3399                                         VIR_TYPED_PARAM_LLONG,
3400                                         dynamicProperty->val->int64) < 0)
3401                 goto cleanup;
3402             mask |= 1 << 0;
3403             ++i;
3404         } else if (STREQ(dynamicProperty->name,
3405                          "config.cpuAllocation.limit") &&
3406                    ! (mask & (1 << 1))) {
3407             if (esxVI_AnyType_ExpectType(dynamicProperty->val,
3408                                          esxVI_Type_Long) < 0) {
3409                 goto cleanup;
3410             }
3411             if (virTypedParameterAssign(&params[i],
3412                                         VIR_DOMAIN_SCHEDULER_LIMIT,
3413                                         VIR_TYPED_PARAM_LLONG,
3414                                         dynamicProperty->val->int64) < 0)
3415                 goto cleanup;
3416             mask |= 1 << 1;
3417             ++i;
3418         } else if (STREQ(dynamicProperty->name,
3419                          "config.cpuAllocation.shares") &&
3420                    ! (mask & (1 << 2))) {
3421             if (virTypedParameterAssign(&params[i],
3422                                         VIR_DOMAIN_SCHEDULER_SHARES,
3423                                         VIR_TYPED_PARAM_INT, 0) < 0)
3424                 goto cleanup;
3425             if (esxVI_SharesInfo_CastFromAnyType(dynamicProperty->val,
3426                                                  &sharesInfo) < 0) {
3427                 goto cleanup;
3428             }
3429 
3430             switch (sharesInfo->level) {
3431               case esxVI_SharesLevel_Custom:
3432                 params[i].value.i = sharesInfo->shares->value;
3433                 break;
3434 
3435               case esxVI_SharesLevel_Low:
3436                 params[i].value.i = -1;
3437                 break;
3438 
3439               case esxVI_SharesLevel_Normal:
3440                 params[i].value.i = -2;
3441                 break;
3442 
3443               case esxVI_SharesLevel_High:
3444                 params[i].value.i = -3;
3445                 break;
3446 
3447               case esxVI_SharesLevel_Undefined:
3448               default:
3449                 virReportEnumRangeError(esxVI_SharesLevel, sharesInfo->level);
3450                 esxVI_SharesInfo_Free(&sharesInfo);
3451                 goto cleanup;
3452             }
3453 
3454             esxVI_SharesInfo_Free(&sharesInfo);
3455 
3456             mask |= 1 << 2;
3457             ++i;
3458         } else {
3459             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3460         }
3461     }
3462 
3463     *nparams = i;
3464     result = 0;
3465 
3466  cleanup:
3467     esxVI_String_Free(&propertyNameList);
3468     esxVI_ObjectContent_Free(&virtualMachine);
3469 
3470     return result;
3471 }
3472 
3473 static int
esxDomainGetSchedulerParameters(virDomainPtr domain,virTypedParameterPtr params,int * nparams)3474 esxDomainGetSchedulerParameters(virDomainPtr domain,
3475                                 virTypedParameterPtr params, int *nparams)
3476 {
3477     return esxDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
3478 }
3479 
3480 
3481 static int
esxDomainSetSchedulerParametersFlags(virDomainPtr domain,virTypedParameterPtr params,int nparams,unsigned int flags)3482 esxDomainSetSchedulerParametersFlags(virDomainPtr domain,
3483                                      virTypedParameterPtr params, int nparams,
3484                                      unsigned int flags)
3485 {
3486     int result = -1;
3487     esxPrivate *priv = domain->conn->privateData;
3488     esxVI_ObjectContent *virtualMachine = NULL;
3489     esxVI_VirtualMachineConfigSpec *spec = NULL;
3490     esxVI_SharesInfo *sharesInfo = NULL;
3491     esxVI_ManagedObjectReference *task = NULL;
3492     esxVI_TaskInfoState taskInfoState;
3493     g_autofree char *taskInfoErrorMessage = NULL;
3494     size_t i;
3495 
3496     virCheckFlags(0, -1);
3497     if (virTypedParamsValidate(params, nparams,
3498                                VIR_DOMAIN_SCHEDULER_RESERVATION,
3499                                VIR_TYPED_PARAM_LLONG,
3500                                VIR_DOMAIN_SCHEDULER_LIMIT,
3501                                VIR_TYPED_PARAM_LLONG,
3502                                VIR_DOMAIN_SCHEDULER_SHARES,
3503                                VIR_TYPED_PARAM_INT,
3504                                NULL) < 0)
3505         return -1;
3506 
3507     if (esxVI_EnsureSession(priv->primary) < 0)
3508         return -1;
3509 
3510     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3511           (priv->primary, domain->uuid, NULL, &virtualMachine,
3512            priv->parsedUri->autoAnswer) < 0 ||
3513         esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
3514         esxVI_ResourceAllocationInfo_Alloc(&spec->cpuAllocation) < 0) {
3515         goto cleanup;
3516     }
3517 
3518     for (i = 0; i < nparams; ++i) {
3519         if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_RESERVATION)) {
3520             if (esxVI_Long_Alloc(&spec->cpuAllocation->reservation) < 0)
3521                 goto cleanup;
3522 
3523             if (params[i].value.l < 0) {
3524                 virReportError(VIR_ERR_INVALID_ARG,
3525                                _("Could not set reservation to %lld MHz, expecting "
3526                                  "positive value"), params[i].value.l);
3527                 goto cleanup;
3528             }
3529 
3530             spec->cpuAllocation->reservation->value = params[i].value.l;
3531         } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_LIMIT)) {
3532             if (esxVI_Long_Alloc(&spec->cpuAllocation->limit) < 0)
3533                 goto cleanup;
3534 
3535             if (params[i].value.l < -1) {
3536                 virReportError(VIR_ERR_INVALID_ARG,
3537                                _("Could not set limit to %lld MHz, expecting "
3538                                  "positive value or -1 (unlimited)"),
3539                                params[i].value.l);
3540                 goto cleanup;
3541             }
3542 
3543             spec->cpuAllocation->limit->value = params[i].value.l;
3544         } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_SHARES)) {
3545             if (esxVI_SharesInfo_Alloc(&sharesInfo) < 0 ||
3546                 esxVI_Int_Alloc(&sharesInfo->shares) < 0) {
3547                 goto cleanup;
3548             }
3549 
3550             spec->cpuAllocation->shares = g_steal_pointer(&sharesInfo);
3551 
3552             if (params[i].value.i >= 0) {
3553                 spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom;
3554                 spec->cpuAllocation->shares->shares->value = params[i].value.i;
3555             } else {
3556                 switch (params[i].value.i) {
3557                   case -1:
3558                     spec->cpuAllocation->shares->level = esxVI_SharesLevel_Low;
3559                     spec->cpuAllocation->shares->shares->value = -1;
3560                     break;
3561 
3562                   case -2:
3563                     spec->cpuAllocation->shares->level =
3564                       esxVI_SharesLevel_Normal;
3565                     spec->cpuAllocation->shares->shares->value = -1;
3566                     break;
3567 
3568                   case -3:
3569                     spec->cpuAllocation->shares->level =
3570                       esxVI_SharesLevel_High;
3571                     spec->cpuAllocation->shares->shares->value = -1;
3572                     break;
3573 
3574                   default:
3575                     virReportError(VIR_ERR_INVALID_ARG,
3576                                    _("Could not set shares to %d, expecting positive "
3577                                      "value or -1 (low), -2 (normal) or -3 (high)"),
3578                                    params[i].value.i);
3579                     goto cleanup;
3580                 }
3581             }
3582         }
3583     }
3584 
3585     if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
3586                               &task) < 0 ||
3587         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
3588                                     esxVI_Occurrence_RequiredItem,
3589                                     priv->parsedUri->autoAnswer, &taskInfoState,
3590                                     &taskInfoErrorMessage) < 0) {
3591         goto cleanup;
3592     }
3593 
3594     if (taskInfoState != esxVI_TaskInfoState_Success) {
3595         virReportError(VIR_ERR_INTERNAL_ERROR,
3596                        _("Could not change scheduler parameters: %s"),
3597                        taskInfoErrorMessage);
3598         goto cleanup;
3599     }
3600 
3601     result = 0;
3602 
3603  cleanup:
3604     esxVI_SharesInfo_Free(&sharesInfo);
3605     esxVI_ObjectContent_Free(&virtualMachine);
3606     esxVI_VirtualMachineConfigSpec_Free(&spec);
3607     esxVI_ManagedObjectReference_Free(&task);
3608     return result;
3609 }
3610 
3611 static int
esxDomainSetSchedulerParameters(virDomainPtr domain,virTypedParameterPtr params,int nparams)3612 esxDomainSetSchedulerParameters(virDomainPtr domain,
3613                                 virTypedParameterPtr params, int nparams)
3614 {
3615     return esxDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
3616 }
3617 
3618 /* The subset of migration flags we are able to support.  */
3619 #define ESX_MIGRATION_FLAGS \
3620     (VIR_MIGRATE_PERSIST_DEST | \
3621      VIR_MIGRATE_UNDEFINE_SOURCE | \
3622      VIR_MIGRATE_LIVE | \
3623      VIR_MIGRATE_PAUSED)
3624 
3625 static int
esxDomainMigratePrepare(virConnectPtr dconn,char ** cookie G_GNUC_UNUSED,int * cookielen G_GNUC_UNUSED,const char * uri_in G_GNUC_UNUSED,char ** uri_out,unsigned long flags,const char * dname G_GNUC_UNUSED,unsigned long resource G_GNUC_UNUSED)3626 esxDomainMigratePrepare(virConnectPtr dconn,
3627                         char **cookie G_GNUC_UNUSED,
3628                         int *cookielen G_GNUC_UNUSED,
3629                         const char *uri_in G_GNUC_UNUSED,
3630                         char **uri_out,
3631                         unsigned long flags,
3632                         const char *dname G_GNUC_UNUSED,
3633                         unsigned long resource G_GNUC_UNUSED)
3634 {
3635     esxPrivate *priv = dconn->privateData;
3636 
3637     virCheckFlags(ESX_MIGRATION_FLAGS, -1);
3638 
3639     if (!uri_in) {
3640         *uri_out = g_strdup_printf("vpxmigr://%s/%s/%s", priv->vCenter->ipAddress,
3641                                    priv->vCenter->computeResource->resourcePool->value,
3642                                    priv->vCenter->hostSystem->_reference->value);
3643     }
3644 
3645     return 0;
3646 }
3647 
3648 
3649 
3650 static int
esxDomainMigratePerform(virDomainPtr domain,const char * cookie G_GNUC_UNUSED,int cookielen G_GNUC_UNUSED,const char * uri,unsigned long flags,const char * dname,unsigned long bandwidth G_GNUC_UNUSED)3651 esxDomainMigratePerform(virDomainPtr domain,
3652                         const char *cookie G_GNUC_UNUSED,
3653                         int cookielen G_GNUC_UNUSED,
3654                         const char *uri,
3655                         unsigned long flags,
3656                         const char *dname,
3657                         unsigned long bandwidth G_GNUC_UNUSED)
3658 {
3659     int result = -1;
3660     esxPrivate *priv = domain->conn->privateData;
3661     virURI *parsedUri = NULL;
3662     char *saveptr;
3663     char *path_resourcePool;
3664     char *path_hostSystem;
3665     esxVI_ObjectContent *virtualMachine = NULL;
3666     esxVI_ManagedObjectReference resourcePool;
3667     esxVI_ManagedObjectReference hostSystem;
3668     esxVI_Event *eventList = NULL;
3669     esxVI_ManagedObjectReference *task = NULL;
3670     esxVI_TaskInfoState taskInfoState;
3671     g_autofree char *taskInfoErrorMessage = NULL;
3672 
3673     virCheckFlags(ESX_MIGRATION_FLAGS, -1);
3674 
3675     if (!priv->vCenter) {
3676         virReportError(VIR_ERR_INVALID_ARG, "%s",
3677                        _("Migration not possible without a vCenter"));
3678         return -1;
3679     }
3680 
3681     if (dname) {
3682         virReportError(VIR_ERR_INVALID_ARG, "%s",
3683                        _("Renaming domains on migration not supported"));
3684         return -1;
3685     }
3686 
3687     if (esxVI_EnsureSession(priv->vCenter) < 0)
3688         return -1;
3689 
3690     /* Parse migration URI */
3691     if (!(parsedUri = virURIParse(uri)))
3692         return -1;
3693 
3694     if (!parsedUri->scheme || STRCASENEQ(parsedUri->scheme, "vpxmigr")) {
3695         virReportError(VIR_ERR_INVALID_ARG, "%s",
3696                        _("Only vpxmigr:// migration URIs are supported"));
3697         goto cleanup;
3698     }
3699 
3700     if (STRCASENEQ(priv->vCenter->ipAddress, parsedUri->server)) {
3701         virReportError(VIR_ERR_INVALID_ARG, "%s",
3702                        _("Migration source and destination have to refer to "
3703                          "the same vCenter"));
3704         goto cleanup;
3705     }
3706 
3707     path_resourcePool = strtok_r(parsedUri->path, "/", &saveptr);
3708     path_hostSystem = strtok_r(NULL, "", &saveptr);
3709 
3710     if (!path_resourcePool || !path_hostSystem) {
3711         virReportError(VIR_ERR_INVALID_ARG, "%s",
3712                        _("Migration URI has to specify resource pool and host system"));
3713         goto cleanup;
3714     }
3715 
3716     resourcePool._next = NULL;
3717     resourcePool._type = esxVI_Type_ManagedObjectReference;
3718     resourcePool.type = (char *)"ResourcePool";
3719     resourcePool.value = path_resourcePool;
3720 
3721     hostSystem._next = NULL;
3722     hostSystem._type = esxVI_Type_ManagedObjectReference;
3723     hostSystem.type = (char *)"HostSystem";
3724     hostSystem.value = path_hostSystem;
3725 
3726     /* Lookup VirtualMachine */
3727     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
3728           (priv->vCenter, domain->uuid, NULL, &virtualMachine,
3729            priv->parsedUri->autoAnswer) < 0) {
3730         goto cleanup;
3731     }
3732 
3733     /* Validate the purposed migration */
3734     if (esxVI_ValidateMigration(priv->vCenter, virtualMachine->obj,
3735                                 esxVI_VirtualMachinePowerState_Undefined, NULL,
3736                                 &resourcePool, &hostSystem, &eventList) < 0) {
3737         goto cleanup;
3738     }
3739 
3740     if (eventList) {
3741         /*
3742          * FIXME: Need to report the complete list of events. Limit reporting
3743          *        to the first event for now.
3744          */
3745         if (eventList->fullFormattedMessage) {
3746             virReportError(VIR_ERR_INTERNAL_ERROR,
3747                            _("Could not migrate domain, validation reported a "
3748                              "problem: %s"), eventList->fullFormattedMessage);
3749         } else {
3750             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3751                            _("Could not migrate domain, validation reported a "
3752                              "problem"));
3753         }
3754 
3755         goto cleanup;
3756     }
3757 
3758     /* Perform the purposed migration */
3759     if (esxVI_MigrateVM_Task(priv->vCenter, virtualMachine->obj,
3760                              &resourcePool, &hostSystem,
3761                              esxVI_VirtualMachineMovePriority_DefaultPriority,
3762                              esxVI_VirtualMachinePowerState_Undefined,
3763                              &task) < 0 ||
3764         esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
3765                                     esxVI_Occurrence_RequiredItem,
3766                                     priv->parsedUri->autoAnswer, &taskInfoState,
3767                                     &taskInfoErrorMessage) < 0) {
3768         goto cleanup;
3769     }
3770 
3771     if (taskInfoState != esxVI_TaskInfoState_Success) {
3772         virReportError(VIR_ERR_INTERNAL_ERROR,
3773                        _("Could not migrate domain, migration task finished with "
3774                          "an error: %s"),
3775                        taskInfoErrorMessage);
3776         goto cleanup;
3777     }
3778 
3779     result = 0;
3780 
3781  cleanup:
3782     virURIFree(parsedUri);
3783     esxVI_ObjectContent_Free(&virtualMachine);
3784     esxVI_Event_Free(&eventList);
3785     esxVI_ManagedObjectReference_Free(&task);
3786     return result;
3787 }
3788 
3789 
3790 
3791 static virDomainPtr
esxDomainMigrateFinish(virConnectPtr dconn,const char * dname,const char * cookie G_GNUC_UNUSED,int cookielen G_GNUC_UNUSED,const char * uri G_GNUC_UNUSED,unsigned long flags)3792 esxDomainMigrateFinish(virConnectPtr dconn, const char *dname,
3793                        const char *cookie G_GNUC_UNUSED,
3794                        int cookielen G_GNUC_UNUSED,
3795                        const char *uri G_GNUC_UNUSED,
3796                        unsigned long flags)
3797 {
3798     virCheckFlags(ESX_MIGRATION_FLAGS, NULL);
3799 
3800     return esxDomainLookupByName(dconn, dname);
3801 }
3802 
3803 
3804 
3805 static unsigned long long
esxNodeGetFreeMemory(virConnectPtr conn)3806 esxNodeGetFreeMemory(virConnectPtr conn)
3807 {
3808     unsigned long long result = 0;
3809     unsigned long long usageBytes = 0;
3810     esxPrivate *priv = conn->privateData;
3811     esxVI_String *propertyNameList = NULL;
3812     esxVI_ObjectContent *hostSystem = NULL;
3813     esxVI_Int *memoryUsage = NULL;
3814     esxVI_Long *memorySize = NULL;
3815 
3816     if (esxVI_EnsureSession(priv->primary) < 0)
3817         return 0;
3818 
3819     /* Get memory usage of host system */
3820     if (esxVI_String_AppendValueListToList(&propertyNameList,
3821                                            "summary.quickStats.overallMemoryUsage\0"
3822                                            "hardware.memorySize\0") < 0 ||
3823         esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
3824                                          &hostSystem) < 0 ||
3825         esxVI_GetInt(hostSystem, "summary.quickStats.overallMemoryUsage",
3826                       &memoryUsage, esxVI_Occurrence_RequiredItem) < 0 ||
3827         esxVI_GetLong(hostSystem, "hardware.memorySize", &memorySize,
3828                       esxVI_Occurrence_RequiredItem) < 0) {
3829         goto cleanup;
3830     }
3831 
3832     usageBytes = (unsigned long long)(memoryUsage->value) * 1048576;
3833     result = memorySize->value - usageBytes;
3834 
3835  cleanup:
3836     esxVI_String_Free(&propertyNameList);
3837     esxVI_ObjectContent_Free(&hostSystem);
3838     esxVI_Int_Free(&memoryUsage);
3839     esxVI_Long_Free(&memorySize);
3840 
3841     return result;
3842 }
3843 
3844 
3845 
3846 static int
esxConnectIsEncrypted(virConnectPtr conn)3847 esxConnectIsEncrypted(virConnectPtr conn)
3848 {
3849     esxPrivate *priv = conn->privateData;
3850 
3851     return STRCASEEQ(priv->parsedUri->transport, "https");
3852 }
3853 
3854 
3855 
3856 static int
esxConnectIsSecure(virConnectPtr conn)3857 esxConnectIsSecure(virConnectPtr conn)
3858 {
3859     esxPrivate *priv = conn->privateData;
3860 
3861     return STRCASEEQ(priv->parsedUri->transport, "https");
3862 }
3863 
3864 
3865 
3866 static int
esxConnectIsAlive(virConnectPtr conn)3867 esxConnectIsAlive(virConnectPtr conn)
3868 {
3869     esxPrivate *priv = conn->privateData;
3870 
3871     /* XXX we should be able to do something better than this but this is
3872      * simple, safe, and good enough for now. In worst case, the function will
3873      * return true even though the connection is not alive.
3874      */
3875     if (priv->primary)
3876         return 1;
3877     else
3878         return 0;
3879 }
3880 
3881 
3882 
3883 static int
esxDomainIsActive(virDomainPtr domain)3884 esxDomainIsActive(virDomainPtr domain)
3885 {
3886     int result = -1;
3887     esxPrivate *priv = domain->conn->privateData;
3888     esxVI_ObjectContent *virtualMachine = NULL;
3889     esxVI_String *propertyNameList = NULL;
3890     esxVI_VirtualMachinePowerState powerState;
3891 
3892     if (esxVI_EnsureSession(priv->primary) < 0)
3893         return -1;
3894 
3895     if (esxVI_String_AppendValueToList(&propertyNameList,
3896                                        "runtime.powerState") < 0 ||
3897         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3898                                          propertyNameList, &virtualMachine,
3899                                          esxVI_Occurrence_RequiredItem) < 0 ||
3900         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
3901         goto cleanup;
3902     }
3903 
3904     if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
3905         result = 1;
3906     } else {
3907         result = 0;
3908     }
3909 
3910  cleanup:
3911     esxVI_ObjectContent_Free(&virtualMachine);
3912     esxVI_String_Free(&propertyNameList);
3913 
3914     return result;
3915 }
3916 
3917 
3918 
3919 static int
esxDomainIsPersistent(virDomainPtr domain)3920 esxDomainIsPersistent(virDomainPtr domain)
3921 {
3922     /* ESX has no concept of transient domains, so all of them are
3923      * persistent.  However, we do want to check for existence. */
3924     int result = -1;
3925     esxPrivate *priv = domain->conn->privateData;
3926     esxVI_ObjectContent *virtualMachine = NULL;
3927 
3928     if (esxVI_EnsureSession(priv->primary) < 0)
3929         return -1;
3930 
3931     if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3932                                          NULL, &virtualMachine,
3933                                          esxVI_Occurrence_RequiredItem) < 0)
3934         goto cleanup;
3935 
3936     result = 1;
3937 
3938  cleanup:
3939     esxVI_ObjectContent_Free(&virtualMachine);
3940 
3941     return result;
3942 }
3943 
3944 
3945 
3946 static int
esxDomainIsUpdated(virDomainPtr domain G_GNUC_UNUSED)3947 esxDomainIsUpdated(virDomainPtr domain G_GNUC_UNUSED)
3948 {
3949     /* ESX domains never have a persistent state that differs from
3950      * current state.  However, we do want to check for existence.  */
3951     int result = -1;
3952     esxPrivate *priv = domain->conn->privateData;
3953     esxVI_ObjectContent *virtualMachine = NULL;
3954 
3955     if (esxVI_EnsureSession(priv->primary) < 0)
3956         return -1;
3957 
3958     if (esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
3959                                          NULL, &virtualMachine,
3960                                          esxVI_Occurrence_RequiredItem) < 0)
3961         goto cleanup;
3962 
3963     result = 0;
3964 
3965  cleanup:
3966     esxVI_ObjectContent_Free(&virtualMachine);
3967 
3968     return result;
3969 }
3970 
3971 
3972 
3973 static virDomainSnapshotPtr
esxDomainSnapshotCreateXML(virDomainPtr domain,const char * xmlDesc,unsigned int flags)3974 esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
3975                            unsigned int flags)
3976 {
3977     esxPrivate *priv = domain->conn->privateData;
3978     esxVI_ObjectContent *virtualMachine = NULL;
3979     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
3980     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
3981     esxVI_ManagedObjectReference *task = NULL;
3982     esxVI_TaskInfoState taskInfoState;
3983     g_autofree char *taskInfoErrorMessage = NULL;
3984     virDomainSnapshotPtr snapshot = NULL;
3985     bool diskOnly = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) != 0;
3986     bool quiesce = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) != 0;
3987     g_autoptr(virDomainSnapshotDef) def = NULL;
3988     unsigned int parse_flags = 0;
3989 
3990     /* ESX supports disk-only and quiesced snapshots; libvirt tracks no
3991      * snapshot metadata so supporting that flag is trivial.  */
3992     virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
3993                   VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
3994                   VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
3995                   VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL);
3996 
3997     if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE)
3998         parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_VALIDATE;
3999 
4000     if (esxVI_EnsureSession(priv->primary) < 0)
4001         return NULL;
4002 
4003     def = virDomainSnapshotDefParseString(xmlDesc,
4004                                           priv->xmlopt, NULL, NULL, parse_flags);
4005 
4006     if (!def)
4007         return NULL;
4008 
4009     if (def->ndisks) {
4010         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
4011                        _("disk snapshots not supported yet"));
4012         return NULL;
4013     }
4014 
4015     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4016           (priv->primary, domain->uuid, NULL, &virtualMachine,
4017            priv->parsedUri->autoAnswer) < 0 ||
4018         esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4019                                          &rootSnapshotList) < 0 ||
4020         esxVI_GetSnapshotTreeByName(rootSnapshotList, def->parent.name,
4021                                     &snapshotTree, NULL,
4022                                     esxVI_Occurrence_OptionalItem) < 0) {
4023         goto cleanup;
4024     }
4025 
4026     if (snapshotTree) {
4027         virReportError(VIR_ERR_OPERATION_INVALID,
4028                        _("Snapshot '%s' already exists"), def->parent.name);
4029         goto cleanup;
4030     }
4031 
4032     if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
4033                                   def->parent.name, def->parent.description,
4034                                   diskOnly ? esxVI_Boolean_False : esxVI_Boolean_True,
4035                                   quiesce ? esxVI_Boolean_True : esxVI_Boolean_False,
4036                                   &task) < 0 ||
4037         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4038                                     esxVI_Occurrence_RequiredItem,
4039                                     priv->parsedUri->autoAnswer, &taskInfoState,
4040                                     &taskInfoErrorMessage) < 0) {
4041         goto cleanup;
4042     }
4043 
4044     if (taskInfoState != esxVI_TaskInfoState_Success) {
4045         virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
4046                        taskInfoErrorMessage);
4047         goto cleanup;
4048     }
4049 
4050     snapshot = virGetDomainSnapshot(domain, def->parent.name);
4051 
4052  cleanup:
4053     esxVI_ObjectContent_Free(&virtualMachine);
4054     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4055     esxVI_ManagedObjectReference_Free(&task);
4056     return snapshot;
4057 }
4058 
4059 
4060 
4061 static char *
esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,unsigned int flags)4062 esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
4063                             unsigned int flags)
4064 {
4065     esxPrivate *priv = snapshot->domain->conn->privateData;
4066     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4067     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4068     esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
4069     virDomainSnapshotDef def;
4070     char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
4071     char *xml = NULL;
4072 
4073     virCheckFlags(0, NULL);
4074 
4075     memset(&def, 0, sizeof(def));
4076 
4077     if (esxVI_EnsureSession(priv->primary) < 0)
4078         return NULL;
4079 
4080     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4081                                          &rootSnapshotList) < 0 ||
4082         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4083                                     &snapshotTree, &snapshotTreeParent,
4084                                     esxVI_Occurrence_RequiredItem) < 0) {
4085         goto cleanup;
4086     }
4087 
4088     def.parent.name = snapshot->name;
4089     def.parent.description = snapshotTree->description;
4090     def.parent.parent_name = snapshotTreeParent ? snapshotTreeParent->name : NULL;
4091 
4092     if (esxVI_DateTime_ConvertToCalendarTime(snapshotTree->createTime,
4093                                              &def.parent.creationTime) < 0) {
4094         goto cleanup;
4095     }
4096 
4097     def.state = esxVI_VirtualMachinePowerState_ConvertToLibvirt
4098                   (snapshotTree->state);
4099 
4100     virUUIDFormat(snapshot->domain->uuid, uuid_string);
4101 
4102     xml = virDomainSnapshotDefFormat(uuid_string, &def, priv->xmlopt,
4103                                      0);
4104 
4105  cleanup:
4106     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4107 
4108     return xml;
4109 }
4110 
4111 
4112 
4113 static int
esxDomainSnapshotNum(virDomainPtr domain,unsigned int flags)4114 esxDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
4115 {
4116     int count;
4117     esxPrivate *priv = domain->conn->privateData;
4118     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4119     bool recurse;
4120     bool leaves;
4121 
4122     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4123                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
4124                   VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4125 
4126     recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4127     leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4128 
4129     if (esxVI_EnsureSession(priv->primary) < 0)
4130         return -1;
4131 
4132     /* ESX snapshots do not require libvirt to maintain any metadata.  */
4133     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)
4134         return 0;
4135 
4136     if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4137                                          &rootSnapshotTreeList) < 0) {
4138         return -1;
4139     }
4140 
4141     count = esxVI_GetNumberOfSnapshotTrees(rootSnapshotTreeList, recurse,
4142                                            leaves);
4143 
4144     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4145 
4146     return count;
4147 }
4148 
4149 
4150 
4151 static int
esxDomainSnapshotListNames(virDomainPtr domain,char ** names,int nameslen,unsigned int flags)4152 esxDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
4153                            unsigned int flags)
4154 {
4155     int result;
4156     esxPrivate *priv = domain->conn->privateData;
4157     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4158     bool recurse;
4159     bool leaves;
4160 
4161     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
4162                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
4163                   VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4164 
4165     recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) == 0;
4166     leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4167 
4168     if (!names || nameslen < 0) {
4169         virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4170         return -1;
4171     }
4172 
4173     if (nameslen == 0 || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA))
4174         return 0;
4175 
4176     if (esxVI_EnsureSession(priv->primary) < 0)
4177         return -1;
4178 
4179     if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4180                                          &rootSnapshotTreeList) < 0) {
4181         return -1;
4182     }
4183 
4184     result = esxVI_GetSnapshotTreeNames(rootSnapshotTreeList, names, nameslen,
4185                                         recurse, leaves);
4186 
4187     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4188 
4189     return result;
4190 }
4191 
4192 
4193 
4194 static int
esxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,unsigned int flags)4195 esxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
4196 {
4197     int count = -1;
4198     esxPrivate *priv = snapshot->domain->conn->privateData;
4199     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4200     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4201     bool recurse;
4202     bool leaves;
4203 
4204     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4205                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
4206                   VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4207 
4208     recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4209     leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4210 
4211     if (esxVI_EnsureSession(priv->primary) < 0)
4212         return -1;
4213 
4214     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4215                                          &rootSnapshotTreeList) < 0 ||
4216         esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, snapshot->name,
4217                                     &snapshotTree, NULL,
4218                                     esxVI_Occurrence_RequiredItem) < 0) {
4219         goto cleanup;
4220     }
4221 
4222     /* ESX snapshots do not require libvirt to maintain any metadata.  */
4223     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
4224         count = 0;
4225         goto cleanup;
4226     }
4227 
4228     count = esxVI_GetNumberOfSnapshotTrees(snapshotTree->childSnapshotList,
4229                                            recurse, leaves);
4230 
4231  cleanup:
4232     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4233 
4234     return count;
4235 }
4236 
4237 
4238 
4239 static int
esxDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,char ** names,int nameslen,unsigned int flags)4240 esxDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
4241                                    char **names, int nameslen,
4242                                    unsigned int flags)
4243 {
4244     int result = -1;
4245     esxPrivate *priv = snapshot->domain->conn->privateData;
4246     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4247     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4248     bool recurse;
4249     bool leaves;
4250 
4251     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
4252                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
4253                   VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
4254 
4255     recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0;
4256     leaves = (flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) != 0;
4257 
4258     if (!names || nameslen < 0) {
4259         virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
4260         return -1;
4261     }
4262 
4263     if (nameslen == 0)
4264         return 0;
4265 
4266     if (esxVI_EnsureSession(priv->primary) < 0)
4267         return -1;
4268 
4269     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4270                                          &rootSnapshotTreeList) < 0 ||
4271         esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, snapshot->name,
4272                                     &snapshotTree, NULL,
4273                                     esxVI_Occurrence_RequiredItem) < 0) {
4274         goto cleanup;
4275     }
4276 
4277     /* ESX snapshots do not require libvirt to maintain any metadata.  */
4278     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
4279         result = 0;
4280         goto cleanup;
4281     }
4282 
4283     result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
4284                                         names, nameslen, recurse, leaves);
4285 
4286  cleanup:
4287     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4288 
4289     return result;
4290 }
4291 
4292 
4293 
4294 static virDomainSnapshotPtr
esxDomainSnapshotLookupByName(virDomainPtr domain,const char * name,unsigned int flags)4295 esxDomainSnapshotLookupByName(virDomainPtr domain, const char *name,
4296                               unsigned int flags)
4297 {
4298     esxPrivate *priv = domain->conn->privateData;
4299     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4300     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4301     virDomainSnapshotPtr snapshot = NULL;
4302 
4303     virCheckFlags(0, NULL);
4304 
4305     if (esxVI_EnsureSession(priv->primary) < 0)
4306         return NULL;
4307 
4308     if (esxVI_LookupRootSnapshotTreeList(priv->primary, domain->uuid,
4309                                          &rootSnapshotTreeList) < 0 ||
4310         esxVI_GetSnapshotTreeByName(rootSnapshotTreeList, name, &snapshotTree,
4311                                     NULL,
4312                                     esxVI_Occurrence_RequiredItem) < 0) {
4313         goto cleanup;
4314     }
4315 
4316     snapshot = virGetDomainSnapshot(domain, name);
4317 
4318  cleanup:
4319     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4320 
4321     return snapshot;
4322 }
4323 
4324 
4325 
4326 static int
esxDomainHasCurrentSnapshot(virDomainPtr domain,unsigned int flags)4327 esxDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
4328 {
4329     esxPrivate *priv = domain->conn->privateData;
4330     esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
4331 
4332     virCheckFlags(0, -1);
4333 
4334     if (esxVI_EnsureSession(priv->primary) < 0)
4335         return -1;
4336 
4337     if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4338                                         &currentSnapshotTree,
4339                                         esxVI_Occurrence_OptionalItem) < 0) {
4340         return -1;
4341     }
4342 
4343     if (currentSnapshotTree) {
4344         esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
4345         return 1;
4346     }
4347 
4348     return 0;
4349 }
4350 
4351 
4352 
4353 static virDomainSnapshotPtr
esxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,unsigned int flags)4354 esxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
4355 {
4356     esxPrivate *priv = snapshot->domain->conn->privateData;
4357     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4358     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4359     esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
4360     virDomainSnapshotPtr parent = NULL;
4361 
4362     virCheckFlags(0, NULL);
4363 
4364     if (esxVI_EnsureSession(priv->primary) < 0)
4365         return NULL;
4366 
4367     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4368                                          &rootSnapshotList) < 0 ||
4369         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4370                                     &snapshotTree, &snapshotTreeParent,
4371                                     esxVI_Occurrence_RequiredItem) < 0) {
4372         goto cleanup;
4373     }
4374 
4375     if (!snapshotTreeParent) {
4376         virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
4377                        _("snapshot '%s' does not have a parent"),
4378                        snapshotTree->name);
4379         goto cleanup;
4380     }
4381 
4382     parent = virGetDomainSnapshot(snapshot->domain, snapshotTreeParent->name);
4383 
4384  cleanup:
4385     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4386 
4387     return parent;
4388 }
4389 
4390 
4391 
4392 static virDomainSnapshotPtr
esxDomainSnapshotCurrent(virDomainPtr domain,unsigned int flags)4393 esxDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
4394 {
4395     esxPrivate *priv = domain->conn->privateData;
4396     esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
4397     virDomainSnapshotPtr snapshot = NULL;
4398 
4399     virCheckFlags(0, NULL);
4400 
4401     if (esxVI_EnsureSession(priv->primary) < 0)
4402         return NULL;
4403 
4404     if (esxVI_LookupCurrentSnapshotTree(priv->primary, domain->uuid,
4405                                         &currentSnapshotTree,
4406                                         esxVI_Occurrence_RequiredItem) < 0) {
4407         return NULL;
4408     }
4409 
4410     snapshot = virGetDomainSnapshot(domain, currentSnapshotTree->name);
4411 
4412     esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
4413 
4414     return snapshot;
4415 }
4416 
4417 
4418 static int
esxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,unsigned int flags)4419 esxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
4420 {
4421     esxPrivate *priv = snapshot->domain->conn->privateData;
4422     esxVI_VirtualMachineSnapshotTree *currentSnapshotTree = NULL;
4423     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4424     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4425     int ret = -1;
4426 
4427     virCheckFlags(0, -1);
4428 
4429     if (esxVI_EnsureSession(priv->primary) < 0)
4430         return -1;
4431 
4432     /* Check that snapshot exists.  */
4433     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4434                                          &rootSnapshotList) < 0 ||
4435         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4436                                     &snapshotTree, NULL,
4437                                     esxVI_Occurrence_RequiredItem) < 0) {
4438         goto cleanup;
4439     }
4440 
4441     if (esxVI_LookupCurrentSnapshotTree(priv->primary, snapshot->domain->uuid,
4442                                         &currentSnapshotTree,
4443                                         esxVI_Occurrence_RequiredItem) < 0) {
4444         goto cleanup;
4445     }
4446 
4447     ret = STREQ(snapshot->name, currentSnapshotTree->name);
4448 
4449  cleanup:
4450     esxVI_VirtualMachineSnapshotTree_Free(&currentSnapshotTree);
4451     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4452     return ret;
4453 }
4454 
4455 
4456 static int
esxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,unsigned int flags)4457 esxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot, unsigned int flags)
4458 {
4459     esxPrivate *priv = snapshot->domain->conn->privateData;
4460     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4461     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4462     int ret = -1;
4463 
4464     virCheckFlags(0, -1);
4465 
4466     if (esxVI_EnsureSession(priv->primary) < 0)
4467         return -1;
4468 
4469     /* Check that snapshot exists.  If so, there is no metadata.  */
4470     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4471                                          &rootSnapshotList) < 0 ||
4472         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4473                                     &snapshotTree, NULL,
4474                                     esxVI_Occurrence_RequiredItem) < 0) {
4475         goto cleanup;
4476     }
4477 
4478     ret = 0;
4479 
4480  cleanup:
4481     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4482     return ret;
4483 }
4484 
4485 
4486 static int
esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,unsigned int flags)4487 esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
4488 {
4489     int result = -1;
4490     esxPrivate *priv = snapshot->domain->conn->privateData;
4491     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4492     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4493     esxVI_ManagedObjectReference *task = NULL;
4494     esxVI_TaskInfoState taskInfoState;
4495     g_autofree char *taskInfoErrorMessage = NULL;
4496 
4497     virCheckFlags(0, -1);
4498 
4499     if (esxVI_EnsureSession(priv->primary) < 0)
4500         return -1;
4501 
4502     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4503                                          &rootSnapshotList) < 0 ||
4504         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4505                                     &snapshotTree, NULL,
4506                                     esxVI_Occurrence_RequiredItem) < 0) {
4507         goto cleanup;
4508     }
4509 
4510     if (esxVI_RevertToSnapshot_Task(priv->primary, snapshotTree->snapshot, NULL,
4511                                     esxVI_Boolean_Undefined, &task) < 0 ||
4512         esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4513                                     esxVI_Occurrence_RequiredItem,
4514                                     priv->parsedUri->autoAnswer, &taskInfoState,
4515                                     &taskInfoErrorMessage) < 0) {
4516         goto cleanup;
4517     }
4518 
4519     if (taskInfoState != esxVI_TaskInfoState_Success) {
4520         virReportError(VIR_ERR_INTERNAL_ERROR,
4521                        _("Could not revert to snapshot '%s': %s"), snapshot->name,
4522                        taskInfoErrorMessage);
4523         goto cleanup;
4524     }
4525 
4526     result = 0;
4527 
4528  cleanup:
4529     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4530     esxVI_ManagedObjectReference_Free(&task);
4531     return result;
4532 }
4533 
4534 
4535 
4536 static int
esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,unsigned int flags)4537 esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
4538 {
4539     int result = -1;
4540     esxPrivate *priv = snapshot->domain->conn->privateData;
4541     esxVI_VirtualMachineSnapshotTree *rootSnapshotList = NULL;
4542     esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
4543     esxVI_Boolean removeChildren = esxVI_Boolean_False;
4544     esxVI_ManagedObjectReference *task = NULL;
4545     esxVI_TaskInfoState taskInfoState;
4546     g_autofree char *taskInfoErrorMessage = NULL;
4547 
4548     virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
4549                   VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
4550 
4551     if (esxVI_EnsureSession(priv->primary) < 0)
4552         return -1;
4553 
4554     if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
4555         removeChildren = esxVI_Boolean_True;
4556 
4557     if (esxVI_LookupRootSnapshotTreeList(priv->primary, snapshot->domain->uuid,
4558                                          &rootSnapshotList) < 0 ||
4559         esxVI_GetSnapshotTreeByName(rootSnapshotList, snapshot->name,
4560                                     &snapshotTree, NULL,
4561                                     esxVI_Occurrence_RequiredItem) < 0) {
4562         goto cleanup;
4563     }
4564 
4565     /* ESX snapshots do not require any libvirt metadata, making this
4566      * flag trivial once we know we have a valid snapshot.  */
4567     if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
4568         result = 0;
4569         goto cleanup;
4570     }
4571 
4572     if (esxVI_RemoveSnapshot_Task(priv->primary, snapshotTree->snapshot,
4573                                   removeChildren, &task) < 0 ||
4574         esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
4575                                     esxVI_Occurrence_RequiredItem,
4576                                     priv->parsedUri->autoAnswer, &taskInfoState,
4577                                     &taskInfoErrorMessage) < 0) {
4578         goto cleanup;
4579     }
4580 
4581     if (taskInfoState != esxVI_TaskInfoState_Success) {
4582         virReportError(VIR_ERR_INTERNAL_ERROR,
4583                        _("Could not delete snapshot '%s': %s"), snapshot->name,
4584                        taskInfoErrorMessage);
4585         goto cleanup;
4586     }
4587 
4588     result = 0;
4589 
4590  cleanup:
4591     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
4592     esxVI_ManagedObjectReference_Free(&task);
4593     return result;
4594 }
4595 
4596 
4597 
4598 static int
esxDomainSetMemoryParameters(virDomainPtr domain,virTypedParameterPtr params,int nparams,unsigned int flags)4599 esxDomainSetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4600                              int nparams, unsigned int flags)
4601 {
4602     int result = -1;
4603     esxPrivate *priv = domain->conn->privateData;
4604     esxVI_ObjectContent *virtualMachine = NULL;
4605     esxVI_VirtualMachineConfigSpec *spec = NULL;
4606     esxVI_ManagedObjectReference *task = NULL;
4607     esxVI_TaskInfoState taskInfoState;
4608     g_autofree char *taskInfoErrorMessage = NULL;
4609     size_t i;
4610 
4611     virCheckFlags(0, -1);
4612     if (virTypedParamsValidate(params, nparams,
4613                                VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
4614                                VIR_TYPED_PARAM_ULLONG,
4615                                NULL) < 0)
4616         return -1;
4617 
4618     if (esxVI_EnsureSession(priv->primary) < 0)
4619         return -1;
4620 
4621     if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
4622           (priv->primary, domain->uuid, NULL, &virtualMachine,
4623            priv->parsedUri->autoAnswer) < 0 ||
4624         esxVI_VirtualMachineConfigSpec_Alloc(&spec) < 0 ||
4625         esxVI_ResourceAllocationInfo_Alloc(&spec->memoryAllocation) < 0) {
4626         goto cleanup;
4627     }
4628 
4629     for (i = 0; i < nparams; ++i) {
4630         if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
4631             if (esxVI_Long_Alloc(&spec->memoryAllocation->reservation) < 0)
4632                 goto cleanup;
4633 
4634             spec->memoryAllocation->reservation->value =
4635               VIR_DIV_UP(params[i].value.ul, 1024); /* Scale from kilobytes to megabytes */
4636         }
4637     }
4638 
4639     if (esxVI_ReconfigVM_Task(priv->primary, virtualMachine->obj, spec,
4640                               &task) < 0 ||
4641         esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
4642                                     esxVI_Occurrence_RequiredItem,
4643                                     priv->parsedUri->autoAnswer, &taskInfoState,
4644                                     &taskInfoErrorMessage) < 0) {
4645         goto cleanup;
4646     }
4647 
4648     if (taskInfoState != esxVI_TaskInfoState_Success) {
4649         virReportError(VIR_ERR_INTERNAL_ERROR,
4650                        _("Could not change memory parameters: %s"),
4651                        taskInfoErrorMessage);
4652         goto cleanup;
4653     }
4654 
4655     result = 0;
4656 
4657  cleanup:
4658     esxVI_ObjectContent_Free(&virtualMachine);
4659     esxVI_VirtualMachineConfigSpec_Free(&spec);
4660     esxVI_ManagedObjectReference_Free(&task);
4661     return result;
4662 }
4663 
4664 
4665 
4666 static int
esxDomainGetMemoryParameters(virDomainPtr domain,virTypedParameterPtr params,int * nparams,unsigned int flags)4667 esxDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params,
4668                              int *nparams, unsigned int flags)
4669 {
4670     int result = -1;
4671     esxPrivate *priv = domain->conn->privateData;
4672     esxVI_String *propertyNameList = NULL;
4673     esxVI_ObjectContent *virtualMachine = NULL;
4674     esxVI_Long *reservation = NULL;
4675 
4676     virCheckFlags(0, -1);
4677 
4678     if (*nparams == 0) {
4679         *nparams = 1; /* min_guarantee */
4680         return 0;
4681     }
4682 
4683     if (esxVI_EnsureSession(priv->primary) < 0)
4684         return -1;
4685 
4686     if (esxVI_String_AppendValueToList
4687           (&propertyNameList, "config.memoryAllocation.reservation") < 0 ||
4688         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
4689                                          propertyNameList, &virtualMachine,
4690                                          esxVI_Occurrence_RequiredItem) < 0 ||
4691         esxVI_GetLong(virtualMachine, "config.memoryAllocation.reservation",
4692                       &reservation, esxVI_Occurrence_RequiredItem) < 0) {
4693         goto cleanup;
4694     }
4695 
4696     /* Scale from megabytes to kilobytes */
4697     if (virTypedParameterAssign(params, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
4698                                 VIR_TYPED_PARAM_ULLONG,
4699                                 reservation->value * 1024) < 0)
4700         goto cleanup;
4701 
4702     *nparams = 1;
4703     result = 0;
4704 
4705  cleanup:
4706     esxVI_String_Free(&propertyNameList);
4707     esxVI_ObjectContent_Free(&virtualMachine);
4708     esxVI_Long_Free(&reservation);
4709 
4710     return result;
4711 }
4712 
4713 #define MATCH(FLAG) (flags & (FLAG))
4714 static int
esxConnectListAllDomains(virConnectPtr conn,virDomainPtr ** domains,unsigned int flags)4715 esxConnectListAllDomains(virConnectPtr conn,
4716                          virDomainPtr **domains,
4717                          unsigned int flags)
4718 {
4719     int ret = -1;
4720     esxPrivate *priv = conn->privateData;
4721     bool needIdentity;
4722     bool needPowerState;
4723     virDomainPtr dom;
4724     virDomainPtr *doms = NULL;
4725     size_t ndoms = 0;
4726     esxVI_String *propertyNameList = NULL;
4727     esxVI_ObjectContent *virtualMachineList = NULL;
4728     esxVI_ObjectContent *virtualMachine = NULL;
4729     esxVI_AutoStartDefaults *autoStartDefaults = NULL;
4730     esxVI_VirtualMachinePowerState powerState;
4731     esxVI_AutoStartPowerInfo *powerInfoList = NULL;
4732     esxVI_AutoStartPowerInfo *powerInfo = NULL;
4733     esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
4734     int id;
4735     unsigned char uuid[VIR_UUID_BUFLEN];
4736     int count = 0;
4737     bool autostart;
4738     int state;
4739     esxVI_DynamicProperty *dynamicProperty = NULL;
4740 
4741     virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
4742 
4743     /* check for flags that would produce empty output lists:
4744      * - persistence: all esx machines are persistent
4745      * - managed save: esx doesn't support managed save
4746      */
4747     if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
4748          !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
4749         (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
4750          !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
4751         if (domains)
4752             *domains = g_new0(virDomainPtr, 1);
4753 
4754         ret = 0;
4755         goto cleanup;
4756     }
4757 
4758     if (esxVI_EnsureSession(priv->primary) < 0)
4759         return -1;
4760 
4761     /* check system default autostart value */
4762     if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
4763         if (esxVI_LookupAutoStartDefaults(priv->primary,
4764                                           &autoStartDefaults) < 0) {
4765             goto cleanup;
4766         }
4767 
4768         if (autoStartDefaults->enabled == esxVI_Boolean_True) {
4769             if (esxVI_LookupAutoStartPowerInfoList(priv->primary,
4770                                                    &powerInfoList) < 0) {
4771                 goto cleanup;
4772             }
4773         }
4774     }
4775 
4776     needIdentity = MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT) ||
4777                    domains;
4778 
4779     if (needIdentity) {
4780         /* Request required data for esxVI_GetVirtualMachineIdentity */
4781         if (esxVI_String_AppendValueListToList(&propertyNameList,
4782                                                "configStatus\0"
4783                                                "name\0"
4784                                                "config.uuid\0") < 0) {
4785             goto cleanup;
4786         }
4787     }
4788 
4789     needPowerState = MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) ||
4790                      MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) ||
4791                      domains;
4792 
4793     if (needPowerState) {
4794         if (esxVI_String_AppendValueToList(&propertyNameList,
4795                                            "runtime.powerState") < 0) {
4796             goto cleanup;
4797         }
4798     }
4799 
4800     if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
4801         if (esxVI_String_AppendValueToList(&propertyNameList,
4802                                            "snapshot.rootSnapshotList") < 0) {
4803             goto cleanup;
4804         }
4805     }
4806 
4807     if (esxVI_LookupVirtualMachineList(priv->primary, propertyNameList,
4808                                        &virtualMachineList) < 0)
4809         goto cleanup;
4810 
4811     if (domains) {
4812         doms = g_new0(virDomainPtr, 1);
4813         ndoms = 1;
4814     }
4815 
4816     for (virtualMachine = virtualMachineList; virtualMachine;
4817          virtualMachine = virtualMachine->_next) {
4818         g_autofree char *name = NULL;
4819 
4820         if (needIdentity) {
4821             if (esxVI_GetVirtualMachineIdentity(virtualMachine, &id,
4822                                                 &name, uuid) < 0) {
4823                 goto cleanup;
4824             }
4825         }
4826 
4827         if (needPowerState) {
4828             if (esxVI_GetVirtualMachinePowerState(virtualMachine,
4829                                                   &powerState) < 0) {
4830                 goto cleanup;
4831             }
4832         }
4833 
4834         /* filter by active state */
4835         if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
4836             !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) &&
4837                powerState != esxVI_VirtualMachinePowerState_PoweredOff) ||
4838               (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) &&
4839                powerState == esxVI_VirtualMachinePowerState_PoweredOff)))
4840             continue;
4841 
4842         /* filter by snapshot existence */
4843         if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
4844 
4845             esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4846 
4847             for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
4848                 dynamicProperty = dynamicProperty->_next) {
4849                 if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
4850                     if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
4851                         (dynamicProperty->val, &rootSnapshotTreeList) < 0) {
4852                         goto cleanup;
4853                     }
4854 
4855                     break;
4856                 }
4857             }
4858 
4859             if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
4860                    rootSnapshotTreeList) ||
4861                   (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
4862                    !rootSnapshotTreeList)))
4863                 continue;
4864         }
4865 
4866         /* filter by autostart */
4867         if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) {
4868             autostart = false;
4869 
4870             if (autoStartDefaults->enabled == esxVI_Boolean_True) {
4871                 for (powerInfo = powerInfoList; powerInfo;
4872                      powerInfo = powerInfo->_next) {
4873                     if (STREQ(powerInfo->key->value, virtualMachine->obj->value)) {
4874                         if (STRCASEEQ(powerInfo->startAction, "powerOn"))
4875                             autostart = true;
4876 
4877                         break;
4878                     }
4879                 }
4880             }
4881 
4882             if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
4883                    autostart) ||
4884                   (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) &&
4885                    !autostart)))
4886                 continue;
4887         }
4888 
4889         /* filter by domain state */
4890         if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) {
4891             state = esxVI_VirtualMachinePowerState_ConvertToLibvirt(powerState);
4892 
4893             if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
4894                    state == VIR_DOMAIN_RUNNING) ||
4895                   (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
4896                    state == VIR_DOMAIN_PAUSED) ||
4897                   (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
4898                    state == VIR_DOMAIN_SHUTOFF) ||
4899                   (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
4900                    (state != VIR_DOMAIN_RUNNING &&
4901                     state != VIR_DOMAIN_PAUSED &&
4902                     state != VIR_DOMAIN_SHUTOFF))))
4903                 continue;
4904         }
4905 
4906         /* just count the machines */
4907         if (!doms) {
4908             count++;
4909             continue;
4910         }
4911 
4912         VIR_RESIZE_N(doms, ndoms, count, 2);
4913 
4914         /* Only running/suspended virtual machines have an ID != -1 */
4915         if (powerState == esxVI_VirtualMachinePowerState_PoweredOff)
4916             id = -1;
4917 
4918         if (!(dom = virGetDomain(conn, name, uuid, id)))
4919             goto cleanup;
4920 
4921         doms[count++] = dom;
4922     }
4923 
4924     if (doms) {
4925         *domains = g_steal_pointer(&doms);
4926     }
4927     ret = count;
4928 
4929  cleanup:
4930     if (doms) {
4931         for (id = 0; id < count; id++)
4932             virObjectUnref(doms[id]);
4933 
4934         g_free(doms);
4935     }
4936 
4937     esxVI_AutoStartDefaults_Free(&autoStartDefaults);
4938     esxVI_AutoStartPowerInfo_Free(&powerInfoList);
4939     esxVI_String_Free(&propertyNameList);
4940     esxVI_ObjectContent_Free(&virtualMachineList);
4941     esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
4942 
4943     return ret;
4944 }
4945 #undef MATCH
4946 
4947 static int
esxDomainHasManagedSaveImage(virDomainPtr domain,unsigned int flags)4948 esxDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
4949 {
4950     int result = -1;
4951     esxPrivate *priv = domain->conn->privateData;
4952     esxVI_ManagedObjectReference *managedObjectReference = NULL;
4953     char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
4954 
4955     virCheckFlags(0, -1);
4956 
4957     if (esxVI_EnsureSession(priv->primary) < 0)
4958         return -1;
4959 
4960     virUUIDFormat(domain->uuid, uuid_string);
4961 
4962     if (esxVI_FindByUuid(priv->primary, priv->primary->datacenter->_reference,
4963                          uuid_string, esxVI_Boolean_True,
4964                          esxVI_Boolean_Undefined,
4965                          &managedObjectReference) < 0) {
4966         return -1;
4967     }
4968 
4969     if (!managedObjectReference) {
4970         virReportError(VIR_ERR_NO_DOMAIN,
4971                        _("Could not find domain with UUID '%s'"),
4972                        uuid_string);
4973         goto cleanup;
4974     }
4975 
4976     result = 0;
4977 
4978  cleanup:
4979     esxVI_ManagedObjectReference_Free(&managedObjectReference);
4980     return result;
4981 }
4982 
4983 
4984 static char *
esxDomainGetHostname(virDomainPtr domain,unsigned int flags)4985 esxDomainGetHostname(virDomainPtr domain,
4986                      unsigned int flags)
4987 {
4988     esxPrivate *priv = domain->conn->privateData;
4989     esxVI_String *propertyNameList = NULL;
4990     esxVI_ObjectContent *virtualMachine = NULL;
4991     esxVI_VirtualMachinePowerState powerState;
4992     char *hostname = NULL;
4993     char *new_hostname = NULL;
4994 
4995     virCheckFlags(0, NULL);
4996 
4997     if (esxVI_EnsureSession(priv->primary) < 0)
4998         return NULL;
4999 
5000     if (esxVI_String_AppendValueListToList(&propertyNameList,
5001                                        "runtime.powerState\0"
5002                                        "guest.hostName") < 0 ||
5003         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
5004                                          propertyNameList, &virtualMachine,
5005                                          esxVI_Occurrence_OptionalItem) ||
5006         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
5007         goto cleanup;
5008     }
5009 
5010     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
5011         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5012                        _("Domain is not powered on"));
5013         goto cleanup;
5014     }
5015 
5016     if (esxVI_GetStringValue(virtualMachine, "guest.hostName",
5017                              &hostname, esxVI_Occurrence_OptionalItem) < 0) {
5018         goto cleanup;
5019     }
5020 
5021     if (!hostname) {
5022         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5023                        _("hostName field not available (missing VMware Tools?)"));
5024         goto cleanup;
5025     }
5026 
5027     new_hostname = g_strdup(hostname);
5028 
5029  cleanup:
5030     esxVI_String_Free(&propertyNameList);
5031     esxVI_ObjectContent_Free(&virtualMachine);
5032 
5033     return new_hostname;
5034 }
5035 
5036 
5037 static int
esxParseIPAddress(const char * ipAddress,int prefixLength,virDomainIPAddress * addr)5038 esxParseIPAddress(const char *ipAddress, int prefixLength,
5039                   virDomainIPAddress *addr)
5040 {
5041     virSocketAddr tmp_addr;
5042     virIPAddrType addr_type;
5043 
5044     if (virSocketAddrParseAny(&tmp_addr, ipAddress, AF_UNSPEC, false) <= 0)
5045         return 0;
5046 
5047     switch (VIR_SOCKET_ADDR_FAMILY(&tmp_addr)) {
5048     case AF_INET:
5049         addr_type = VIR_IP_ADDR_TYPE_IPV4;
5050         break;
5051     case AF_INET6:
5052         addr_type = VIR_IP_ADDR_TYPE_IPV6;
5053         break;
5054     default:
5055         return 0;
5056     }
5057 
5058     addr->type = addr_type;
5059     addr->addr = g_strdup(ipAddress);
5060     addr->prefix = prefixLength;
5061 
5062     return 1;
5063 }
5064 
5065 
5066 static int
esxDomainInterfaceAddresses(virDomainPtr domain,virDomainInterfacePtr ** ifaces,unsigned int source,unsigned int flags)5067 esxDomainInterfaceAddresses(virDomainPtr domain,
5068                             virDomainInterfacePtr **ifaces,
5069                             unsigned int source,
5070                             unsigned int flags)
5071 {
5072     int result = -1;
5073     esxPrivate *priv = domain->conn->privateData;
5074     esxVI_String *propertyNameList = NULL;
5075     esxVI_ObjectContent *virtualMachine = NULL;
5076     esxVI_VirtualMachinePowerState powerState;
5077     esxVI_DynamicProperty *dynamicProperty;
5078     esxVI_GuestNicInfo *guestNicInfoList = NULL;
5079     esxVI_GuestNicInfo *guestNicInfo = NULL;
5080     virDomainInterfacePtr *ifaces_ret = NULL;
5081     size_t ifaces_count = 0;
5082     size_t i;
5083     int ret;
5084 
5085     virCheckFlags(0, -1);
5086     if (source != VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT) {
5087         virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
5088                        _("Unknown IP address data source %d"),
5089                        source);
5090         return -1;
5091     }
5092 
5093     if (esxVI_EnsureSession(priv->primary) < 0)
5094         return -1;
5095 
5096     if (esxVI_String_AppendValueListToList(&propertyNameList,
5097                                            "runtime.powerState\0"
5098                                            "guest.net") < 0 ||
5099         esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid,
5100                                          propertyNameList, &virtualMachine,
5101                                          esxVI_Occurrence_RequiredItem) ||
5102         esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) {
5103         goto cleanup;
5104     }
5105 
5106     if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
5107         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5108                        _("Domain is not powered on"));
5109         goto cleanup;
5110     }
5111 
5112     for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
5113          dynamicProperty = dynamicProperty->_next) {
5114         if (STREQ(dynamicProperty->name, "guest.net")) {
5115             if (esxVI_GuestNicInfo_CastListFromAnyType
5116                      (dynamicProperty->val, &guestNicInfoList) < 0) {
5117                 goto cleanup;
5118             }
5119         }
5120     }
5121 
5122     if (!guestNicInfoList) {
5123         virReportError(VIR_ERR_INTERNAL_ERROR,
5124                        _("Missing property '%s' in answer"),
5125                        "guest.net");
5126         goto cleanup;
5127     }
5128 
5129     for (guestNicInfo = guestNicInfoList; guestNicInfo;
5130          guestNicInfo = guestNicInfo->_next) {
5131         virDomainInterfacePtr iface = NULL;
5132         size_t addrs_count = 0;
5133 
5134         if (guestNicInfo->connected != esxVI_Boolean_True ||
5135             !guestNicInfo->network) {
5136             continue;
5137         }
5138 
5139         VIR_EXPAND_N(ifaces_ret, ifaces_count, 1);
5140         ifaces_ret[ifaces_count - 1] = g_new0(virDomainInterface, 1);
5141 
5142         iface = ifaces_ret[ifaces_count - 1];
5143         iface->naddrs = 0;
5144         iface->name = g_strdup(guestNicInfo->network);
5145         iface->hwaddr = g_strdup(guestNicInfo->macAddress);
5146 
5147         if (guestNicInfo->ipConfig) {
5148             esxVI_NetIpConfigInfoIpAddress *ipAddress;
5149             for (ipAddress = guestNicInfo->ipConfig->ipAddress; ipAddress;
5150                  ipAddress = ipAddress->_next) {
5151                 virDomainIPAddress ip_addr;
5152 
5153                 ret = esxParseIPAddress(ipAddress->ipAddress,
5154                                         ipAddress->prefixLength->value, &ip_addr);
5155                 if (ret < 0)
5156                     goto cleanup;
5157                 else if (ret == 0)
5158                     continue;
5159 
5160                 VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr);
5161             }
5162         } else {
5163             esxVI_String *str;
5164             for (str = guestNicInfo->ipAddress; str;
5165                  str = str->_next) {
5166                 virDomainIPAddress ip_addr;
5167 
5168                 /* Not even the netmask seems available... */
5169                 ret = esxParseIPAddress(str->value, 0, &ip_addr);
5170                 if (ret < 0)
5171                     goto cleanup;
5172                 else if (ret == 0)
5173                     continue;
5174 
5175                 VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr);
5176             }
5177         }
5178 
5179         iface->naddrs = addrs_count;
5180     }
5181 
5182     *ifaces = ifaces_ret;
5183     result = ifaces_count;
5184 
5185  cleanup:
5186     if (result < 0) {
5187         if (ifaces_ret) {
5188             for (i = 0; i < ifaces_count; i++)
5189                 virDomainInterfaceFree(ifaces_ret[i]);
5190         }
5191     }
5192     esxVI_String_Free(&propertyNameList);
5193     esxVI_ObjectContent_Free(&virtualMachine);
5194     esxVI_GuestNicInfo_Free(&guestNicInfoList);
5195 
5196     return result;
5197 }
5198 
5199 
5200 static virHypervisorDriver esxHypervisorDriver = {
5201     .name = "ESX",
5202     .connectOpen = esxConnectOpen, /* 0.7.0 */
5203     .connectClose = esxConnectClose, /* 0.7.0 */
5204     .connectSupportsFeature = esxConnectSupportsFeature, /* 0.7.0 */
5205     .connectGetType = esxConnectGetType, /* 0.7.0 */
5206     .connectGetVersion = esxConnectGetVersion, /* 0.7.0 */
5207     .connectGetHostname = esxConnectGetHostname, /* 0.7.0 */
5208     .nodeGetInfo = esxNodeGetInfo, /* 0.7.0 */
5209     .connectGetCapabilities = esxConnectGetCapabilities, /* 0.7.1 */
5210     .connectListDomains = esxConnectListDomains, /* 0.7.0 */
5211     .connectNumOfDomains = esxConnectNumOfDomains, /* 0.7.0 */
5212     .connectListAllDomains = esxConnectListAllDomains, /* 0.10.2 */
5213     .domainLookupByID = esxDomainLookupByID, /* 0.7.0 */
5214     .domainLookupByUUID = esxDomainLookupByUUID, /* 0.7.0 */
5215     .domainLookupByName = esxDomainLookupByName, /* 0.7.0 */
5216     .domainSuspend = esxDomainSuspend, /* 0.7.0 */
5217     .domainResume = esxDomainResume, /* 0.7.0 */
5218     .domainShutdown = esxDomainShutdown, /* 0.7.0 */
5219     .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
5220     .domainReboot = esxDomainReboot, /* 0.7.0 */
5221     .domainDestroy = esxDomainDestroy, /* 0.7.0 */
5222     .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
5223     .domainGetOSType = esxDomainGetOSType, /* 0.7.0 */
5224     .domainGetMaxMemory = esxDomainGetMaxMemory, /* 0.7.0 */
5225     .domainSetMaxMemory = esxDomainSetMaxMemory, /* 0.7.0 */
5226     .domainSetMemory = esxDomainSetMemory, /* 0.7.0 */
5227     .domainSetMemoryFlags = esxDomainSetMemoryFlags, /* 5.6.0 */
5228     .domainSetMemoryParameters = esxDomainSetMemoryParameters, /* 0.8.6 */
5229     .domainGetMemoryParameters = esxDomainGetMemoryParameters, /* 0.8.6 */
5230     .domainGetInfo = esxDomainGetInfo, /* 0.7.0 */
5231     .domainGetState = esxDomainGetState, /* 0.9.2 */
5232     .domainScreenshot = esxDomainScreenshot, /* 1.2.10 */
5233     .domainSetVcpus = esxDomainSetVcpus, /* 0.7.0 */
5234     .domainSetVcpusFlags = esxDomainSetVcpusFlags, /* 0.8.5 */
5235     .domainGetVcpusFlags = esxDomainGetVcpusFlags, /* 0.8.5 */
5236     .domainGetMaxVcpus = esxDomainGetMaxVcpus, /* 0.7.0 */
5237     .domainGetXMLDesc = esxDomainGetXMLDesc, /* 0.7.0 */
5238     .connectDomainXMLFromNative = esxConnectDomainXMLFromNative, /* 0.7.0 */
5239     .connectDomainXMLToNative = esxConnectDomainXMLToNative, /* 0.7.2 */
5240     .connectListDefinedDomains = esxConnectListDefinedDomains, /* 0.7.0 */
5241     .connectNumOfDefinedDomains = esxConnectNumOfDefinedDomains, /* 0.7.0 */
5242     .domainCreate = esxDomainCreate, /* 0.7.0 */
5243     .domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
5244     .domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
5245     .domainDefineXMLFlags = esxDomainDefineXMLFlags, /* 1.2.12 */
5246     .domainUndefine = esxDomainUndefine, /* 0.7.1 */
5247     .domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
5248     .domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
5249     .domainSetAutostart = esxDomainSetAutostart, /* 0.9.0 */
5250     .domainGetSchedulerType = esxDomainGetSchedulerType, /* 0.7.0 */
5251     .domainGetSchedulerParameters = esxDomainGetSchedulerParameters, /* 0.7.0 */
5252     .domainGetSchedulerParametersFlags = esxDomainGetSchedulerParametersFlags, /* 0.9.2 */
5253     .domainSetSchedulerParameters = esxDomainSetSchedulerParameters, /* 0.7.0 */
5254     .domainSetSchedulerParametersFlags = esxDomainSetSchedulerParametersFlags, /* 0.9.2 */
5255     .domainMigratePrepare = esxDomainMigratePrepare, /* 0.7.0 */
5256     .domainMigratePerform = esxDomainMigratePerform, /* 0.7.0 */
5257     .domainMigrateFinish = esxDomainMigrateFinish, /* 0.7.0 */
5258     .nodeGetFreeMemory = esxNodeGetFreeMemory, /* 0.7.2 */
5259     .connectIsEncrypted = esxConnectIsEncrypted, /* 0.7.3 */
5260     .connectIsSecure = esxConnectIsSecure, /* 0.7.3 */
5261     .domainIsActive = esxDomainIsActive, /* 0.7.3 */
5262     .domainIsPersistent = esxDomainIsPersistent, /* 0.7.3 */
5263     .domainIsUpdated = esxDomainIsUpdated, /* 0.8.6 */
5264     .domainSnapshotCreateXML = esxDomainSnapshotCreateXML, /* 0.8.0 */
5265     .domainSnapshotGetXMLDesc = esxDomainSnapshotGetXMLDesc, /* 0.8.0 */
5266     .domainSnapshotNum = esxDomainSnapshotNum, /* 0.8.0 */
5267     .domainSnapshotListNames = esxDomainSnapshotListNames, /* 0.8.0 */
5268     .domainSnapshotNumChildren = esxDomainSnapshotNumChildren, /* 0.9.7 */
5269     .domainSnapshotListChildrenNames = esxDomainSnapshotListChildrenNames, /* 0.9.7 */
5270     .domainSnapshotLookupByName = esxDomainSnapshotLookupByName, /* 0.8.0 */
5271     .domainHasCurrentSnapshot = esxDomainHasCurrentSnapshot, /* 0.8.0 */
5272     .domainSnapshotGetParent = esxDomainSnapshotGetParent, /* 0.9.7 */
5273     .domainSnapshotCurrent = esxDomainSnapshotCurrent, /* 0.8.0 */
5274     .domainRevertToSnapshot = esxDomainRevertToSnapshot, /* 0.8.0 */
5275     .domainSnapshotIsCurrent = esxDomainSnapshotIsCurrent, /* 0.9.13 */
5276     .domainSnapshotHasMetadata = esxDomainSnapshotHasMetadata, /* 0.9.13 */
5277     .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */
5278     .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */
5279     .domainHasManagedSaveImage = esxDomainHasManagedSaveImage, /* 1.2.13 */
5280     .domainGetHostname = esxDomainGetHostname, /* 6.8.0 */
5281     .domainInterfaceAddresses = esxDomainInterfaceAddresses, /* 6.8.0 */
5282 };
5283 
5284 
5285 static virConnectDriver esxConnectDriver = {
5286     .remoteOnly = true,
5287     .uriSchemes = (const char *[]){ "vpx", "esx", "gsx", NULL },
5288     .hypervisorDriver = &esxHypervisorDriver,
5289     .interfaceDriver = &esxInterfaceDriver,
5290     .networkDriver = &esxNetworkDriver,
5291     .storageDriver = &esxStorageDriver,
5292 };
5293 
5294 int
esxRegister(void)5295 esxRegister(void)
5296 {
5297     return virRegisterConnectDriver(&esxConnectDriver,
5298                                     false);
5299 }
5300