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(¶ms[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(¶ms[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(¶ms[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 ¤tSnapshotTree,
4339 esxVI_Occurrence_OptionalItem) < 0) {
4340 return -1;
4341 }
4342
4343 if (currentSnapshotTree) {
4344 esxVI_VirtualMachineSnapshotTree_Free(¤tSnapshotTree);
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 ¤tSnapshotTree,
4406 esxVI_Occurrence_RequiredItem) < 0) {
4407 return NULL;
4408 }
4409
4410 snapshot = virGetDomainSnapshot(domain, currentSnapshotTree->name);
4411
4412 esxVI_VirtualMachineSnapshotTree_Free(¤tSnapshotTree);
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 ¤tSnapshotTree,
4443 esxVI_Occurrence_RequiredItem) < 0) {
4444 goto cleanup;
4445 }
4446
4447 ret = STREQ(snapshot->name, currentSnapshotTree->name);
4448
4449 cleanup:
4450 esxVI_VirtualMachineSnapshotTree_Free(¤tSnapshotTree);
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