Hi, the development was hindered by our testing cluster being offline since 2 weeks due to server room cooling system maintenance. But I finally got a basic version of dump-XML done, that fills all fields of the virDomainDef that the VMX file contains data for. Changes since first announcement: - Move code into esx subdirectory - Add esxNodeGetInfo() - Fix esxDomainGetInfo() to report the correct value for memory - Add memory and max-memory getter/setters - Add CPU scheduler getter/setters - Validate a migration before trying to perform it - Replace esxUtil_Strdup() with strdup() and remove esxUtil_MigrateStringFromLibXML() - Add esxVI_EnsureSession() to handle expiring sessions - Separate VI client code into multiple files and generate most of the type handling code with macros - Add esxDomainDumpXML() based on esxVMX_ParseConfig() The ESX driver isn't complete yet, currently it supports: - domain lookup by ID, UUID and name - domain listing - domain info retrieval - domain suspend and resume - domain start and destroy - domain reboot and shutdown, if the VMware tools are installed inside the domain - domain migration with previous validation - domain memory configuration - domain CPU amount and scheduler configuration - domain XML-dump - domain XML-from-native (VMX) - node info retrieval - node hostname retrieval The next milestone is creating/defining a new domain from a domain XML config, but this will not be finished until feature freeze for 0.7.0 on friday. Regards, Matthias
diff --git a/configure.in b/configure.in index 634e812..552587c 100644 --- a/configure.in +++ b/configure.in @@ -193,6 +193,8 @@ AC_ARG_WITH([lxc], [ --with-lxc add Linux Container support (on)],[],[with_lxc=yes]) AC_ARG_WITH([one], [ --with-one add ONE support (on)],[],[with_one=check]) +AC_ARG_WITH([esx], +[ --with-esx add ESX support (on)],[],[with_esx=yes]) AC_ARG_WITH([test], [ --with-test add test driver support (on)],[],[with_test=yes]) AC_ARG_WITH([remote], @@ -317,6 +319,11 @@ if test "$with_one" = "yes" ; then fi AM_CONDITIONAL([WITH_ONE],[test "$with_one" = "yes"]) +if test "$with_esx" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) +fi +AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) + if test "$with_test" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_TEST], 1, [whether Test driver is enabled]) fi @@ -1084,6 +1091,26 @@ AM_CONDITIONAL([WITH_STORAGE_DISK], [test "$with_storage_disk" = "yes"]) AC_SUBST([LIBPARTED_CFLAGS]) AC_SUBST([LIBPARTED_LIBS]) +dnl +dnl check for libcurl +dnl + +LIBCURL_CFLAGS="" +LIBCURL_LIBS="" +LIBCURL_REQUIRED="7.18.0" +LIBCURL_FOUND="no" + +if test "$with_esx" = "yes" ; then + PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [LIBCURL_FOUND=yes], [LIBCURL_FOUND=no]) + + if test "$LIBCURL_FOUND" = "no"; then + AC_MSG_CHECKING(for libcurl libraries >= $LIBCURL_REQUIRED) + AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) + fi +fi + +AC_SUBST([LIBCURL_CFLAGS]) +AC_SUBST([LIBCURL_LIBS]) dnl dnl check for python @@ -1492,6 +1519,7 @@ AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ ONE: $with_one]) +AC_MSG_NOTICE([ ESX: $with_esx]) AC_MSG_NOTICE([ Test: $with_test]) AC_MSG_NOTICE([ Remote: $with_remote]) AC_MSG_NOTICE([ Network: $with_network]) @@ -1519,6 +1547,11 @@ AC_MSG_NOTICE([ dlopen: $DRIVER_MODULES_CFLAGS $DRIVER_MODULES_LIBS]) else AC_MSG_NOTICE([ dlopen: no]) fi +if test "$with_esx" = "yes" ; then +AC_MSG_NOTICE([ libcurl: $LIBCURL_CFLAGS $LIBCURL_LIBS]) +else +AC_MSG_NOTICE([ libcurl: no]) +fi AC_MSG_NOTICE([]) AC_MSG_NOTICE([Libraries]) AC_MSG_NOTICE([]) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 1092896..672572f 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -65,6 +65,7 @@ typedef enum { VIR_FROM_VBOX, /* Error from VirtualBox driver */ VIR_FROM_INTERFACE, /* Error when operating on an interface */ VIR_FROM_ONE, /* Error from OpenNebula driver */ + VIR_FROM_ESX, /* Error from ESX driver */ } virErrorDomain; diff --git a/src/Makefile.am b/src/Makefile.am index 9b662ae..ff83966 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,6 +156,14 @@ ONE_DRIVER_SOURCES = \ ./opennebula/one_client.c \ ./opennebula/one_client.h +ESX_DRIVER_SOURCES = \ + esx/esx_driver.c esx/esx_driver.h \ + esx/esx_util.c esx/esx_util.h \ + esx/esx_vi.c esx/esx_vi.h \ + esx/esx_vi_methods.c esx/esx_vi_methods.h \ + esx/esx_vi_types.c esx/esx_vi_types.h \ + esx/esx_vmx.c esx/esx_vmx.h + NETWORK_DRIVER_SOURCES = \ network_driver.h network_driver.c @@ -375,6 +383,21 @@ endif +if WITH_ESX +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_esx.la +else +noinst_LTLIBRARIES += libvirt_driver_esx.la +libvirt_la_LIBADD += libvirt_driver_esx.la +endif +libvirt_driver_esx_la_CFLAGS = $(LIBCURL_CFLAGS) +libvirt_driver_esx_la_LDFLAGS = $(LIBCURL_LIBS) +if WITH_DRIVER_MODULES +libvirt_driver_esx_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_esx_la_SOURCES = $(ESX_DRIVER_SOURCES) +endif + if WITH_NETWORK if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_network.la @@ -475,6 +498,7 @@ EXTRA_DIST += \ $(ONE_DRIVER_SOURCES) \ $(OPENVZ_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ + $(ESX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ diff --git a/src/driver.h b/src/driver.h index 2502c63..2d94444 100644 --- a/src/driver.h +++ b/src/driver.h @@ -22,6 +22,7 @@ typedef enum { VIR_DRV_UML = 7, VIR_DRV_VBOX = 8, VIR_DRV_ONE = 9, + VIR_DRV_ESX = 10, } virDrvNo; diff --git a/src/libvirt.c b/src/libvirt.c index f4a7fa7..46d3702 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -58,6 +58,9 @@ #ifdef WITH_VBOX #include "vbox/vbox_driver.h" #endif +#ifdef WITH_ESX +#include "esx/esx_driver.h" +#endif #endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -308,6 +311,7 @@ virInitialize(void) virDriverLoadModule("xen"); virDriverLoadModule("openvz"); virDriverLoadModule("vbox"); + virDriverLoadModule("esx"); virDriverLoadModule("remote"); #else #ifdef WITH_TEST @@ -322,6 +326,9 @@ virInitialize(void) #ifdef WITH_VBOX if (vboxRegister() == -1) return -1; #endif +#ifdef WITH_ESX + if (esxRegister() == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -905,6 +912,10 @@ virGetVersion(unsigned long *libVer, const char *type, if (STRCASEEQ(type, "ONE")) *typeVer = LIBVIR_VERSION_NUMBER; #endif +#if WITH_ESX + if (STRCASEEQ(type, "ESX")) + *typeVer = LIBVIR_VERSION_NUMBER; +#endif #if WITH_REMOTE if (STRCASEEQ(type, "Remote")) *typeVer = remoteVersion(); diff --git a/src/virterror.c b/src/virterror.c index d284fb8..587db72 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -163,6 +163,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_ONE: dom = "ONE "; break; + case VIR_FROM_ESX: + dom = "ESX "; + break; } return(dom); }
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c new file mode 100644 index 0000000..aa73e46 --- /dev/null +++ b/src/esx/esx_driver.c @@ -0,0 +1,2861 @@ + +/* + * esx_driver.c: core driver methods for managing VMware ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Maximilian Wilhelm <max@xxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Some links to relevant documentation: + * + * - Memory model: http://www.vmware.com/pdf/esx3_memory.pdf + * - VI API reference: http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/ + * - VMX-file parameters: http://www.sanbarrow.com/vmx.html + */ + +#include <config.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <netdb.h> + +#include "internal.h" +#include "virterror_internal.h" +#include "domain_conf.h" +#include "util.h" +#include "memory.h" +#include "logging.h" +#include "uuid.h" +#include "esx_driver.h" +#include "esx_vi.h" +#include "esx_vi_methods.h" +#include "esx_util.h" +#include "esx_vmx.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_ERROR(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + +static int esxDomainGetMaxVcpus(virDomainPtr domain); + +typedef struct _esxPrivate { + esxVI_Context *host; + esxVI_Context *vcenter; + int phantom; // boolean + char *transport; + int32_t nvcpus_max; + esxVI_Boolean supports_vmotion; + int32_t usedCpuTimeCounterId; +} esxPrivate; + + + +/* + * URI format: esx://[<user>@]<server>[?transport={http|https}][&vcenter=<vcenter>] + * esx:///phantom + */ +static virDrvOpenStatus +esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) +{ + esxPrivate *priv = NULL; + char dummy_string[NI_MAXHOST] = ""; + char *url = NULL; + char *vcenter = NULL; + char *username = NULL; + char *password = NULL; + int phantom = 0; + + /* Decline if the URI is NULL or the scheme is not 'esx' */ + if (conn->uri == NULL || conn->uri->scheme == NULL || + STRNEQ(conn->uri->scheme, "esx")) { + return VIR_DRV_OPEN_DECLINED; + } + + /* Check for 'esx:///phantom' URI */ + if (conn->uri->server == NULL && conn->uri->path != NULL && + STREQ(conn->uri->path, "/phantom")) { + phantom = 1; + } + + if (! phantom) { + /* Decline non-phantom URIs without server part, or missing auth */ + if (conn->uri->server == NULL || auth == NULL || auth->cb == NULL) { + return VIR_DRV_OPEN_DECLINED; + } + + if (conn->uri->path != NULL) { + VIR_WARN("Ignoring unexpected path '%s' in URI", conn->uri->path); + } + } + + /* Allocate per-connection private data */ + if (VIR_ALLOC(priv) < 0) { + virReportOOMError(conn); + goto failure; + } + + priv->phantom = phantom; + priv->nvcpus_max = -1; + priv->supports_vmotion = esxVI_Boolean_Undefined; + priv->usedCpuTimeCounterId = -1; + + /* Request credentials and login to non-phantom host/vCenter */ + if (! phantom) { + if (esxUtil_ParseQuery(conn, &priv->transport, &vcenter) < 0) { + goto failure; + } + + if (esxUtil_ResolveHostname(conn, conn->uri->server, dummy_string, + NI_MAXHOST) < 0) { + goto failure; + } + + if (vcenter != NULL && + esxUtil_ResolveHostname(conn, vcenter, dummy_string, + NI_MAXHOST) < 0) { + goto failure; + } + + if (virAsprintf(&url, "%s://%s/sdk", priv->transport, + conn->uri->server) < 0) { + virReportOOMError(conn); + goto failure; + } + + if (conn->uri->user != NULL) { + username = strdup(conn->uri->user); + + if (username == NULL) { + virReportOOMError(conn); + goto failure; + } + } else { + username = esxUtil_RequestUsername(auth, "root", conn->uri->server); + + if (username == NULL) { + ESX_ERROR(conn, VIR_ERR_AUTH_FAILED, "Username request failed"); + goto failure; + } + } + + if (esxVI_Context_Alloc(conn, &priv->host) < 0) { + goto failure; + } + + password = esxUtil_RequestPassword(auth, username, conn->uri->server); + + if (password == NULL) { + ESX_ERROR(conn, VIR_ERR_AUTH_FAILED, "Password request failed"); + goto failure; + } + + if (esxVI_Context_Connect(conn, priv->host, url, username, + password) < 0) { + goto failure; + } + + VIR_FREE(url); + VIR_FREE(password); + VIR_FREE(username); + + if (vcenter != NULL) { + if (virAsprintf(&url, "%s://%s/sdk", priv->transport, + vcenter) < 0) { + virReportOOMError(conn); + goto failure; + } + + if (esxVI_Context_Alloc(conn, &priv->vcenter) < 0) { + goto failure; + } + + username = esxUtil_RequestUsername(auth, "administrator", vcenter); + + if (username == NULL) { + ESX_ERROR(conn, VIR_ERR_AUTH_FAILED, + "Username request failed"); + goto failure; + } + + password = esxUtil_RequestPassword(auth, username, vcenter); + + if (password == NULL) { + ESX_ERROR(conn, VIR_ERR_AUTH_FAILED, + "Password request failed"); + goto failure; + } + + if (esxVI_Context_Connect(conn, priv->vcenter, url, username, + password) < 0) { + goto failure; + } + + VIR_FREE(url); + VIR_FREE(password); + VIR_FREE(username); + } + + VIR_FREE(vcenter); + } + + conn->privateData = priv; + + return VIR_DRV_OPEN_SUCCESS; + + failure: + VIR_FREE(url); + VIR_FREE(vcenter); + VIR_FREE(password); + VIR_FREE(username); + + if (priv != NULL) { + esxVI_Context_Free(&priv->host); + esxVI_Context_Free(&priv->vcenter); + + VIR_FREE(priv); + } + + return VIR_DRV_OPEN_ERROR; +} + + + +static int +esxClose(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + + if (! priv->phantom) { + esxVI_EnsureSession(conn, priv->host); + + esxVI_Logout(conn, priv->host); + esxVI_Context_Free(&priv->host); + + if (priv->vcenter != NULL) { + esxVI_EnsureSession(conn, priv->vcenter); + + esxVI_Logout(conn, priv->vcenter); + esxVI_Context_Free(&priv->vcenter); + } + } + + VIR_FREE(priv->transport); + VIR_FREE(priv); + + conn->privateData = NULL; + + return 0; +} + + + +static esxVI_Boolean +esxSupportsVMotion(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (priv->supports_vmotion != esxVI_Boolean_Undefined) { + return priv->supports_vmotion; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(conn, &propertyNameList, + "capability.vmotionSupported") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->hostFolder, + "HostSystem", propertyNameList, + esxVI_Boolean_True, &hostSystem) < 0) { + goto failure; + } + + if (hostSystem == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the HostSystem object"); + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "capability.vmotionSupported")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Boolean) < 0) { + goto failure; + } + + priv->supports_vmotion = dynamicProperty->val->boolean; + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return priv->supports_vmotion; + + failure: + priv->supports_vmotion = esxVI_Boolean_Undefined; + + goto cleanup; +} + + + +static int +esxSupportsFeature(virConnectPtr conn, int feature) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_Boolean supports_vmotion = esxVI_Boolean_Undefined; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return -1; + } + + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V1: + supports_vmotion = esxSupportsVMotion(conn); + + if (supports_vmotion == esxVI_Boolean_Undefined) { + return -1; + } + + /* + * Migration is only possible via a Virtual Center and if VMotion is + * enabled + */ + return priv->vcenter != NULL && + supports_vmotion == esxVI_Boolean_True ? 1 : 0; + + default: + return 0; + } +} + + + +static const char * +esxGetType(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "ESX"; +} + + + +static int +esxGetVersion(virConnectPtr conn, unsigned long *version) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + char *temp; + unsigned int major, minor, release; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return -1; + } + + temp = (char *)priv->host->service->about->version; + + /* Expecting 'major.minor.release' format */ + if (virStrToLong_ui(temp, &temp, 10, &major) < 0 || temp == NULL || + *temp != '.') { + goto failure; + } + + if (virStrToLong_ui(temp + 1, &temp, 10, &minor) < 0 || temp == NULL || + *temp != '.') { + goto failure; + } + + if (virStrToLong_ui(temp + 1, NULL, 10, &release) < 0) { + goto failure; + } + + *version = 1000000 * major + 1000 * minor + release; + + return 0; + + failure: + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting version to match 'major.minor.release', but got '%s'", + priv->host->service->about->version); + + return -1; +} + + + +static char * +esxGetHostname(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + const char *hostName = NULL; + const char *domainName = NULL; + char *complete = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList + (conn, &propertyNameList, + "config.network.dnsConfig.hostName\0" + "config.network.dnsConfig.domainName\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->hostFolder, + "HostSystem", propertyNameList, + esxVI_Boolean_True, &hostSystem) < 0) { + goto failure; + } + + if (hostSystem == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the HostSystem object"); + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, + "config.network.dnsConfig.hostName")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + hostName = dynamicProperty->val->string; + } else if (STREQ(dynamicProperty->name, + "config.network.dnsConfig.domainName")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + domainName = dynamicProperty->val->string; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (hostName == NULL || strlen (hostName) < 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing or empty 'hostName' property"); + goto failure; + } + + if (domainName == NULL || strlen (domainName) < 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing or empty 'domainName' property"); + goto failure; + } + + if (virAsprintf(&complete, "%s.%s", hostName, domainName) < 0) { + virReportOOMError(conn); + goto failure; + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return complete; + + failure: + VIR_FREE(complete); + + goto cleanup; +} + + + + +static int +esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + int64_t cpuInfo_hz = 0; + int16_t cpuInfo_numCpuCores = 0; + int16_t cpuInfo_numCpuPackages = 0; + int16_t cpuInfo_numCpuThreads = 0; + int64_t memorySize = 0; + int32_t numaInfo_numNodes = 0; + char *ptr = NULL; + + memset (nodeinfo, 0, sizeof (virNodeInfo)); + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "hardware.cpuInfo.hz\0" + "hardware.cpuInfo.numCpuCores\0" + "hardware.cpuInfo.numCpuPackages\0" + "hardware.cpuInfo.numCpuThreads\0" + "hardware.memorySize\0" + "hardware.numaInfo.numNodes\0" + "summary.hardware.cpuModel\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->hostFolder, + "HostSystem", propertyNameList, + esxVI_Boolean_True, &hostSystem) < 0) { + goto failure; + } + + if (hostSystem == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the HostSystem object"); + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "hardware.cpuInfo.hz")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto failure; + } + + cpuInfo_hz = dynamicProperty->val->int64; + } else if (STREQ(dynamicProperty->name, + "hardware.cpuInfo.numCpuCores")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Short) < 0) { + goto failure; + } + + cpuInfo_numCpuCores = dynamicProperty->val->int16; + } else if (STREQ(dynamicProperty->name, + "hardware.cpuInfo.numCpuPackages")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Short) < 0) { + goto failure; + } + + cpuInfo_numCpuPackages = dynamicProperty->val->int16; + } else if (STREQ(dynamicProperty->name, + "hardware.cpuInfo.numCpuThreads")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Short) < 0) { + goto failure; + } + + cpuInfo_numCpuThreads = dynamicProperty->val->int16; + } else if (STREQ(dynamicProperty->name, "hardware.memorySize")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto failure; + } + + memorySize = dynamicProperty->val->int64; + } else if (STREQ(dynamicProperty->name, + "hardware.numaInfo.numNodes")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_Int) < 0) { + goto failure; + } + + numaInfo_numNodes = dynamicProperty->val->int32; + } else if (STREQ(dynamicProperty->name, + "summary.hardware.cpuModel")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + ptr = dynamicProperty->val->string; + + /* Strip the string to fit more relevant information in 32 chars */ + while (*ptr != '\0') { + if (STRPREFIX (ptr, " ")) { + memmove(ptr, ptr + 1, strlen (ptr + 1) + 1); + continue; + } else if (STRPREFIX (ptr, "(R)")) { + memmove(ptr, ptr + 3, strlen (ptr + 3) + 1); + continue; + } + + ++ptr; + } + + strncpy (nodeinfo->model, dynamicProperty->val->string, + sizeof (nodeinfo->model) - 1); + nodeinfo->model[sizeof (nodeinfo->model) - 1] = '\0'; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + nodeinfo->memory = memorySize / 1024; /* Scale from bytes to kilobytes */ + nodeinfo->cpus = cpuInfo_numCpuCores; + nodeinfo->mhz = cpuInfo_hz / (1024 * 1024); /* Scale from hz to mhz */ + nodeinfo->nodes = numaInfo_numNodes; + nodeinfo->sockets = cpuInfo_numCpuPackages; + nodeinfo->cores = cpuInfo_numCpuPackages > 0 + ? cpuInfo_numCpuCores / cpuInfo_numCpuPackages + : 0; + nodeinfo->threads = cpuInfo_numCpuCores > 0 + ? cpuInfo_numCpuThreads / cpuInfo_numCpuCores + : 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxListDomains(virConnectPtr conn, int *ids, int maxids) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + int count = 0; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (ids == NULL || maxids < 0) { + goto failure; + } + + if (maxids == 0) { + return 0; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->vmFolder, + "VirtualMachine", propertyNameList, + esxVI_Boolean_True, &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + if (esxVI_GetVirtualMachinePowerState(conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + continue; + } + + if (esxUtil_ParseVirtualMachineIDString(virtualMachine->obj->value, + &ids[count]) < 0 || + ids[count] <= 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Failed to parse positive integer from '%s'", + virtualMachine->obj->value); + goto failure; + } + + count++; + + if (count >= maxids) { + break; + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + + return count; + + failure: + count = -1; + + goto cleanup; +} + + + +static int +esxNumberOfDomains(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return -1; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + return -1; + } + + return esxVI_GetNumberOfDomainsByPowerState + (conn, priv->host, esxVI_VirtualMachinePowerState_PoweredOn, + esxVI_Boolean_False); +} + + + +static virDomainPtr +esxDomainLookupByID(virConnectPtr conn, int id) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + int id_ = -1; + char *name_ = NULL; + unsigned char uuid_[VIR_UUID_BUFLEN]; + virDomainPtr domain = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "name\0" + "runtime.powerState\0" + "summary.config.uuid\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->vmFolder, + "VirtualMachine", propertyNameList, + esxVI_Boolean_True, &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + if (esxVI_GetVirtualMachinePowerState(conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + /* Only running/suspended domains have an ID != -1 */ + if (powerState == esxVI_VirtualMachinePowerState_PoweredOff) { + continue; + } + + VIR_FREE(name_); + + if (esxVI_GetVirtualMachineIdentity(conn, virtualMachine, &id_, + &name_, uuid_) < 0) { + goto failure; + } + + if (id_ != id) { + continue; + } + + domain = virGetDomain(conn, name_, uuid_); + + if (domain == NULL) { + goto failure; + } + + domain->id = id; + + break; + } + + if (domain == NULL) { + ESX_ERROR(conn, VIR_ERR_NO_DOMAIN, "No domain with ID %d", id); + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + VIR_FREE(name_); + + return domain; + + failure: + domain = NULL; + + goto cleanup; +} + + + +static virDomainPtr +esxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + int id_ = -1; + char *name_ = NULL; + unsigned char uuid_[VIR_UUID_BUFLEN]; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + virDomainPtr domain = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "name\0" + "runtime.powerState\0" + "summary.config.uuid\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->vmFolder, + "VirtualMachine", propertyNameList, + esxVI_Boolean_True, &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + VIR_FREE(name_); + + if (esxVI_GetVirtualMachineIdentity(conn, virtualMachine, &id_, + &name_, uuid_) < 0) { + goto failure; + } + + if (memcmp(uuid, uuid_, + VIR_UUID_BUFLEN * sizeof (unsigned char)) != 0) { + continue; + } + + domain = virGetDomain(conn, name_, uuid); + + if (domain == NULL) { + goto failure; + } + + if (esxVI_GetVirtualMachinePowerState(conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + /* Only running/suspended virtual machines have an ID != -1 */ + if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) { + domain->id = id_; + } else { + domain->id = -1; + } + + break; + } + + if (domain == NULL) { + virUUIDFormat(uuid, uuid_string); + + ESX_ERROR(conn, VIR_ERR_NO_DOMAIN, "No domain with UUID '%s'", + uuid_string); + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + VIR_FREE(name_); + + return domain; + + failure: + domain = NULL; + + goto cleanup; +} + + + +static virDomainPtr +esxDomainLookupByName(virConnectPtr conn, const char *name) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + int id_ = -1; + char *name_ = NULL; + unsigned char uuid_[VIR_UUID_BUFLEN]; + virDomainPtr domain = NULL; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "name\0" + "runtime.powerState\0" + "summary.config.uuid\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->vmFolder, + "VirtualMachine", propertyNameList, + esxVI_Boolean_True, &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + VIR_FREE(name_); + + if (esxVI_GetVirtualMachineIdentity(conn, virtualMachine, &id_, + &name_, uuid_) < 0) { + goto failure; + } + + if (STRNEQ(name_, name)) { + continue; + } + + domain = virGetDomain(conn, name, uuid_); + + if (domain == NULL) { + goto failure; + } + + if (esxVI_GetVirtualMachinePowerState(conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + /* Only running/suspended virtual machines have an ID != -1 */ + if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) { + domain->id = id_; + } else { + domain->id = -1; + } + + break; + } + + if (domain == NULL) { + ESX_ERROR(conn, VIR_ERR_NO_DOMAIN, "No domain with name '%s'", name); + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + VIR_FREE(name_); + + return domain; + + failure: + domain = NULL; + + goto cleanup; +} + + + +static int +esxDomainSuspend(virDomainPtr domain) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not powered on"); + goto failure; + } + + if (esxVI_SuspendVM_Task(domain->conn, priv->host, virtualMachine->obj, + &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not suspend domain"); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainResume(virDomainPtr domain) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_Suspended) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not suspended"); + goto failure; + } + + if (esxVI_PowerOnVM_Task(domain->conn, priv->host, virtualMachine->obj, + &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not resume domain"); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainShutdown(virDomainPtr domain) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not powered on"); + goto failure; + } + + if (esxVI_ShutdownGuest(domain->conn, priv->host, + virtualMachine->obj) < 0) { + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not powered on"); + goto failure; + } + + if (esxVI_RebootGuest(domain->conn, priv->host, virtualMachine->obj) < 0) { + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainDestroy(virDomainPtr domain) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not powered on"); + goto failure; + } + + if (esxVI_PowerOffVM_Task(domain->conn, priv->host, virtualMachine->obj, + &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not destory domain"); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static char * +esxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) +{ + return strdup("hvm"); +} + + + +static unsigned long +esxDomainGetMaxMemory(virDomainPtr domain) +{ + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + unsigned long memoryMB = 0; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "config.hardware.memoryMB") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0) { + goto failure; + } + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Int) < 0) { + goto failure; + } + + if (dynamicProperty->val->int32 < 0) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Got invalid memory size %d", + dynamicProperty->val->int32); + } else { + memoryMB = dynamicProperty->val->int32; + } + + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + + return memoryMB * 1024; /* Scale from megabyte to kilobyte */ + + failure: + memoryMB = 0; + + goto cleanup; +} + + + +static int +esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachineConfigSpec *spec = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, NULL, + &virtualMachine) < 0 || + esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 || + esxVI_Long_Alloc(domain->conn, &spec->memoryMB) < 0) { + goto failure; + } + + spec->memoryMB->value = + memory / 1024; /* Scale from kilobytes to megabytes */ + + if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj, + spec, &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not set max-memory to %lu kilobytes", memory); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_VirtualMachineConfigSpec_Free(&spec); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainSetMemory(virDomainPtr domain, unsigned long memory) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachineConfigSpec *spec = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, NULL, + &virtualMachine) < 0 || + esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 || + esxVI_ResourceAllocationInfo_Alloc(domain->conn, + &spec->memoryAllocation) < 0 || + esxVI_Long_Alloc(domain->conn, &spec->memoryAllocation->limit) < 0) { + goto failure; + } + + spec->memoryAllocation->limit->value = + memory / 1024; /* Scale from kilobytes to megabytes */ + + if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj, + spec, &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not set memory to %lu kilobytes", memory); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_VirtualMachineConfigSpec_Free(&spec); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_VirtualMachinePowerState powerState; + int64_t memory_limit = -1; + esxVI_PerfMetricId *perfMetricId = NULL; + esxVI_PerfMetricId *perfMetricIdList = NULL; + esxVI_Int *counterId = NULL; + esxVI_Int *counterIdList = NULL; + esxVI_PerfCounterInfo *perfCounterInfo = NULL; + esxVI_PerfCounterInfo *perfCounterInfoList = NULL; + esxVI_PerfQuerySpec *querySpec = NULL; + esxVI_PerfEntityMetric *perfEntityMetric = NULL; + esxVI_PerfEntityMetric *perfEntityMetricList = NULL; + esxVI_PerfMetricIntSeries *perfMetricIntSeries = NULL; + esxVI_Long *value = NULL; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(domain->conn, &propertyNameList, + "runtime.powerState\0" + "config.hardware.memoryMB\0" + "config.hardware.numCPU\0" + "config.memoryAllocation.limit\0") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0) { + goto failure; + } + + info->state = VIR_DOMAIN_NOSTATE; + info->maxMem = 0; + info->memory = 0; + info->nrVirtCpu = 0; + info->cpuTime = 0; /* FIXME */ + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "runtime.powerState")) { + if (esxVI_VirtualMachinePowerState_CastFromAnyType + (domain->conn, dynamicProperty->val, &powerState) < 0) { + goto failure; + } + + switch (powerState) { + case esxVI_VirtualMachinePowerState_PoweredOff: + info->state = VIR_DOMAIN_SHUTOFF; + break; + + case esxVI_VirtualMachinePowerState_PoweredOn: + info->state = VIR_DOMAIN_RUNNING; + break; + + case esxVI_VirtualMachinePowerState_Suspended: + info->state = VIR_DOMAIN_PAUSED; + break; + + default: + info->state = VIR_DOMAIN_NOSTATE; + break; + } + } else if (STREQ(dynamicProperty->name, "config.hardware.memoryMB")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Int) < 0) { + goto failure; + } + + info->maxMem = dynamicProperty->val->int32 * 1024; /* Scale from megabyte to kilobyte */ + } else if (STREQ(dynamicProperty->name, "config.hardware.numCPU")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Int) < 0) { + goto failure; + } + + info->nrVirtCpu = dynamicProperty->val->int32; + } else if (STREQ(dynamicProperty->name, + "config.memoryAllocation.limit")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto failure; + } + + memory_limit = dynamicProperty->val->int64; + + if (memory_limit > 0) { + memory_limit *= 1024; /* Scale from megabyte to kilobyte */ + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + /* memory_limit < 0 means no memory limit is set */ + info->memory = memory_limit < 0 ? info->maxMem : memory_limit; + + /* Verify the cached 'used CPU time' performance counter ID */ + if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) { + if (esxVI_Int_Alloc(domain->conn, &counterId) < 0) { + goto failure; + } + + counterId->value = priv->usedCpuTimeCounterId; + + if (esxVI_Int_AppendToList(domain->conn, &counterIdList, + counterId) < 0) { + goto failure; + } + + if (esxVI_QueryPerfCounter(domain->conn, priv->host, counterIdList, + &perfCounterInfo) < 0) { + goto failure; + } + + if (STRNEQ(perfCounterInfo->groupInfo->key, "cpu") || + STRNEQ(perfCounterInfo->nameInfo->key, "used") || + STRNEQ(perfCounterInfo->unitInfo->key, "millisecond")) { + VIR_DEBUG("Cached usedCpuTimeCounterId %d is invalid", + priv->usedCpuTimeCounterId); + + priv->usedCpuTimeCounterId = -1; + } + + esxVI_Int_Free(&counterIdList); + esxVI_PerfCounterInfo_Free(&perfCounterInfo); + } + + /* + * Query the PerformanceManager for the 'used CPU time' performance + * counter ID and cache it, if it's not already cached. + */ + if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId < 0) { + if (esxVI_QueryAvailablePerfMetric(domain->conn, priv->host, + virtualMachine->obj, NULL, NULL, + NULL, &perfMetricIdList) < 0) { + goto failure; + } + + for (perfMetricId = perfMetricIdList; perfMetricId != NULL; + perfMetricId = perfMetricId->_next) { + VIR_DEBUG("perfMetricId counterId %d, instance '%s'", + perfMetricId->counterId->value, perfMetricId->instance); + + counterId = NULL; + + if (esxVI_Int_DeepCopy(domain->conn, &counterId, + perfMetricId->counterId) < 0 || + esxVI_Int_AppendToList(domain->conn, &counterIdList, + counterId) < 0) { + goto failure; + } + } + + if (esxVI_QueryPerfCounter(domain->conn, priv->host, counterIdList, + &perfCounterInfoList) < 0) { + goto failure; + } + + for (perfCounterInfo = perfCounterInfoList; perfCounterInfo != NULL; + perfCounterInfo = perfCounterInfo->_next) { + VIR_DEBUG("perfCounterInfo key %d, nameInfo '%s', groupInfo '%s', " + "unitInfo '%s', rollupType %d, statsType %d", + perfCounterInfo->key->value, + perfCounterInfo->nameInfo->key, + perfCounterInfo->groupInfo->key, + perfCounterInfo->unitInfo->key, + perfCounterInfo->rollupType, + perfCounterInfo->statsType); + + if (STREQ(perfCounterInfo->groupInfo->key, "cpu") && + STREQ(perfCounterInfo->nameInfo->key, "used") && + STREQ(perfCounterInfo->unitInfo->key, "millisecond")) { + priv->usedCpuTimeCounterId = perfCounterInfo->key->value; + break; + } + } + + if (priv->usedCpuTimeCounterId < 0) { + VIR_WARN0("Could not find 'used CPU time' performance counter"); + } + } + + /* + * Query the PerformanceManager for the 'used CPU time' performance + * counter value. + */ + if (info->state == VIR_DOMAIN_RUNNING && priv->usedCpuTimeCounterId >= 0) { + VIR_DEBUG("usedCpuTimeCounterId %d BEGIN", priv->usedCpuTimeCounterId); + + if (esxVI_PerfQuerySpec_Alloc(domain->conn, &querySpec) < 0 || + esxVI_Int_Alloc(domain->conn, &querySpec->maxSample) < 0 || + esxVI_PerfMetricId_Alloc(domain->conn, &querySpec->metricId) < 0 || + esxVI_Int_Alloc(domain->conn, + &querySpec->metricId->counterId) < 0) { + goto failure; + } + + querySpec->entity = virtualMachine->obj; + querySpec->maxSample->value = 1; + querySpec->metricId->counterId->value = priv->usedCpuTimeCounterId; + querySpec->metricId->instance = (char *)""; + querySpec->format = (char *)"normal"; + + + if (esxVI_QueryPerf(domain->conn, priv->host, querySpec, + &perfEntityMetricList) < 0) { + querySpec->entity = NULL; + querySpec->metricId->instance = NULL; + querySpec->format = NULL; + goto failure; + } + + for (perfEntityMetric = perfEntityMetricList; perfEntityMetric != NULL; + perfEntityMetric = perfEntityMetric->_next) { + VIR_DEBUG0("perfEntityMetric ..."); + + for (perfMetricIntSeries = perfEntityMetric->value; + perfMetricIntSeries != NULL; + perfMetricIntSeries = perfMetricIntSeries->_next) { + VIR_DEBUG0("perfMetricIntSeries ..."); + + for (value = perfMetricIntSeries->value; + value != NULL; + value = value->_next) { + VIR_DEBUG("value %"PRIi64, value->value); + } + } + } + + querySpec->entity = NULL; + querySpec->metricId->instance = NULL; + querySpec->format = NULL; + + VIR_DEBUG("usedCpuTimeCounterId %d END", priv->usedCpuTimeCounterId); + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_PerfMetricId_Free(&perfMetricIdList); + esxVI_Int_Free(&counterIdList); + esxVI_PerfCounterInfo_Free(&perfCounterInfoList); + esxVI_PerfQuerySpec_Free(&querySpec); + esxVI_PerfEntityMetric_Free(&perfEntityMetricList); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + int nvcpus_max; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachineConfigSpec *spec = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (nvcpus < 1) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Requested number of virtual CPUs must al least be 1"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + nvcpus_max = esxDomainGetMaxVcpus(domain); + + if (nvcpus_max < 0) { + goto failure; + } + + if (nvcpus > nvcpus_max) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Requested number of virtual CPUs is greater than max " + "allowable number of virtual CPUs for the domain: %d > %d", + nvcpus, nvcpus_max); + goto failure; + } + + if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, NULL, + &virtualMachine) < 0 || + esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 || + esxVI_Int_Alloc(domain->conn, &spec->numCPUs) < 0) { + goto failure; + } + + spec->numCPUs->value = nvcpus; + + if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj, + spec, &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not set number of virtual CPUs to %d", nvcpus); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_VirtualMachineConfigSpec_Free(&spec); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainGetMaxVcpus(virDomainPtr domain) +{ + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (priv->nvcpus_max > 0) { + return priv->nvcpus_max; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "capability.maxSupportedVcpus") < 0 || + esxVI_GetObjectContent(domain->conn, priv->host, + priv->host->hostFolder, "HostSystem", + propertyNameList, esxVI_Boolean_True, + &hostSystem) < 0) { + goto failure; + } + + if (hostSystem == NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the HostSystem object"); + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "capability.maxSupportedVcpus")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Int) < 0) { + goto failure; + } + + priv->nvcpus_max = dynamicProperty->val->int32; + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + + return priv->nvcpus_max; + + failure: + priv->nvcpus_max = -1; + + goto cleanup; +} + + + +static char * +esxDomainDumpXML(virDomainPtr domain, int flags) +{ + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + const char *vmPathName = NULL; + char *datastoreName = NULL; + char *vmxPath = NULL; + char *url = NULL; + char *vmx = NULL; + virDomainDefPtr def = NULL; + char *xml = NULL; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return NULL; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "config.files.vmPathName") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0) { + goto failure; + } + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.files.vmPathName")) { + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + vmPathName = dynamicProperty->val->string; + break; + } + } + + /* expected format: "[<datastoreName>] <vmxPath>" */ + if (sscanf(vmPathName, "[%a[^]%]] %as", &datastoreName, &vmxPath) != 2) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "'config.files.vmPathName' property '%s' doesn't have " + "expected format '[<datastore>] <vmx>'", vmPathName); + goto failure; + } + + if (virAsprintf(&url, "%s://%s/folder/%s?dcPath=%s&dsName=%s", + priv->transport, domain->conn->uri->server, + vmxPath, priv->host->datacenter->value, + datastoreName) < 0) { + virReportOOMError(domain->conn); + goto failure; + } + + if (esxVI_Context_Download(domain->conn, priv->host, url, &vmx) < 0) { + goto failure; + } + + def = esxVMX_ParseConfig(domain->conn, vmx); + + if (def != NULL) { + xml = virDomainDefFormat(domain->conn, def, flags); + } + + cleanup: + VIR_FREE(datastoreName); + VIR_FREE(vmxPath); + VIR_FREE(url); + VIR_FREE(vmx); + + return xml; + + failure: + VIR_FREE(xml); + + goto cleanup; +} + + + +static char * +esxDomainXMLFromNative(virConnectPtr conn, const char *nativeFormat, + const char *nativeConfig, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDomainDefPtr def = NULL; + char *xml = NULL; + + if (STRNEQ(nativeFormat, "vmware-vmx")) { + ESX_ERROR(conn, VIR_ERR_INVALID_ARG, + "Unsupported config format '%s'", nativeFormat); + goto cleanup; + } + + def = esxVMX_ParseConfig(conn, nativeConfig); + + if (def != NULL) { + xml = virDomainDefFormat(conn, def, VIR_DOMAIN_XML_INACTIVE); + } + +cleanup: + virDomainDefFree(def); + + return xml; +} + + + +static int +esxListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_VirtualMachinePowerState powerState; + int count = 0; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (names == NULL || maxnames < 0) { + goto failure; + } + + if (maxnames == 0) { + return 0; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "name\0" + "runtime.powerState\0") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->vmFolder, + "VirtualMachine", propertyNameList, + esxVI_Boolean_True, &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + if (esxVI_GetVirtualMachinePowerState(conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState == esxVI_VirtualMachinePowerState_PoweredOn) { + continue; + } + + for (dynamicProperty = virtualMachine->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "name")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + names[count] = strdup(dynamicProperty->val->string); + + if (names[count] == NULL) { + virReportOOMError(conn); + goto failure; + } + + count++; + break; + } + } + + if (count >= maxnames) { + break; + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + + return count; + + failure: + count = -1; + + goto cleanup; + +} + + + +static int +esxNumberOfDefinedDomains(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return -1; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + return -1; + } + + return esxVI_GetNumberOfDomainsByPowerState + (conn, priv->host, esxVI_VirtualMachinePowerState_PoweredOn, + esxVI_Boolean_True); +} + + + +static int +esxDomainCreate(virDomainPtr domain) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0 || + esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine, + &powerState) < 0) { + goto failure; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Domain is not powered off"); + goto failure; + } + + if (esxVI_PowerOnVM_Task(domain->conn, priv->host, virtualMachine->obj, + &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not start domain"); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static char * +esxDomainGetSchedulerType(virDomainPtr domain, int *nparams) +{ + char *type = strdup("allocation"); + + if (type == NULL) { + virReportOOMError(domain->conn); + } + + *nparams = 3; /* reservation, limit, shares */ + + return type; +} + + + +static int +esxDomainGetSchedulerParameters(virDomainPtr domain, + virSchedParameterPtr params, int *nparams) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_SharesInfo *sharesInfo = NULL; + unsigned int mask = 0; + int i = 0; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (*nparams < 3) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Parameter array must have space for 3 items"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueListToList(domain->conn, &propertyNameList, + "config.cpuAllocation.reservation\0" + "config.cpuAllocation.limit\0" + "config.cpuAllocation.shares\0") < 0 || + esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, propertyNameList, + &virtualMachine) < 0) { + goto failure; + } + + for (dynamicProperty = virtualMachine->propSet; + dynamicProperty != NULL && mask != 7 && i < 3; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "config.cpuAllocation.reservation") && + !(mask & (1 << 0))) { + snprintf (params[i].field, VIR_DOMAIN_SCHED_FIELD_LENGTH, "%s", + "reservation"); + + params[i].type = VIR_DOMAIN_SCHED_FIELD_LLONG; + + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto failure; + } + + params[i].value.l = dynamicProperty->val->int64; + mask |= 1 << 0; + ++i; + } else if (STREQ(dynamicProperty->name, + "config.cpuAllocation.limit") && + !(mask & (1 << 1))) { + snprintf (params[i].field, VIR_DOMAIN_SCHED_FIELD_LENGTH, "%s", + "limit"); + + params[i].type = VIR_DOMAIN_SCHED_FIELD_LLONG; + + if (esxVI_AnyType_ExpectType(domain->conn, dynamicProperty->val, + esxVI_Type_Long) < 0) { + goto failure; + } + + params[i].value.l = dynamicProperty->val->int64; + mask |= 1 << 1; + ++i; + } else if (STREQ(dynamicProperty->name, + "config.cpuAllocation.shares") && + !(mask & (1 << 2))) { + snprintf (params[i].field, VIR_DOMAIN_SCHED_FIELD_LENGTH, "%s", + "shares"); + + params[i].type = VIR_DOMAIN_SCHED_FIELD_INT; + + if (esxVI_SharesInfo_CastFromAnyType(domain->conn, + dynamicProperty->val, + &sharesInfo) < 0) { + goto failure; + } + + switch (sharesInfo->level) { + case esxVI_SharesLevel_Custom: + params[i].value.i = sharesInfo->shares->value; + break; + + case esxVI_SharesLevel_Low: + params[i].value.i = -1; + break; + + case esxVI_SharesLevel_Normal: + params[i].value.i = -2; + break; + + case esxVI_SharesLevel_High: + params[i].value.i = -3; + break; + + default: + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Shares level has unknown value %"PRIi32, + sharesInfo->level); + goto failure; + } + + esxVI_SharesInfo_Free(&sharesInfo); + + mask |= 1 << 2; + ++i; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + *nparams = i; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainSetSchedulerParameters(virDomainPtr domain, + virSchedParameterPtr params, int nparams) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachineConfigSpec *spec = NULL; + esxVI_SharesInfo *sharesInfo = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + int i; + int32_t value; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host, + domain->uuid, NULL, + &virtualMachine) < 0 || + esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 || + esxVI_ResourceAllocationInfo_Alloc(domain->conn, + &spec->cpuAllocation) < 0) { + goto failure; + } + + for (i = 0; i < nparams; ++i) { + if (STREQ (params[i].field, "reservation") && + params[i].type == VIR_DOMAIN_SCHED_FIELD_LLONG) { + if (esxVI_Long_Alloc(domain->conn, + &spec->cpuAllocation->reservation) < 0) { + goto failure; + } + + if (params[i].value.l < 0) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Could not set reservation to %lld MHz, expecting " + "positive value", params[i].value.l); + goto failure; + } + + spec->cpuAllocation->reservation->value = params[i].value.l; + } else if (STREQ (params[i].field, "limit") && + params[i].type == VIR_DOMAIN_SCHED_FIELD_LLONG) { + if (esxVI_Long_Alloc(domain->conn, + &spec->cpuAllocation->limit) < 0) { + goto failure; + } + + if (params[i].value.l < -1) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Could not set limit to %lld MHz, expecting " + "positive value or -1 (unlimited)", + params[i].value.l); + goto failure; + } + + spec->cpuAllocation->limit->value = params[i].value.l; + } else if (STREQ (params[i].field, "shares") && + (params[i].type == VIR_DOMAIN_SCHED_FIELD_INT || + params[i].type == VIR_DOMAIN_SCHED_FIELD_LLONG)) { + if (params[i].type == VIR_DOMAIN_SCHED_FIELD_LLONG) { + /* + * Allow VIR_DOMAIN_SCHED_FIELD_LLONG here even if the expected + * data type is VIR_DOMAIN_SCHED_FIELD_INT, because virsh is + * using VIR_DOMAIN_SCHED_FIELD_LLONG only. + */ + if (params[i].value.l < INT32_MIN || + params[i].value.l > INT32_MAX) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Could not set shares to %lld, expecting 32bit " + "integer value", params[i].value.l); + goto failure; + } + + value = params[i].value.l; + } else { + value = params[i].value.i; + } + + if (esxVI_SharesInfo_Alloc(domain->conn, &sharesInfo) < 0 || + esxVI_Int_Alloc(domain->conn, &sharesInfo->shares) < 0) { + goto failure; + } + + spec->cpuAllocation->shares = sharesInfo; + + if (value >= 0) { + spec->cpuAllocation->shares->level = esxVI_SharesLevel_Custom; + spec->cpuAllocation->shares->shares->value = value; + } else { + switch (value) { + case -1: + spec->cpuAllocation->shares->level = esxVI_SharesLevel_Low; + spec->cpuAllocation->shares->shares->value = -1; + break; + + case -2: + spec->cpuAllocation->shares->level = + esxVI_SharesLevel_Normal; + spec->cpuAllocation->shares->shares->value = -1; + break; + + case -3: + spec->cpuAllocation->shares->level = + esxVI_SharesLevel_High; + spec->cpuAllocation->shares->shares->value = -1; + break; + + default: + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Could not set shares to %d, expecting positive " + "value or -1 (low), -2 (normal) or -3 (high)", + params[i].value.i); + goto failure; + } + } + } else { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Unknown field '%s'", params[i].field); + goto failure; + } + } + + if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj, + spec, &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->host, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not change scheduler parameters"); + goto failure; + } + + cleanup: + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_VirtualMachineConfigSpec_Free(&spec); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainMigratePrepare(virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in, char **uri_out, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + int result = 0; + char *transport = NULL; + + if (uri_in == NULL) { + if (esxUtil_ParseQuery(dconn, &transport, NULL) < 0) { + return -1; + } + + if (virAsprintf(uri_out, "%s://%s/sdk", transport, + dconn->uri->server) < 0) { + virReportOOMError(dconn); + goto failure; + } + } + + cleanup: + VIR_FREE(transport); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static int +esxDomainMigratePerform(virDomainPtr domain, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname, + unsigned long bandwidth ATTRIBUTE_UNUSED) +{ + int result = 0; + esxPrivate *priv = (esxPrivate *)domain->conn->privateData; + xmlURIPtr xmlUri = NULL; + char host_ip_string[NI_MAXHOST] = ""; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ManagedObjectReference *managedObjectReference = NULL; + esxVI_ObjectContent *computeResource = NULL; + esxVI_ManagedObjectReference *resourcePool = NULL; + esxVI_Event *eventList = NULL; + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + + if (priv->phantom) { + ESX_ERROR(domain->conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (priv->vcenter == NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Migration not possible without a Virtual Center"); + goto failure; + } + + if (dname != NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, + "Renaming domains on migration not supported"); + goto failure; + } + + if (esxVI_EnsureSession(domain->conn, priv->vcenter) < 0) { + goto failure; + } + + /* Parse the destination URI and resolve the hostname */ + xmlUri = xmlParseURI(uri); + + if (xmlUri == NULL) { + virReportOOMError(domain->conn); + goto failure; + } + + if (esxUtil_ResolveHostname(domain->conn, xmlUri->server, host_ip_string, + NI_MAXHOST) < 0) { + goto failure; + } + + /* Lookup VirtualMachine, HostSystem and ResourcePool */ + if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->vcenter, + domain->uuid, NULL, + &virtualMachine) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "parent") < 0 || + esxVI_LookupHostSystemByIp(domain->conn, priv->vcenter, + host_ip_string, propertyNameList, + &hostSystem) < 0) { + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "parent")) { + if (esxVI_ManagedObjectReference_CastFromAnyType + (domain->conn, dynamicProperty->val, &managedObjectReference, + "ComputeResource") < 0) { + goto failure; + } + + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (managedObjectReference == NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve compute resource of host system"); + goto failure; + } + + esxVI_String_Free(&propertyNameList); + + if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList, + "resourcePool") < 0 || + esxVI_GetObjectContent(domain->conn, priv->vcenter, + managedObjectReference, "ComputeResource", + propertyNameList, esxVI_Boolean_False, + &computeResource) < 0) { + goto failure; + } + + if (computeResource == NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve compute resource of host system"); + goto failure; + } + + for (dynamicProperty = computeResource->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "resourcePool")) { + if (esxVI_ManagedObjectReference_CastFromAnyType + (domain->conn, dynamicProperty->val, &resourcePool, + "ResourcePool") < 0) { + goto failure; + } + + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (resourcePool == NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve resource pool of compute resource of " + "host system"); + goto failure; + } + + /* Validate the purposed migration */ + if (esxVI_ValidateMigration(domain->conn, priv->vcenter, + virtualMachine->obj, + esxVI_VirtualMachinePowerState_Undefined, + NULL, resourcePool, hostSystem->obj, + &eventList) < 0) { + goto failure; + } + + if (eventList != NULL) { + /* + * FIXME: Need to report the complete list of events. Limit reporting + * to the first event for now. + */ + if (eventList->fullFormattedMessage != NULL) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not migrate domain, validation reported a " + "problem: %s", eventList->fullFormattedMessage); + } else { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not migrate domain, validation reported a " + "problem"); + } + + goto failure; + } + + /* Perform the purposed migration */ + if (esxVI_MigrateVM_Task(domain->conn, priv->vcenter, virtualMachine->obj, + resourcePool, hostSystem->obj, &task) < 0 || + esxVI_WaitForTaskCompletion(domain->conn, priv->vcenter, task, + &taskInfoState) < 0) { + goto failure; + } + + if (taskInfoState != esxVI_TaskInfoState_Success) { + ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR, + "Could not migrate domain, migration task finished with " + "an error"); + goto failure; + } + + cleanup: + xmlFreeURI(xmlUri); + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_ManagedObjectReference_Free(&managedObjectReference); + esxVI_ObjectContent_Free(&computeResource); + esxVI_ManagedObjectReference_Free(&resourcePool); + esxVI_Event_Free(&eventList); + esxVI_ManagedObjectReference_Free(&task); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +static virDomainPtr +esxDomainMigrateFinish(virConnectPtr dconn, const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return esxDomainLookupByName(dconn, dname); +} + + + +static virDriver esxDriver = { + VIR_DRV_ESX, + "ESX", + esxOpen, /* open */ + esxClose, /* close */ + esxSupportsFeature, /* supports_feature */ + esxGetType, /* type */ + esxGetVersion, /* version */ + esxGetHostname, /* hostname */ + NULL, /* getMaxVcpus */ + esxNodeGetInfo, /* nodeGetInfo */ + NULL, /* getCapabilities */ + esxListDomains, /* listDomains */ + esxNumberOfDomains, /* numOfDomains */ + NULL, /* domainCreateXML */ + esxDomainLookupByID, /* domainLookupByID */ + esxDomainLookupByUUID, /* domainLookupByUUID */ + esxDomainLookupByName, /* domainLookupByName */ + esxDomainSuspend, /* domainSuspend */ + esxDomainResume, /* domainResume */ + esxDomainShutdown, /* domainShutdown */ + esxDomainReboot, /* domainReboot */ + esxDomainDestroy, /* domainDestroy */ + esxDomainGetOSType, /* domainGetOSType */ + esxDomainGetMaxMemory, /* domainGetMaxMemory */ + esxDomainSetMaxMemory, /* domainSetMaxMemory */ + esxDomainSetMemory, /* domainSetMemory */ + esxDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + esxDomainSetVcpus, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + esxDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + esxDomainDumpXML, /* domainDumpXML */ + esxDomainXMLFromNative, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + esxListDefinedDomains, /* listDefinedDomains */ + esxNumberOfDefinedDomains, /* numOfDefinedDomains */ + esxDomainCreate, /* domainCreate */ + NULL, /* domainDefineXML */ + NULL, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, /* domainDetachDevice */ + NULL, /* domainGetAutostart */ + NULL, /* domainSetAutostart */ + esxDomainGetSchedulerType, /* domainGetSchedulerType */ + esxDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + esxDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + esxDomainMigratePrepare, /* domainMigratePrepare */ + esxDomainMigratePerform, /* domainMigratePerform */ + esxDomainMigrateFinish, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + NULL, /* nodeGetCellsFreeMemory */ + NULL, /* nodeGetFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ +}; + + + +int +esxRegister(void) +{ + virRegisterDriver(&esxDriver); + + return 0; +} diff --git a/src/esx/esx_driver.h b/src/esx/esx_driver.h new file mode 100644 index 0000000..85f4b32 --- /dev/null +++ b/src/esx/esx_driver.h @@ -0,0 +1,29 @@ + +/* + * esx_driver.h: core driver methods for managing VMware ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Maximilian Wilhelm <max@xxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_DRIVER_H__ +#define __ESX_DRIVER_H__ + +int esxRegister(void); + +#endif /* __ESX_DRIVER_H__ */ diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c new file mode 100644 index 0000000..bd931bf --- /dev/null +++ b/src/esx/esx_util.c @@ -0,0 +1,488 @@ + +/* + * esx_util.c: utility methods for the VMware ESX driver + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Maximilian Wilhelm <max@xxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include <netdb.h> + +#include "internal.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "qparams.h" +#include "util.h" +#include "memory.h" +#include "logging.h" +#include "uuid.h" +#include "esx_util.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_ERROR(conn, code, fmt...) \ + virReportErrorHelper (conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + + + +char * +esxUtil_RequestUsername(virConnectAuthPtr auth, const char *default_username, + const char *server) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt = NULL; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter username for %s [%s]", server, + default_username) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_AUTHNAME) { + continue; + } + + cred.type = VIR_CRED_AUTHNAME; + cred.prompt = prompt; + cred.challenge = NULL; + cred.defresult = default_username; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + + + +char * +esxUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *server) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter %s password for %s", username, + server) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE && + auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) { + continue; + } + + cred.type = auth->credtype[ncred]; + cred.prompt = prompt; + cred.challenge = NULL; + cred.defresult = NULL; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + + + +int +esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vcenter) +{ + int result = 0; + int i; + struct qparam_set *queryParamSet = NULL; + struct qparam *queryParam = NULL; + + if (transport != NULL) { + *transport = NULL; + } + + if (vcenter != NULL) { + *vcenter = NULL; + } + +#ifdef HAVE_XMLURI_QUERY_RAW + queryParamSet = qparam_query_parse(conn->uri->query_raw); +#else + queryParamSet = qparam_query_parse(conn->uri->query); +#endif + + if (queryParamSet == NULL) { + goto failure; + } + + for (i = 0; i < queryParamSet->n; i++) { + queryParam = &queryParamSet->p[i]; + + if (STRCASEEQ(queryParam->name, "transport") && transport != NULL) { + *transport = strdup(queryParam->value); + + if (*transport == NULL) { + virReportOOMError(conn); + goto failure; + } + + if (STRNEQ(*transport, "http") && STRNEQ(*transport, "https")) { + ESX_ERROR(conn, VIR_ERR_INVALID_ARG, + "Query parameter 'transport' has unexpected value " + "'%s' (should be http|https)", *transport); + goto failure; + } + } else if (STRCASEEQ(queryParam->name, "vcenter") && vcenter != NULL) { + *vcenter = strdup(queryParam->value); + + if (*vcenter == NULL) { + virReportOOMError(conn); + goto failure; + } + } else { + VIR_WARN("Ignoring unexpected query parameter '%s'", + queryParam->name); + } + } + + if (transport != NULL && *transport == NULL) { + *transport = strdup("https"); + + if (*transport == NULL) { + virReportOOMError(conn); + goto failure; + } + } + + cleanup: + if (queryParamSet != NULL) { + free_qparam_set(queryParamSet); + } + + return result; + + failure: + if (transport != NULL) { + VIR_FREE(*transport); + } + + if (vcenter != NULL) { + VIR_FREE(*vcenter); + } + + result = -1; + + goto cleanup; +} + + + +int +esxUtil_ParseVirtualMachineIDString(const char *id_string, int *id) +{ + /* Try to parse an integer from the complete string. */ + if (virStrToLong_i(id_string, NULL, 10, id) == 0) { + return 0; + } + + /* + * If that fails try to parse an integer from the string tail + * assuming the naming scheme Virtual Center seems to use. + */ + if (STRPREFIX(id_string, "vm-")) { + if (virStrToLong_i(id_string + 3, NULL, 10, id) == 0) { + return 0; + } + } + + return -1; +} + + + +int +esxUtil_ResolveHostname(virConnectPtr conn, const char *hostname, + char *ip_address, size_t ip_address_length) +{ + struct addrinfo hints; + struct addrinfo *result = NULL; + int errcode; + + memset(&hints, 0, sizeof (struct addrinfo)); + + hints.ai_flags = AI_ADDRCONFIG; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + errcode = getaddrinfo(hostname, NULL, &hints, &result); + + if (errcode != 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "IP address lookup for host '%s' failed: %s", hostname, + gai_strerror(errcode)); + return -1; + } + + if (result == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "No IP address for host '%s' found: %s", hostname, + gai_strerror(errcode)); + return -1; + } + + errcode = getnameinfo(result->ai_addr, result->ai_addrlen, ip_address, + ip_address_length, NULL, 0, NI_NUMERICHOST); + + if (errcode != 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Formating IP address for host '%s' failed: %s", hostname, + gai_strerror(errcode)); + freeaddrinfo(result); + return -1; + } + + freeaddrinfo(result); + + return 0; +} + + + +int +esxUtil_GetConfigString(virConnectPtr conn, virConfPtr conf, const char *name, + char **string, int optional) +{ + virConfValuePtr value; + + *string = NULL; + value = virConfGetValue(conf, name); + + if (value == NULL) { + if (optional) { + return 0; + } + + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + + if (value->type != VIR_CONF_STRING) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must be a string", name); + return -1; + } + + if (value->str == NULL) { + if (optional) { + return 0; + } + + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + + *string = strdup(value->str); + + if (*string == NULL) { + virReportOOMError(conn); + return -1; + } + + return 0; +} + + + +int +esxUtil_GetConfigUUID(virConnectPtr conn, virConfPtr conf, const char *name, + unsigned char *uuid, int optional) +{ + virConfValuePtr value; + + value = virConfGetValue(conf, name); + + if (value == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + if (value->type != VIR_CONF_STRING) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must be a string", name); + return -1; + } + + if (value->str == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + virUUIDParse(value->str, uuid); + + return 0; +} + + + +int +esxUtil_GetConfigLong(virConnectPtr conn, virConfPtr conf, const char *name, + long long *number, long long default_, int optional) +{ + virConfValuePtr value; + + *number = default_; + value = virConfGetValue(conf, name); + + if (value == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + if (value->type == VIR_CONF_STRING) { + if (value->str == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + if (STREQ(value->str, "unlimited")) { + *number = -1; + } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must represent an integer value", + name); + return -1; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must be a string", name); + return -1; + } + + return 0; +} + + + +int +esxUtil_GetConfigBoolean(virConnectPtr conn, virConfPtr conf, + const char *name, int *boolean, int default_, + int optional) +{ + virConfValuePtr value; + + *boolean = default_; + value = virConfGetValue(conf, name); + + if (value == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + if (value->type == VIR_CONF_STRING) { + if (value->str == NULL) { + if (optional) { + return 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing essential config entry '%s'", name); + return -1; + } + } + + if (STRCASEEQ(value->str, "true")) { + *boolean = 1; + } else if (STRCASEEQ(value->str, "false")) { + *boolean = 0; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must represent a boolean value " + "(true|false)", name); + return -1; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Config entry '%s' must be a string", name); + return -1; + } + + return 0; +} + + + +int +esxUtil_EqualSuffix(const char *string, const char* suffix) +{ + int difference = (int)strlen(string) - (int)strlen(suffix); + + if (difference < 0) { + return -1; + } else { + return STRCASEEQ(string + difference, suffix); + } +} diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h new file mode 100644 index 0000000..f746231 --- /dev/null +++ b/src/esx/esx_util.h @@ -0,0 +1,60 @@ + +/* + * esx_util.h: utility methods for the VMware ESX driver + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_UTIL_H__ +#define __ESX_UTIL_H__ + +#include <libxml/tree.h> + +#include "internal.h" +#include "conf.h" + +char *esxUtil_RequestUsername(virConnectAuthPtr auth, + const char *default_username, + const char *server); + +char *esxUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *server); + +int esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vcenter); + +int esxUtil_ParseVirtualMachineIDString(const char *id_string, int *id); + +int esxUtil_ResolveHostname(virConnectPtr conn, const char *hostname, + char *ip_address, size_t ip_address_length); + +int esxUtil_GetConfigString(virConnectPtr conn, virConfPtr conf, + const char *name, char **string, int optional); + +int esxUtil_GetConfigUUID(virConnectPtr conn, virConfPtr conf, const char *name, + unsigned char *uuid, int optional); + +int esxUtil_GetConfigLong(virConnectPtr conn, virConfPtr conf, const char *name, + long long *number, long long default_, int optional); + +int esxUtil_GetConfigBoolean(virConnectPtr conn, virConfPtr conf, + const char *name, int *boolean, int default_, + int optional); + +int esxUtil_EqualSuffix(const char *string, const char* suffix); + +#endif /* __ESX_UTIL_H__ */ diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c new file mode 100644 index 0000000..4b083c6 --- /dev/null +++ b/src/esx/esx_vi.c @@ -0,0 +1,1868 @@ + +/* + * esx_vi.c: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <libxml/parser.h> +#include <libxml/xpathInternals.h> + +#include "buf.h" +#include "memory.h" +#include "logging.h" +#include "util.h" +#include "uuid.h" +#include "virterror_internal.h" +#include "esx_vi.h" +#include "esx_vi_methods.h" +#include "esx_util.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_VI_ERROR(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + +#define ESX_VI__SOAP__REQUEST_HEADER \ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \ + "<soapenv:Envelope " \ + "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " \ + "xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" " \ + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" \ + "<soapenv:Body>" + +#define ESX_VI__SOAP__REQUEST_FOOTER \ + "</soapenv:Body>" \ + "</soapenv:Envelope>" + +#define ESX_VI__SOAP__RESPONSE_XPATH(_type) \ + ((char *)"/soapenv:Envelope/soapenv:Body/" \ + "vim:"_type"Response/vim:returnval") + +#define ESV_VI__XML_TAG__OPEN(_buffer, _element, _type) \ + do { \ + virBufferAddLit(_buffer, "<"); \ + virBufferAdd(_buffer, _element, -1); \ + virBufferAddLit(_buffer, " xmlns=\"urn:vim25\" xsi:type=\""); \ + virBufferAdd(_buffer, _type, -1); \ + virBufferAddLit(_buffer, "\">"); \ + } while (0) + +#define ESV_VI__XML_TAG__CLOSE(_buffer, _element) \ + do { \ + virBufferAddLit(_buffer, "</"); \ + virBufferAdd(_buffer, _element, -1); \ + virBufferAddLit(_buffer, ">"); \ + } while (0) + +#define ESX_VI__TEMPLATE__ALLOC(_type) \ + int \ + esxVI_##_type##_Alloc(virConnectPtr conn, esxVI_##_type **ptrptr) \ + { \ + return esxVI_Alloc(conn, (void **)ptrptr, sizeof (esxVI_##_type)); \ + } + +#define ESX_VI__TEMPLATE__FREE(_type, _body) \ + void \ + esxVI_##_type##_Free(esxVI_##_type **ptrptr) \ + { \ + esxVI_##_type *item = NULL; \ + \ + if (ptrptr == NULL || *ptrptr == NULL) { \ + return; \ + } \ + \ + item = *ptrptr; \ + \ + _body \ + \ + VIR_FREE(*ptrptr); \ + } + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Context + */ + +/* esxVI_Context_Alloc */ +ESX_VI__TEMPLATE__ALLOC(Context); + +/* esxVI_Context_Free */ +ESX_VI__TEMPLATE__FREE(Context, +{ + VIR_FREE(item->url); + + if (item->curl_handle != NULL) { + curl_easy_cleanup(item->curl_handle); + } + + if (item->curl_headers != NULL) { + curl_slist_free_all(item->curl_headers); + } + + virMutexDestroy(&item->curl_lock); + + VIR_FREE(item->username); + VIR_FREE(item->password); + esxVI_ServiceContent_Free(&item->service); + esxVI_UserSession_Free(&item->session); + esxVI_ManagedObjectReference_Free(&item->datacenter); + esxVI_ManagedObjectReference_Free(&item->vmFolder); + esxVI_ManagedObjectReference_Free(&item->hostFolder); + esxVI_SelectionSpec_Free(&item->fullTraversalSpecList); +}); + +static size_t +_esxVI_CURL_WriteBuffer(char *data, size_t size, size_t nmemb, void *buffer) +{ + if (buffer != NULL) { + virBufferAdd((virBufferPtr) buffer, data, size * nmemb); + + return size * nmemb; + } + + return 0; +} + +#define ESX_VI__CURL__ENABLE_DEBUG_OUTPUT 0 + +#if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT +static int +_esxVI_CURL_Debug(CURL *curl ATTRIBUTE_UNUSED, curl_infotype type, + char *info, size_t size, void *data ATTRIBUTE_UNUSED) +{ + switch (type) { + case CURLINFO_TEXT: + VIR_DEBUG0("CURLINFO_TEXT"); + fwrite(info, 1, size, stderr); + printf("\n\n"); + break; + + case CURLINFO_HEADER_IN: + VIR_DEBUG0("CURLINFO_HEADER_IN"); + break; + + case CURLINFO_HEADER_OUT: + VIR_DEBUG0("CURLINFO_HEADER_OUT"); + break; + + case CURLINFO_DATA_IN: + VIR_DEBUG0("CURLINFO_DATA_IN"); + break; + + case CURLINFO_DATA_OUT: + VIR_DEBUG0("CURLINFO_DATA_OUT"); + break; + + default: + VIR_DEBUG0("unknown"); + break; + } + + return 0; +} +#endif + +int +esxVI_Context_Connect(virConnectPtr conn, esxVI_Context *ctx, const char *url, + const char *username, const char *password) +{ + int result = 0; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *datacenterList = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + + if (ctx == NULL || url == NULL || username == NULL || password == NULL || + ctx->url != NULL || ctx->service != NULL || ctx->curl_handle != NULL || + ctx->curl_headers != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + if (esxVI_String_DeepCopyValue(conn, &ctx->url, url) < 0) { + goto failure; + } + + ctx->curl_handle = curl_easy_init(); + + if (ctx->curl_handle == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not initialize CURL"); + goto failure; + } + + ctx->curl_headers = curl_slist_append(ctx->curl_headers, "Content-Type: " + "text/xml; charset=UTF-8"); + + /* + * Add a dummy expect header to stop CURL from waiting for a response code + * 100 (Continue) from the server before continuing the POST operation. + * Waiting for this response would slowdown each communication with the + * server by approx. 2 sec, because the server doesn't send the expected + * 100 (Continue) response and the wait times out resulting in wasting + * approx. 2 sec per POST operation. + */ + ctx->curl_headers = curl_slist_append(ctx->curl_headers, + "Expect: nothing"); + + if (ctx->curl_headers == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not build CURL header list"); + goto failure; + } + + curl_easy_setopt(ctx->curl_handle, CURLOPT_URL, ctx->url); + curl_easy_setopt(ctx->curl_handle, CURLOPT_USERAGENT, "libvirt-esx"); + curl_easy_setopt(ctx->curl_handle, CURLOPT_HEADER, 0); + curl_easy_setopt(ctx->curl_handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(ctx->curl_handle, CURLOPT_COOKIEFILE, ""); + curl_easy_setopt(ctx->curl_handle, CURLOPT_HTTPHEADER, ctx->curl_headers); + curl_easy_setopt(ctx->curl_handle, CURLOPT_WRITEFUNCTION, + _esxVI_CURL_WriteBuffer); +#if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT + curl_easy_setopt(ctx->curl_handle, CURLOPT_DEBUGFUNCTION, + _esxVI_CURL_Debug); +#endif + + if (virMutexInit(&ctx->curl_lock) < 0) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not initialize CURL mutex"); + goto failure; + } + + ctx->username = strdup(username); + ctx->password = strdup(password); + + if (ctx->username == NULL || ctx->password == NULL) { + virReportOOMError(conn); + goto failure; + } + + if (esxVI_RetrieveServiceContent(conn, ctx, &ctx->service) < 0) { + goto failure; + } + + if (STREQ(ctx->service->about->apiType, "HostAgent")) { + if (STRNEQ(ctx->service->about->apiVersion, "2.5.0") && + STRNEQ(ctx->service->about->apiVersion, "2.5u2")) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VI API version '2.5.0' or '2.5u2' but " + "found '%s'", ctx->service->about->apiVersion); + goto failure; + } + } else if (STREQ(ctx->service->about->apiType, "VirtualCenter")) { + if (STRNEQ(ctx->service->about->apiVersion, "2.5u2")) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VI API version '2.5u2' but found '%s'", + ctx->service->about->apiVersion); + goto failure; + } + } else { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VI API type 'HostAgent' or 'VirtualCenter' " + "but found '%s'", ctx->service->about->apiType); + goto failure; + } + + if (esxVI_Login(conn, ctx, username, password, &ctx->session) < 0) { + goto failure; + } + + esxVI_BuildFullTraversalSpecList(conn, &ctx->fullTraversalSpecList); + + if (esxVI_String_AppendValueListToList(conn, &propertyNameList, + "vmFolder\0" + "hostFolder\0") < 0) { + goto failure; + } + + /* Get pointer to Datacenter for later use */ + if (esxVI_GetObjectContent(conn, ctx, ctx->service->rootFolder, + "Datacenter", propertyNameList, + esxVI_Boolean_True, &datacenterList) < 0) { + goto failure; + } + + if (datacenterList == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the 'datacenter' object from the VI " + "host/center"); + goto failure; + } + + ctx->datacenter = datacenterList->obj; + datacenterList->obj = NULL; + + /* Get pointer to vmFolder and hostFolder for later use */ + for (dynamicProperty = datacenterList->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "vmFolder")) { + if (esxVI_ManagedObjectReference_CastFromAnyType + (conn, dynamicProperty->val, &ctx->vmFolder, "Folder")) { + goto failure; + } + } else if (STREQ(dynamicProperty->name, "hostFolder")) { + if (esxVI_ManagedObjectReference_CastFromAnyType + (conn, dynamicProperty->val, &ctx->hostFolder, "Folder")) { + goto failure; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (ctx->vmFolder == NULL || ctx->hostFolder == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "The 'datacenter' object is missing the " + "'vmFolder'/'hostFolder' propoerty"); + goto failure; + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datacenterList); + + return result; + + failure: + result = -1; + + goto cleanup; +} + +int +esxVI_Context_Download(virConnectPtr conn, esxVI_Context *ctx, const char *url, + char **content) +{ + virBuffer buffer = VIR_BUFFER_INITIALIZER; + CURLcode error_code; + long response_code; + + if (content == NULL || *content != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + virMutexLock(&ctx->curl_lock); + + curl_easy_setopt(ctx->curl_handle, CURLOPT_URL, url); + curl_easy_setopt(ctx->curl_handle, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(ctx->curl_handle, CURLOPT_HTTPGET, 1); + + error_code = curl_easy_perform(ctx->curl_handle); + + if (error_code != CURLE_OK) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "curl_easy_perform() returned an error: %s (%d)", + curl_easy_strerror(error_code), error_code); + goto unlock; + } + + error_code = curl_easy_getinfo(ctx->curl_handle, CURLINFO_RESPONSE_CODE, + &response_code); + + if (error_code != CURLE_OK) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "curl_easy_getinfo() returned an error: %s (%d)", + curl_easy_strerror(error_code), error_code); + goto unlock; + } + + virMutexUnlock(&ctx->curl_lock); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + *content = virBufferContentAndReset(&buffer); + + if (response_code != 200) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "HTTP response code %d", (int)response_code); + goto failure; + } + + return 0; + + failure: + free(virBufferContentAndReset(&buffer)); + + return -1; + + unlock: + virMutexUnlock(&ctx->curl_lock); + + goto failure; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * RemoteRequest + */ + +/* esxVI_RemoteRequest_Alloc */ +ESX_VI__TEMPLATE__ALLOC(RemoteRequest); + +/* esxVI_RemoteRequest_Free */ +ESX_VI__TEMPLATE__FREE(RemoteRequest, +{ + VIR_FREE(item->request); + VIR_FREE(item->xpathExpression); +}); + +int +esxVI_RemoteRequest_Execute(virConnectPtr conn, esxVI_Context *ctx, + esxVI_RemoteRequest *remoteRequest, + esxVI_RemoteResponse **remoteResponse) +{ + virBuffer buffer = VIR_BUFFER_INITIALIZER; + esxVI_Fault *fault = NULL; + CURLcode error_code; + + if (remoteRequest == NULL || remoteRequest->request == NULL || + remoteResponse == NULL || *remoteResponse != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + if (esxVI_RemoteResponse_Alloc(conn, remoteResponse) < 0) { + goto failure; + } + + virMutexLock(&ctx->curl_lock); + + curl_easy_setopt(ctx->curl_handle, CURLOPT_URL, ctx->url); + curl_easy_setopt(ctx->curl_handle, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(ctx->curl_handle, CURLOPT_POSTFIELDS, + remoteRequest->request); + curl_easy_setopt(ctx->curl_handle, CURLOPT_POSTFIELDSIZE, + strlen(remoteRequest->request)); + + error_code = curl_easy_perform(ctx->curl_handle); + + if (error_code != CURLE_OK) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "curl_easy_perform() returned an error: %s (%d)", + curl_easy_strerror(error_code), error_code); + goto unlock; + } + + error_code = curl_easy_getinfo(ctx->curl_handle, CURLINFO_RESPONSE_CODE, + &(*remoteResponse)->response_code); + + if (error_code != CURLE_OK) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "curl_easy_getinfo() returned an error: %s (%d)", + curl_easy_strerror(error_code), error_code); + goto unlock; + } + + virMutexUnlock(&ctx->curl_lock); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + (*remoteResponse)->response = virBufferContentAndReset(&buffer); + + if ((*remoteResponse)->response_code == 500 || + (remoteRequest->xpathExpression != NULL && + (*remoteResponse)->response_code == 200)) { + (*remoteResponse)->document = + xmlReadDoc(BAD_CAST(*remoteResponse)->response, "", NULL, + XML_PARSE_NONET); + + if ((*remoteResponse)->document == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse XML response"); + goto failure; + } + + if (xmlDocGetRootElement((*remoteResponse)->document) == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "XML response is an empty document"); + goto failure; + } + + (*remoteResponse)->xpathContext = + xmlXPathNewContext((*remoteResponse)->document); + + if ((*remoteResponse)->xpathContext == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not create XPath context"); + goto failure; + } + + xmlXPathRegisterNs((*remoteResponse)->xpathContext, BAD_CAST "soapenv", + BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/"); + xmlXPathRegisterNs((*remoteResponse)->xpathContext, BAD_CAST "vim", + BAD_CAST "urn:vim25"); + + if ((*remoteResponse)->response_code == 500) { + (*remoteResponse)->xpathObject = + xmlXPathEval(BAD_CAST + "/soapenv:Envelope/soapenv:Body/soapenv:Fault", + (*remoteResponse)->xpathContext); + + if (esxVI_RemoteResponse_DeserializeXPathObject + (conn, *remoteResponse, + (esxVI_RemoteResponse_DeserializeFunc) + esxVI_Fault_Deserialize, + (void **)&fault) < 0) { + goto failure; + } + + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "HTTP response code %d. VI Fault: %s - %s", + (int)(*remoteResponse)->response_code, + fault->faultcode, fault->faultstring); + + goto failure; + } else { + (*remoteResponse)->xpathObject = + xmlXPathEval(BAD_CAST remoteRequest->xpathExpression, + (*remoteResponse)->xpathContext); + } + } else if ((*remoteResponse)->response_code != 200) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "HTTP response code %d", + (int)(*remoteResponse)->response_code); + + goto failure; + } + + return 0; + + failure: + free(virBufferContentAndReset(&buffer)); + esxVI_RemoteResponse_Free(remoteResponse); + esxVI_Fault_Free(&fault); + + return -1; + + unlock: + virMutexUnlock(&ctx->curl_lock); + + goto failure; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * RemoteResponse + */ + +/* esxVI_RemoteResponse_Alloc */ +ESX_VI__TEMPLATE__ALLOC(RemoteResponse); + +/* esxVI_RemoteResponse_Free */ +ESX_VI__TEMPLATE__FREE(RemoteResponse, +{ + VIR_FREE(item->response); + + xmlXPathFreeObject(item->xpathObject); + xmlXPathFreeContext(item->xpathContext); + + if (item->document != NULL) { + xmlFreeDoc(item->document); + } +}); + +int +esxVI_RemoteResponse_DeserializeXPathObject + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_RemoteResponse_DeserializeFunc deserializeFunc, void **item) +{ + xmlNodePtr node = NULL; + + if (remoteResponse->xpathObject != NULL && + remoteResponse->xpathObject->type == XPATH_NODESET) { + if (remoteResponse->xpathObject->nodesetval->nodeNr != 1) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting 1 XML node but found '%d'", + remoteResponse->xpathObject->nodesetval->nodeNr); + return -1; + } + + node = remoteResponse->xpathObject->nodesetval->nodeTab[0]; + + if (node->type != XML_ELEMENT_NODE) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Wrong XML element type %d", node->type); + return -1; + } + + if (deserializeFunc(conn, node, item) < 0) { + return -1; + } + } else { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "XPath error"); + return -1; + } + + return 0; +} + +int +esxVI_RemoteResponse_DeserializeXPathObjectList + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_RemoteResponse_DeserializeListFunc deserializeListFunc, + esxVI_List **list) +{ + xmlNodePtr node = NULL; + + if (remoteResponse->xpathObject != NULL && + remoteResponse->xpathObject->type == XPATH_NODESET) { + if (remoteResponse->xpathObject->nodesetval->nodeNr > 0) { + node = remoteResponse->xpathObject->nodesetval->nodeTab[0]; + + if (node->type != XML_ELEMENT_NODE) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Wrong XML element type %d", node->type); + return -1; + } + } else { + node = NULL; + } + + if (deserializeListFunc(conn, node, list) < 0) { + return -1; + } + } else { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "XPath error"); + return -1; + } + + return 0; +} + +int +esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_ManagedObjectReference **managedObjectReference, + const char *expectedType) +{ + xmlNodePtr node = NULL; + + if (remoteResponse->xpathObject != NULL && + remoteResponse->xpathObject->type == XPATH_NODESET) { + if (remoteResponse->xpathObject->nodesetval->nodeNr != 1) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting 1 XML node but found '%d'", + remoteResponse->xpathObject->nodesetval->nodeNr); + return -1; + } + + node = remoteResponse->xpathObject->nodesetval->nodeTab[0]; + + if (node->type != XML_ELEMENT_NODE) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Wrong XML element type %d", node->type); + return -1; + } + + if (esxVI_ManagedObjectReference_Deserialize(conn, node, + managedObjectReference, + expectedType) < 0) { + return -1; + } + } else { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "XPath error"); + return -1; + } + + return 0; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Enumeration + */ + +int +esxVI_Enumeration_CastFromAnyType(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + esxVI_AnyType *anyType, int *value) +{ + int i; + + if (anyType == NULL || value == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + *value = 0; /* undefined */ + + if (STRNEQ(anyType->other, enumeration->type)) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting type '%s' but found '%s'", enumeration->type, + anyType->other); + return -1; + } + + for (i = 0; enumeration->values[i].name != NULL; ++i) { + if (STREQ(anyType->value, enumeration->values[i].name)) { + *value = enumeration->values[i].value; + return 0; + } + } + + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unknown value '%s' for %s", anyType->value, + enumeration->type); + + return -1; +} + +int +esxVI_Enumeration_Serialize(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + int value, const char *element, + virBufferPtr output, esxVI_Boolean required) +{ + int i; + const char *name = NULL; + + if (element == NULL || output == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (value == 0) { /* undefined */ + return esxVI_CheckSerializationNecessity(conn, element, required); + } + + for (i = 0; enumeration->values[i].name != NULL; ++i) { + if (value == enumeration->values[i].value) { + name = enumeration->values[i].name; + break; + } + } + + if (name == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + ESV_VI__XML_TAG__OPEN(output, element, enumeration->type); + + virBufferAdd(output, name, -1); + + ESV_VI__XML_TAG__CLOSE(output, element); + + return 0; +} + +int +esxVI_Enumeration_Deserialize(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + xmlNodePtr node, int *value) +{ + int i; + int result = 0; + char *name = NULL; + + if (value == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + *value = 0; /* undefined */ + + if (esxVI_String_DeserializeValue(conn, node, &name) < 0) { + goto failure; + } + + for (i = 0; enumeration->values[i].name != NULL; ++i) { + if (STREQ(name, enumeration->values[i].name)) { + *value = enumeration->values[i].value; + goto cleanup; + } + } + + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Unknown value '%s' for %s", + name, enumeration->type); + + cleanup: + VIR_FREE(name); + + return result; + + failure: + goto cleanup; + + result = -1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * List + */ + +int +esxVI_List_Append(virConnectPtr conn, esxVI_List **list, esxVI_List *item) +{ + esxVI_List *next = NULL; + + if (list == NULL || item == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (*list == NULL) { + *list = item; + return 0; + } + + next = *list; + + while (next->_next != NULL) { + next = next->_next; + } + + next->_next = item; + + return 0; +} + +int +esxVI_List_DeepCopy(virConnectPtr conn, esxVI_List **destList, + esxVI_List *srcList, + esxVI_List_DeepCopyFunc deepCopyFunc, + esxVI_List_FreeFunc freeFunc) +{ + esxVI_List *dest = NULL; + esxVI_List *src = NULL; + + if (destList == NULL || *destList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + for (src = srcList; src != NULL; src = src->_next) { + if (deepCopyFunc(conn, &dest, src) < 0 || + esxVI_List_Append(conn, destList, dest) < 0) { + goto failure; + } + + dest = NULL; + } + + return 0; + + failure: + freeFunc(&dest); + freeFunc(destList); + + return -1; +} + +int +esxVI_List_Serialize(virConnectPtr conn, esxVI_List *list, const char *element, + virBufferPtr output, esxVI_Boolean required, + esxVI_List_SerializeFunc serializeFunc) +{ + esxVI_List *item = NULL; + + if (element == NULL || output == NULL || serializeFunc == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (list == NULL) { + return esxVI_CheckSerializationNecessity(conn, element, required); + } + + for (item = list; item != NULL; item = item->_next) { + if (serializeFunc(conn, item, element, output, + esxVI_Boolean_True) < 0) { + return -1; + } + } + + return 0; +} + +int +esxVI_List_Deserialize(virConnectPtr conn, xmlNodePtr node, esxVI_List **list, + esxVI_List_DeserializeFunc deserializeFunc, + esxVI_List_FreeFunc freeFunc) +{ + esxVI_List *item = NULL; + + if (list == NULL || *list != NULL || + deserializeFunc == NULL || freeFunc == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (node == NULL) { + return 0; + } + + for (; node != NULL; node = node->next) { + if (node->type != XML_ELEMENT_NODE) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Wrong XML element type %d", node->type); + goto failure; + } + + item = NULL; + + if (deserializeFunc(conn, node, &item) < 0) { + goto failure; + } + + if (esxVI_List_Append(conn, list, item) < 0) { + goto failure; + } + } + + return 0; + + failure: + freeFunc(list); + + return -1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Utility and Convenience Functions + */ + +int +esxVI_Alloc(virConnectPtr conn, void **ptrptr, size_t size) +{ + if (ptrptr == NULL || *ptrptr != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (virAllocN(ptrptr, size, 1) < 0) { + virReportOOMError(conn); + return -1; + } + + return 0; +} + +int +esxVI_CheckSerializationNecessity(virConnectPtr conn, const char *element, + esxVI_Boolean required) +{ + if (element == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (required == esxVI_Boolean_True) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Required property missing while trying to serialize " + "'%s'", element); + return -1; + } else { + return 0; + } +} + + + +int +esxVI_BuildFullTraversalSpecItem(virConnectPtr conn, + esxVI_SelectionSpec **fullTraversalSpecList, + const char *name, const char *type, + const char *path, const char *selectSetNames) +{ + esxVI_TraversalSpec *traversalSpec = NULL; + esxVI_SelectionSpec *selectionSpec = NULL; + const char *currentSelectSetName = NULL; + + if (fullTraversalSpecList == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_TraversalSpec_Alloc(conn, &traversalSpec) < 0 || + esxVI_String_DeepCopyValue(conn, &traversalSpec->_base->name, + name) < 0 || + esxVI_String_DeepCopyValue(conn, &traversalSpec->type, type) < 0 || + esxVI_String_DeepCopyValue(conn, &traversalSpec->path, path) < 0) { + goto failure; + } + + traversalSpec->skip = esxVI_Boolean_False; + + if (selectSetNames != NULL) { + currentSelectSetName = selectSetNames; + + while (currentSelectSetName != NULL && *currentSelectSetName != '\0') { + selectionSpec = NULL; + + if (esxVI_SelectionSpec_Alloc(conn, &selectionSpec) < 0 || + esxVI_String_DeepCopyValue(conn, &selectionSpec->name, + currentSelectSetName) < 0 || + esxVI_SelectionSpec_AppendToList(conn, + &traversalSpec->selectSet, + selectionSpec) < 0) { + goto failure; + } + + currentSelectSetName += strlen(currentSelectSetName) + 1; + } + } + + if (esxVI_SelectionSpec_AppendToList(conn, fullTraversalSpecList, + traversalSpec->_base) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_TraversalSpec_Free(&traversalSpec); + + return -1; +} + + + +int +esxVI_BuildFullTraversalSpecList(virConnectPtr conn, + esxVI_SelectionSpec **fullTraversalSpecList) +{ + if (fullTraversalSpecList == NULL || *fullTraversalSpecList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "visitFolders", + "Folder", "childEntity", + "visitFolders\0" + "datacenterToVmFolder\0" + "datacenterToHostFolder\0" + "computeResourceToHost\0" + "computeResourceToResourcePool\0" + "HostSystemToVm\0" + "resourcePoolToVm\0") < 0) { + goto failure; + } + + /* Traversal through vmFolder branch */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "datacenterToVmFolder", + "Datacenter", "vmFolder", + "visitFolders\0") < 0) { + goto failure; + } + + /* Traversal through hostFolder branch */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "datacenterToHostFolder", + "Datacenter", "hostFolder", + "visitFolders\0") < 0) { + goto failure; + } + + /* Traversal through host branch */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "computeResourceToHost", + "ComputeResource", "host", + NULL) < 0) { + goto failure; + } + + /* Traversal through resourcePool branch */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "computeResourceToResourcePool", + "ComputeResource", "resourcePool", + "resourcePoolToResourcePool\0" + "resourcePoolToVm\0") < 0) { + goto failure; + } + + /* Recurse through all resource pools */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "resourcePoolToResourcePool", + "ResourcePool", "resourcePool", + "resourcePoolToResourcePool\0" + "resourcePoolToVm\0") < 0) { + goto failure; + } + + /* Recurse through all hosts */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "HostSystemToVm", + "HostSystem", "vm", + "visitFolders\0") < 0) { + goto failure; + } + + /* Recurse through all resource pools */ + if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, + "resourcePoolToVm", + "ResourcePool", "vm", NULL) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_SelectionSpec_Free(fullTraversalSpecList); + + return -1; +} + + + +/* + * Can't use the SessionIsActive() function here, because at least + * 'ESX Server 3.5.0 build-64607' returns an 'method not implemented' fault if + * you try to call it. Query the session manager for the current session of + * this connection instead and re-login if there is no current session for this + * connection. + */ +#define ESX_VI_USE_SESSION_IS_ACTIVE 0 + +int +esxVI_EnsureSession(virConnectPtr conn, esxVI_Context *ctx) +{ + int result = 0; +#if ESX_VI_USE_SESSION_IS_ACTIVE + esxVI_Boolean active = esxVI_Boolean_Undefined; +#else + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *sessionManager = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_UserSession *currentSession = NULL; +#endif + + if (ctx->session == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + +#if ESX_VI_USE_SESSION_IS_ACTIVE + if (esxVI_SessionIsActive(conn, ctx, ctx->session->key, + ctx->session->userName, &active) < 0) { + return -1; + } + + if (active != esxVI_Boolean_True) { + esxVI_UserSession_Free(&ctx->session); + + if (esxVI_Login(conn, ctx, ctx->username, ctx->password, + &ctx->session) < 0) { + return -1; + } + } +#else + if (esxVI_String_AppendValueToList(conn, &propertyNameList, + "currentSession") < 0 || + esxVI_GetObjectContent(conn, ctx, ctx->service->sessionManager, + "SessionManager", propertyNameList, + esxVI_Boolean_False, &sessionManager) < 0) { + goto failure; + } + + for (dynamicProperty = sessionManager->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "currentSession")) { + if (esxVI_UserSession_CastFromAnyType(conn, dynamicProperty->val, + ¤tSession) < 0) { + goto failure; + } + + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (currentSession == NULL) { + esxVI_UserSession_Free(&ctx->session); + + if (esxVI_Login(conn, ctx, ctx->username, ctx->password, + &ctx->session) < 0) { + goto failure; + } + } else if (STRNEQ(ctx->session->key, currentSession->key)) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Key of the current session differs from the key at " + "last login"); + goto failure; + } +#endif + + cleanup: +#if ESX_VI_USE_SESSION_IS_ACTIVE + /* nothing */ +#else + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&sessionManager); + esxVI_UserSession_Free(¤tSession); +#endif + + return result; + + failure: + result = -1; + + goto cleanup; + + return 0; +} + + + +int +esxVI_GetObjectContent(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *root, + const char *type, esxVI_String *propertyNameList, + esxVI_Boolean recurse, + esxVI_ObjectContent **objectContentList) +{ + int result = 0; + esxVI_ObjectSpec *objectSpec = NULL; + esxVI_PropertySpec *propertySpec = NULL; + esxVI_PropertyFilterSpec *propertyFilterSpec = NULL; + + if (ctx->fullTraversalSpecList == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (esxVI_ObjectSpec_Alloc(conn, &objectSpec) < 0) { + goto failure; + } + + objectSpec->obj = root; + objectSpec->skip = esxVI_Boolean_False; + + if (recurse == esxVI_Boolean_True) { + objectSpec->selectSet = ctx->fullTraversalSpecList; + } + + if (esxVI_PropertySpec_Alloc(conn, &propertySpec) < 0) { + goto failure; + } + + propertySpec->type = (char *)type; + propertySpec->pathSet = propertyNameList; + + if (esxVI_PropertyFilterSpec_Alloc(conn, &propertyFilterSpec) < 0 || + esxVI_PropertySpec_AppendToList(conn, &propertyFilterSpec->propSet, + propertySpec) < 0 || + esxVI_ObjectSpec_AppendToList(conn, &propertyFilterSpec->objectSet, + objectSpec) < 0) { + goto failure; + } + + result = esxVI_RetrieveProperties(conn, ctx, propertyFilterSpec, + objectContentList); + + cleanup: + /* + * Remove values given by the caller from the data structures to prevent + * them from being freed by the call to esxVI_PropertyFilterSpec_Free(). + */ + if (objectSpec != NULL) { + objectSpec->obj = NULL; + objectSpec->selectSet = NULL; + } + + if (propertySpec != NULL) { + propertySpec->type = NULL; + propertySpec->pathSet = NULL; + } + + esxVI_PropertyFilterSpec_Free(&propertyFilterSpec); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +int +esxVI_GetVirtualMachinePowerState(virConnectPtr conn, + esxVI_ObjectContent *virtualMachine, + esxVI_VirtualMachinePowerState *powerState) +{ + esxVI_DynamicProperty *dynamicProperty; + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "runtime.powerState")) { + return esxVI_VirtualMachinePowerState_CastFromAnyType + (conn, dynamicProperty->val, powerState); + } + } + + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Missing 'runtime.powerState' property"); + + return -1; +} + + + +int +esxVI_GetNumberOfDomainsByPowerState(virConnectPtr conn, esxVI_Context *ctx, + esxVI_VirtualMachinePowerState powerState, + esxVI_Boolean inverse) +{ + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachineList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_VirtualMachinePowerState powerState_; + int numberOfDomains = 0; + + if (esxVI_String_AppendValueToList(conn, &propertyNameList, + "runtime.powerState") < 0 || + esxVI_GetObjectContent(conn, ctx, ctx->vmFolder, "VirtualMachine", + propertyNameList, esxVI_Boolean_True, + &virtualMachineList) < 0) { + goto failure; + } + + for (virtualMachine = virtualMachineList; virtualMachine != NULL; + virtualMachine = virtualMachine->_next) { + for (dynamicProperty = virtualMachine->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "runtime.powerState")) { + if (esxVI_VirtualMachinePowerState_CastFromAnyType + (conn, dynamicProperty->val, &powerState_) < 0) { + goto failure; + } + + if ((inverse != esxVI_Boolean_True && + powerState_ == powerState) || + (inverse == esxVI_Boolean_True && + powerState_ != powerState)) { + numberOfDomains++; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachineList); + + return numberOfDomains; + + failure: + numberOfDomains = -1; + + goto cleanup; +} + + + +int +esxVI_GetVirtualMachineIdentity(virConnectPtr conn, + esxVI_ObjectContent *virtualMachine, + int *id, char **name, unsigned char *uuid) +{ + const char *uuid_string = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + + if (STRNEQ(virtualMachine->obj->type, "VirtualMachine")) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "ObjectContent does not reference a virtual machine"); + return -1; + } + + if (id != NULL) { + if (esxUtil_ParseVirtualMachineIDString + (virtualMachine->obj->value, id) < 0 || *id <= 0) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse positive integer from '%s'", + virtualMachine->obj->value); + goto failure; + } + } + + if (name != NULL) { + if (*name != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + for (dynamicProperty = virtualMachine->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "name")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + *name = strdup(dynamicProperty->val->string); + + if (*name == NULL) { + virReportOOMError(conn); + goto failure; + } + + break; + } + } + + if (*name == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not get name of virtual machine"); + goto failure; + } + } + + if (uuid != NULL) { + for (dynamicProperty = virtualMachine->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "summary.config.uuid")) { + if (esxVI_AnyType_ExpectType(conn, dynamicProperty->val, + esxVI_Type_String) < 0) { + goto failure; + } + + uuid_string = dynamicProperty->val->string; + break; + } + } + + if (uuid_string == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not get UUID of virtual machine"); + goto failure; + } + + if (virUUIDParse(uuid_string, uuid) < 0) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not parse UUID from string '%s'", uuid_string); + goto failure; + } + } + + return 0; + + failure: + if (name != NULL) { + VIR_FREE(*name); + } + + return -1; +} + + + +int +esxVI_LookupHostSystemByIp(virConnectPtr conn, esxVI_Context *ctx, + const char *ip, esxVI_String *propertyNameList, + esxVI_ObjectContent **hostSystem) +{ + int result = 0; + esxVI_ManagedObjectReference *managedObjectReference = NULL; + + if (hostSystem == NULL || *hostSystem != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_FindByIp(conn, ctx, ctx->datacenter, ip, esxVI_Boolean_False, + &managedObjectReference) < 0) { + goto failure; + } + + if (esxVI_GetObjectContent(conn, ctx, managedObjectReference, + "HostSystem", propertyNameList, + esxVI_Boolean_False, hostSystem) < 0) { + goto failure; + } + + cleanup: + esxVI_ManagedObjectReference_Free(&managedObjectReference); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +int +esxVI_LookupVirtualMachineByUuid(virConnectPtr conn, esxVI_Context *ctx, + const unsigned char *uuid, + esxVI_String *propertyNameList, + esxVI_ObjectContent **virtualMachine) +{ + int result = 0; + esxVI_ManagedObjectReference *managedObjectReference = NULL; + + if (virtualMachine == NULL || *virtualMachine != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_FindByUuid(conn, ctx, ctx->datacenter, uuid, esxVI_Boolean_True, + &managedObjectReference) < 0) { + goto failure; + } + + if (esxVI_GetObjectContent(conn, ctx, managedObjectReference, + "VirtualMachine", propertyNameList, + esxVI_Boolean_False, virtualMachine) < 0) { + goto failure; + } + + cleanup: + esxVI_ManagedObjectReference_Free(&managedObjectReference); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +int +esxVI_StartVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx, + const char *name, const char *request, + esxVI_ManagedObjectReference **task) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0) { + goto failure; + } + + remoteRequest->request = (char *)request; + + if (virAsprintf(&remoteRequest->xpathExpression, + ESX_VI__SOAP__RESPONSE_XPATH("%s_Task"), name) < 0) { + virReportOOMError(conn); + goto failure; + } + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (conn, remoteResponse, task, "Task") < 0) { + goto failure; + } + + cleanup: + /* + * Remove values given by the caller from the data structures to prevent + * them from being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->request = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +int +esxVI_StartSimpleVirtualMachineTask + (virConnectPtr conn, esxVI_Context *ctx, const char *name, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task) +{ + int result = 0; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + char *request = NULL; + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<"); + virBufferAdd(&buffer, name, -1); + virBufferAddLit(&buffer, "_Task xmlns=\"urn:vim25\">"); + + if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this", + &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</"); + virBufferAdd(&buffer, name, -1); + virBufferAddLit(&buffer, "_Task>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + request = virBufferContentAndReset(&buffer); + + if (esxVI_StartVirtualMachineTask(conn, ctx, name, request, task) < 0) { + goto failure; + } + + cleanup: + VIR_FREE(request); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_SimpleVirtualMachineMethod(virConnectPtr conn, esxVI_Context *ctx, + const char *name, + esxVI_ManagedObjectReference *virtualMachine) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<"); + virBufferAdd(&buffer, name, -1); + virBufferAddLit(&buffer, " xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this", + &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</"); + virBufferAdd(&buffer, name, -1); + virBufferAddLit(&buffer, ">"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0) { + goto failure; + } + + cleanup: + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *task, + esxVI_TaskInfoState *finalState) +{ + int result = 0; + esxVI_ObjectSpec *objectSpec = NULL; + esxVI_PropertySpec *propertySpec = NULL; + esxVI_PropertyFilterSpec *propertyFilterSpec = NULL; + esxVI_ManagedObjectReference *propertyFilter = NULL; + char *version = NULL; + esxVI_UpdateSet *updateSet = NULL; + esxVI_PropertyFilterUpdate *propertyFilterUpdate = NULL; + esxVI_ObjectUpdate *objectUpdate = NULL; + esxVI_PropertyChange *propertyChange = NULL; + esxVI_AnyType *propertyValue = NULL; + esxVI_TaskInfoState state = esxVI_TaskInfoState_Undefined; + + version = strdup(""); + + if (version == NULL) { + virReportOOMError(conn); + goto failure; + } + + if (esxVI_ObjectSpec_Alloc(conn, &objectSpec) < 0) { + goto failure; + } + + objectSpec->obj = task; + objectSpec->skip = esxVI_Boolean_False; + + if (esxVI_PropertySpec_Alloc(conn, &propertySpec) < 0) { + goto failure; + } + + propertySpec->type = task->type; + + if (esxVI_String_AppendValueToList(conn, &propertySpec->pathSet, + "info.state") < 0 || + esxVI_PropertyFilterSpec_Alloc(conn, &propertyFilterSpec) < 0 || + esxVI_PropertySpec_AppendToList(conn, &propertyFilterSpec->propSet, + propertySpec) < 0 || + esxVI_ObjectSpec_AppendToList(conn, &propertyFilterSpec->objectSet, + objectSpec) < 0 || + esxVI_CreateFilter(conn, ctx, propertyFilterSpec, esxVI_Boolean_True, + &propertyFilter) < 0) { + goto failure; + } + + while (state != esxVI_TaskInfoState_Success && + state != esxVI_TaskInfoState_Error) { + esxVI_UpdateSet_Free(&updateSet); + + if (esxVI_WaitForUpdates(conn, ctx, version, &updateSet) < 0) { + goto failure; + } + + VIR_FREE(version); + version = strdup(updateSet->version); + + if (version == NULL) { + virReportOOMError(conn); + goto failure; + } + + if (updateSet->filterSet == NULL) { + continue; + } + + for (propertyFilterUpdate = updateSet->filterSet; + propertyFilterUpdate != NULL; + propertyFilterUpdate = propertyFilterUpdate->_next) { + for (objectUpdate = propertyFilterUpdate->objectSet; + objectUpdate != NULL; objectUpdate = objectUpdate->_next) { + for (propertyChange = objectUpdate->changeSet; + propertyChange != NULL; + propertyChange = propertyChange->_next) { + if (STREQ(propertyChange->name, "info.state")) { + if (propertyChange->op == esxVI_PropertyChangeOp_Add || + propertyChange->op == esxVI_PropertyChangeOp_Assign) { + propertyValue = propertyChange->val; + } else { + propertyValue = NULL; + } + } + } + } + } + + if (propertyValue == NULL) { + continue; + } + + if (esxVI_TaskInfoState_CastFromAnyType(conn, propertyValue, + &state) < 0) { + goto failure; + } + } + + if (esxVI_DestroyPropertyFilter(conn, ctx, propertyFilter) < 0) { + VIR_DEBUG0("DestroyPropertyFilter failed"); + } + + if (esxVI_TaskInfoState_CastFromAnyType(conn, propertyValue, + finalState) < 0) { + goto failure; + } + + cleanup: + /* + * Remove values given by the caller from the data structures to prevent + * them from being freed by the call to esxVI_PropertyFilterSpec_Free(). + */ + if (objectSpec != NULL) { + objectSpec->obj = NULL; + } + + if (propertySpec != NULL) { + propertySpec->type = NULL; + } + + esxVI_PropertyFilterSpec_Free(&propertyFilterSpec); + esxVI_ManagedObjectReference_Free(&propertyFilter); + VIR_FREE(version); + esxVI_UpdateSet_Free(&updateSet); + + return result; + + failure: + result = -1; + + goto cleanup; +} diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h new file mode 100644 index 0000000..a9343fb --- /dev/null +++ b/src/esx/esx_vi.h @@ -0,0 +1,251 @@ + +/* + * esx_vi.h: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_VI_H__ +#define __ESX_VI_H__ + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <curl/curl.h> + +#include "internal.h" +#include "datatypes.h" +#include "esx_vi_types.h" + +typedef struct _esxVI_Context esxVI_Context; +typedef struct _esxVI_RemoteResponse esxVI_RemoteResponse; +typedef struct _esxVI_RemoteRequest esxVI_RemoteRequest; +typedef struct _esxVI_Enumeration esxVI_Enumeration; +typedef struct _esxVI_EnumerationValue esxVI_EnumerationValue; +typedef struct _esxVI_List esxVI_List; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Context + */ + +struct _esxVI_Context { + char *url; + CURL *curl_handle; + struct curl_slist *curl_headers; + virMutex curl_lock; + char *username; + char *password; + esxVI_ServiceContent *service; + esxVI_UserSession *session; + esxVI_ManagedObjectReference *datacenter; + esxVI_ManagedObjectReference *vmFolder; + esxVI_ManagedObjectReference *hostFolder; + esxVI_SelectionSpec *fullTraversalSpecList; +}; + +int esxVI_Context_Alloc(virConnectPtr conn, esxVI_Context **ctx); +void esxVI_Context_Free(esxVI_Context **ctx); +int esxVI_Context_Connect(virConnectPtr conn, esxVI_Context *ctx, + const char *url, const char *username, + const char *password); +int esxVI_Context_Download(virConnectPtr conn, esxVI_Context *ctx, + const char *url, char **content); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * RemoteRequest + */ + +struct _esxVI_RemoteRequest { + char *request; /* required */ + char *xpathExpression; /* optional */ +}; + +int esxVI_RemoteRequest_Alloc(virConnectPtr conn, + esxVI_RemoteRequest **remoteRequest); +void esxVI_RemoteRequest_Free(esxVI_RemoteRequest **remoteRequest); +int esxVI_RemoteRequest_Execute(virConnectPtr conn, esxVI_Context *ctx, + esxVI_RemoteRequest *remoteRequest, + esxVI_RemoteResponse **remoteResponse); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * RemoteResponse + */ + +struct _esxVI_RemoteResponse { + long response_code; /* required */ + char *response; /* required */ + xmlDocPtr document; /* optional */ + xmlXPathContextPtr xpathContext; /* optional */ + xmlXPathObjectPtr xpathObject; /* optional */ +}; + +typedef int (*esxVI_RemoteResponse_DeserializeFunc) (virConnectPtr conn, + xmlNodePtr node, + void **item); +typedef int (*esxVI_RemoteResponse_DeserializeListFunc) (virConnectPtr conn, + xmlNodePtr node, + esxVI_List **list); + +int esxVI_RemoteResponse_Alloc(virConnectPtr conn, + esxVI_RemoteResponse **remoteResponse); +void esxVI_RemoteResponse_Free(esxVI_RemoteResponse **remoteResponse); +int esxVI_RemoteResponse_DeserializeXPathObject + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_RemoteResponse_DeserializeFunc deserializeFunc, void **item); +int esxVI_RemoteResponse_DeserializeXPathObjectList + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_RemoteResponse_DeserializeListFunc deserializeListFunc, + esxVI_List **list); +int esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse, + esxVI_ManagedObjectReference **managedObjectReference, + const char *expectedType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Enumeration + */ + +struct _esxVI_EnumerationValue { + const char *name; + int value; +}; + +struct _esxVI_Enumeration { + const char *type; + esxVI_EnumerationValue values[10]; +}; + +int esxVI_Enumeration_CastFromAnyType(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + esxVI_AnyType *anyType, int *boolean); +int esxVI_Enumeration_Serialize(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + int value, const char *element, + virBufferPtr output, esxVI_Boolean required); +int esxVI_Enumeration_Deserialize(virConnectPtr conn, + const esxVI_Enumeration *enumeration, + xmlNodePtr node, int *value); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * List + */ + +struct _esxVI_List { + esxVI_List *_next; +}; + +typedef int (*esxVI_List_FreeFunc) (esxVI_List **item); +typedef int (*esxVI_List_DeepCopyFunc) (virConnectPtr conn, esxVI_List **dest, + esxVI_List *src); +typedef int (*esxVI_List_SerializeFunc) (virConnectPtr conn, esxVI_List *item, + const char *element, + virBufferPtr output, + esxVI_Boolean required); +typedef int (*esxVI_List_DeserializeFunc) (virConnectPtr conn, xmlNodePtr node, + esxVI_List **item); + +int esxVI_List_Append(virConnectPtr conn, esxVI_List **list, esxVI_List *item); +int esxVI_List_DeepCopy(virConnectPtr conn, esxVI_List **destList, + esxVI_List *srcList, + esxVI_List_DeepCopyFunc deepCopyFunc, + esxVI_List_FreeFunc freeFunc); +int esxVI_List_Serialize(virConnectPtr conn, esxVI_List *list, + const char *element, virBufferPtr output, + esxVI_Boolean required, + esxVI_List_SerializeFunc serializeFunc); +int esxVI_List_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_List **list, + esxVI_List_DeserializeFunc deserializeFunc, + esxVI_List_FreeFunc freeFunc); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Utility and Convenience Functions + */ + +int +esxVI_Alloc(virConnectPtr conn, void **ptrptr, size_t size); + +int +esxVI_CheckSerializationNecessity(virConnectPtr conn, const char *element, + esxVI_Boolean required); + +int esxVI_BuildFullTraversalSpecItem + (virConnectPtr conn, esxVI_SelectionSpec **fullTraversalSpecList, + const char *name, const char *type, const char *path, + const char *selectSetNames); +int esxVI_BuildFullTraversalSpecList + (virConnectPtr conn, esxVI_SelectionSpec **fullTraversalSpecList); + +int esxVI_EnsureSession(virConnectPtr conn, esxVI_Context *ctx); + +int esxVI_GetObjectContent(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *root, + const char *type, esxVI_String *propertyNameList, + esxVI_Boolean recurse, + esxVI_ObjectContent **objectContentList); + +int esxVI_GetVirtualMachinePowerState + (virConnectPtr conn, esxVI_ObjectContent *virtualMachine, + esxVI_VirtualMachinePowerState *powerState); + +int esxVI_GetNumberOfDomainsByPowerState + (virConnectPtr conn, esxVI_Context *ctx, + esxVI_VirtualMachinePowerState powerState, esxVI_Boolean inverse); + +int esxVI_GetVirtualMachineIdentity(virConnectPtr conn, + esxVI_ObjectContent *virtualMachine, + int *id, char **name, unsigned char *uuid); + +int esxVI_LookupHostSystemByIp(virConnectPtr conn, esxVI_Context *ctx, + const char *ip, esxVI_String *propertyNameList, + esxVI_ObjectContent **hostSystem); + +int esxVI_LookupVirtualMachineByUuid(virConnectPtr conn, esxVI_Context *ctx, + const unsigned char *uuid, + esxVI_String *propertyNameList, + esxVI_ObjectContent **virtualMachine); + +int esxVI_StartVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx, + const char *name, const char *request, + esxVI_ManagedObjectReference **task); + +int esxVI_StartSimpleVirtualMachineTask + (virConnectPtr conn, esxVI_Context *ctx, const char *name, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task); + +int esxVI_SimpleVirtualMachineMethod + (virConnectPtr conn, esxVI_Context *ctx, const char *name, + esxVI_ManagedObjectReference *virtualMachine); + +int esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *task, + esxVI_TaskInfoState *finalState); + +#endif /* __ESX_VI_H__ */ diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c new file mode 100644 index 0000000..9a659df --- /dev/null +++ b/src/esx/esx_vi_methods.c @@ -0,0 +1,1315 @@ + +/* + * esx_vi_methods.c: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "buf.h" +#include "memory.h" +#include "logging.h" +#include "uuid.h" +#include "virterror_internal.h" +#include "esx_vi_methods.h" +#include "esx_util.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_VI_ERROR(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + +#define ESX_VI__SOAP__REQUEST_HEADER \ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \ + "<soapenv:Envelope " \ + "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " \ + "xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" " \ + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" \ + "<soapenv:Body>" + +#define ESX_VI__SOAP__REQUEST_FOOTER \ + "</soapenv:Body>" \ + "</soapenv:Envelope>" + +#define ESX_VI__SOAP__RESPONSE_XPATH(_type) \ + ((char *)"/soapenv:Envelope/soapenv:Body/" \ + "vim:"_type"Response/vim:returnval") + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Methods + */ + +static const char *_esxVI_RetrieveServiceContentRequest = +ESX_VI__SOAP__REQUEST_HEADER + "<RetrieveServiceContent xmlns=\"urn:vim25\">" + "<_this xmlns=\"urn:vim25\" " + "xsi:type=\"ManagedObjectReference\" " + "type=\"ServiceInstance\">" + "ServiceInstance" + "</_this>" + "</RetrieveServiceContent>" +ESX_VI__SOAP__REQUEST_FOOTER; + +int +esxVI_RetrieveServiceContent(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ServiceContent **serviceContent) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + + if (serviceContent == NULL || *serviceContent != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0) { + goto failure; + } + + remoteRequest->request = (char *)_esxVI_RetrieveServiceContentRequest; + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("RetrieveServiceContent"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObject + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeFunc) + esxVI_ServiceContent_Deserialize, + (void **)serviceContent) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->request = NULL; + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +int +esxVI_Login(virConnectPtr conn, esxVI_Context *ctx, + const char *userName, const char *password, + esxVI_UserSession **userSession) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (userSession == NULL || *userSession != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<Login xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->sessionManager, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_String_SerializeValue(conn, userName, "userName", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_String_SerializeValue(conn, password, "password", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</Login>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = ESX_VI__SOAP__RESPONSE_XPATH("Login"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObject + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeFunc) + esxVI_UserSession_Deserialize, + (void **)userSession) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_Logout(virConnectPtr conn, esxVI_Context *ctx) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<Logout xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->sessionManager, + "_this", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</Logout>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0) { + goto failure; + } + + cleanup: + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_SessionIsActive(virConnectPtr conn, esxVI_Context *ctx, + const char *sessionID, const char *userName, + esxVI_Boolean *active) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (active == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<SessionIsActive xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->sessionManager, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_String_SerializeValue(conn, sessionID, "sessionID", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_String_SerializeValue(conn, userName, "userName", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</SessionIsActive>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("SessionIsActive"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObject + (conn, remoteResponse, + /* + * FIXME: esxVI_Boolean_Deserialize expects *boolean, + * esxVI_RemoteResponse_DeserializeFunc expects void **, + * passing *boolean casted to void * to it + */ + (esxVI_RemoteResponse_DeserializeFunc)esxVI_Boolean_Deserialize, + (void *)active) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_RetrieveProperties(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PropertyFilterSpec *propertyFilterSpecList, + esxVI_ObjectContent **objectContentList) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (objectContentList == NULL || *objectContentList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<RetrieveProperties xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->propertyCollector, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_PropertyFilterSpec_SerializeList(conn, propertyFilterSpecList, + "specSet", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</RetrieveProperties>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("RetrieveProperties"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectList + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeListFunc) + esxVI_ObjectContent_DeserializeList, + (esxVI_List **)objectContentList) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_PowerOnVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task) +{ + return esxVI_StartSimpleVirtualMachineTask(conn, ctx, "PowerOnVM", + virtualMachine, task); +} + + + +int +esxVI_PowerOffVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task) +{ + return esxVI_StartSimpleVirtualMachineTask(conn, ctx, "PowerOffVM", + virtualMachine, task); +} + + + +int +esxVI_SuspendVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task) +{ + return esxVI_StartSimpleVirtualMachineTask(conn, ctx, "SuspendVM", + virtualMachine, task); +} + + + +int +esxVI_MigrateVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference *resourcePool, + esxVI_ManagedObjectReference *hostSystem, + esxVI_ManagedObjectReference **task) +{ + int result = 0; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + char *request = NULL; + + if (task == NULL || *task != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<MigrateVM_Task xmlns=\"urn:vim25\">"); + + if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this", + &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, resourcePool, "pool", + &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, hostSystem, "host", + &buffer, + esxVI_Boolean_True) < 0 || + esxVI_VirtualMachineMovePriority_Serialize + (conn, esxVI_VirtualMachineMovePriority_DefaultPriority, + "priority", &buffer, esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</MigrateVM_Task>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + request = virBufferContentAndReset(&buffer); + + if (esxVI_StartVirtualMachineTask(conn, ctx, "MigrateVM", request, + task) < 0) { + goto failure; + } + + cleanup: + VIR_FREE(request); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_ReconfigVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_VirtualMachineConfigSpec *spec, + esxVI_ManagedObjectReference **task) +{ + int result = 0; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + char *request = NULL; + + if (task == NULL || *task != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<ReconfigVM_Task xmlns=\"urn:vim25\">"); + + if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this", + &buffer, + esxVI_Boolean_True) < 0 || + esxVI_VirtualMachineConfigSpec_Serialize(conn, spec, "spec", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</ReconfigVM_Task>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + request = virBufferContentAndReset(&buffer); + + if (esxVI_StartVirtualMachineTask(conn, ctx, "ReconfigVM", request, + task) < 0) { + goto failure; + } + + cleanup: + VIR_FREE(request); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_CreateFilter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PropertyFilterSpec *propertyFilterSpec, + esxVI_Boolean partialUpdates, + esxVI_ManagedObjectReference **propertyFilter) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (propertyFilter == NULL || *propertyFilter != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<CreateFilter xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->propertyCollector, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_PropertyFilterSpec_Serialize(conn, propertyFilterSpec, "spec", + &buffer, esxVI_Boolean_True) < 0 || + esxVI_Boolean_Serialize(conn, partialUpdates, "partialUpdates", + &buffer, esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</CreateFilter>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("CreateFilter"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (conn, remoteResponse, propertyFilter, "PropertyFilter") < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_DestroyPropertyFilter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *propertyFilter) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<DestroyPropertyFilter xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, propertyFilter, "_this", + &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</DestroyPropertyFilter>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0) { + goto failure; + } + + cleanup: + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_WaitForUpdates(virConnectPtr conn, esxVI_Context *ctx, + const char *version, esxVI_UpdateSet **updateSet) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (updateSet == NULL || *updateSet != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<WaitForUpdates xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, + ctx->service->propertyCollector, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_String_SerializeValue(conn, version, "version", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</WaitForUpdates>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("WaitForUpdates"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObject + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeFunc)esxVI_UpdateSet_Deserialize, + (void **)updateSet) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_RebootGuest(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine) +{ + return esxVI_SimpleVirtualMachineMethod(conn, ctx, "RebootGuest", + virtualMachine); +} + + + +int +esxVI_ShutdownGuest(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine) +{ + return esxVI_SimpleVirtualMachineMethod(conn, ctx, "ShutdownGuest", + virtualMachine); +} + + + +int +esxVI_ValidateMigration(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachineList, + esxVI_VirtualMachinePowerState powerState, + esxVI_String *testTypeList, + esxVI_ManagedObjectReference *resourcePool, + esxVI_ManagedObjectReference *hostSystem, + esxVI_Event **eventList) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (eventList == NULL || *eventList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<ValidateMigration xmlns=\"urn:vim25\">" + "<_this xmlns=\"urn:vim25\" " + "xsi:type=\"ManagedObjectReference\" " + "type=\"ServiceInstance\">" + "ServiceInstance" + "</_this>"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_SerializeList(conn, virtualMachineList, + "vm", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_VirtualMachinePowerState_Serialize(conn, powerState, "state", + &buffer, + esxVI_Boolean_False) < 0 || + esxVI_String_SerializeList(conn, testTypeList, "testType", &buffer, + esxVI_Boolean_False) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, resourcePool, "pool", + &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, hostSystem, "host", + &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</ValidateMigration>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("ValidateMigration"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectList + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeListFunc) + esxVI_Event_DeserializeList, + (esxVI_List **)eventList) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_FindByIp(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *datacenter, + const char *ip, esxVI_Boolean vmSearch, + esxVI_ManagedObjectReference **managedObjectReference) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (managedObjectReference == NULL || *managedObjectReference != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<FindByIp xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, ctx->service->searchIndex, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, datacenter, + "datacenter", &buffer, + esxVI_Boolean_False) < 0 || + esxVI_String_SerializeValue(conn, ip, "ip", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_Boolean_Serialize(conn, vmSearch, "vmSearch", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</FindByIp>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("FindByIp"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (conn, remoteResponse, managedObjectReference, + vmSearch == esxVI_Boolean_True ? "VirtualMachine" + : "HostSystem") < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_FindByUuid(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *datacenter, + const unsigned char *uuid, esxVI_Boolean vmSearch, + esxVI_ManagedObjectReference **managedObjectReference) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (managedObjectReference == NULL || *managedObjectReference != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virUUIDFormat(uuid, uuid_string); + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<FindByUuid xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, ctx->service->searchIndex, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, datacenter, + "datacenter", &buffer, + esxVI_Boolean_False) < 0 || + esxVI_String_SerializeValue(conn, uuid_string, "uuid", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_Boolean_Serialize(conn, vmSearch, "vmSearch", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</FindByUuid>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("FindByUuid"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference + (conn, remoteResponse, managedObjectReference, + vmSearch == esxVI_Boolean_True ? "VirtualMachine" + : "HostSystem") < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_QueryAvailablePerfMetric(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *entity, + esxVI_DateTime *beginTime, + esxVI_DateTime *endTime, esxVI_Int *intervalId, + esxVI_PerfMetricId **perfMetricIdList) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (perfMetricIdList == NULL || *perfMetricIdList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<QueryAvailablePerfMetric xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, ctx->service->perfManager, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, entity, + "entity", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_DateTime_Serialize(conn, beginTime, "beginTime", &buffer, + esxVI_Boolean_False) < 0 || + esxVI_DateTime_Serialize(conn, endTime, "endTime", &buffer, + esxVI_Boolean_False) < 0 || + esxVI_Int_Serialize(conn, intervalId, "intervalId", &buffer, + esxVI_Boolean_False) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</QueryAvailablePerfMetric>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("QueryAvailablePerfMetric"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectList + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeListFunc) + esxVI_PerfMetricId_DeserializeList, + (esxVI_List **)perfMetricIdList) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_QueryPerfCounter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_Int *counterIdList, + esxVI_PerfCounterInfo **perfCounterInfoList) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (perfCounterInfoList == NULL || *perfCounterInfoList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<QueryPerfCounter xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, ctx->service->perfManager, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_Int_SerializeList(conn, counterIdList, "counterId", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</QueryPerfCounter>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = + ESX_VI__SOAP__RESPONSE_XPATH("QueryPerfCounter"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectList + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeListFunc) + esxVI_PerfCounterInfo_DeserializeList, + (esxVI_List **)perfCounterInfoList) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} + + + +int +esxVI_QueryPerf(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PerfQuerySpec *querySpecList, + esxVI_PerfEntityMetric **perfEntityMetricList) +{ + int result = 0; + esxVI_RemoteRequest *remoteRequest = NULL; + esxVI_RemoteResponse *remoteResponse = NULL; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + + if (ctx->service == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call"); + return -1; + } + + if (perfEntityMetricList == NULL || *perfEntityMetricList != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER); + virBufferAddLit(&buffer, "<QueryPerf xmlns=\"urn:vim25\">"); + + if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 || + esxVI_ManagedObjectReference_Serialize(conn, ctx->service->perfManager, + "_this", &buffer, + esxVI_Boolean_True) < 0 || + esxVI_PerfQuerySpec_SerializeList(conn, querySpecList, "querySpec", + &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, "</QueryPerf>"); + virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER); + + if (virBufferError(&buffer)) { + virReportOOMError(conn); + goto failure; + } + + remoteRequest->request = virBufferContentAndReset(&buffer); + remoteRequest->xpathExpression = ESX_VI__SOAP__RESPONSE_XPATH("QueryPerf"); + + if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest, + &remoteResponse) < 0 || + esxVI_RemoteResponse_DeserializeXPathObjectList + (conn, remoteResponse, + (esxVI_RemoteResponse_DeserializeListFunc) + esxVI_PerfEntityMetric_DeserializeList, + (esxVI_List **)perfEntityMetricList) < 0) { + goto failure; + } + + cleanup: + /* + * Remove static values from the data structures to prevent them from + * being freed by the call to esxVI_RemoteRequest_Free(). + */ + if (remoteRequest != NULL) { + remoteRequest->xpathExpression = NULL; + } + + esxVI_RemoteRequest_Free(&remoteRequest); + esxVI_RemoteResponse_Free(&remoteResponse); + + return result; + + failure: + free(virBufferContentAndReset(&buffer)); + + result = -1; + + goto cleanup; +} diff --git a/src/esx/esx_vi_methods.h b/src/esx/esx_vi_methods.h new file mode 100644 index 0000000..630bff2 --- /dev/null +++ b/src/esx/esx_vi_methods.h @@ -0,0 +1,125 @@ + +/* + * esx_vi_methods.h: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_VI_METHODS_H__ +#define __ESX_VI_METHODS_H__ + +#include "esx_vi.h" +#include "esx_vi_types.h" + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Methods + */ + +int esxVI_RetrieveServiceContent(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ServiceContent **serviceContent); + +int esxVI_Login(virConnectPtr conn, esxVI_Context *ctx, + const char *userName, const char *password, + esxVI_UserSession **userSession); + +int esxVI_Logout(virConnectPtr conn, esxVI_Context *ctx); + +int esxVI_SessionIsActive(virConnectPtr conn, esxVI_Context *ctx, + const char *sessionID, const char *userName, + esxVI_Boolean *active); + +int esxVI_RetrieveProperties(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PropertyFilterSpec *propertyFilterSpecList, + esxVI_ObjectContent **objectContentList); + +int esxVI_PowerOnVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task); + +int esxVI_PowerOffVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task); + +int esxVI_SuspendVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference **task); + +int esxVI_MigrateVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_ManagedObjectReference *resourcePool, + esxVI_ManagedObjectReference *hostSystem, + esxVI_ManagedObjectReference **task); + +int esxVI_ReconfigVM_Task(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine, + esxVI_VirtualMachineConfigSpec *spec, + esxVI_ManagedObjectReference **task); + +int esxVI_CreateFilter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PropertyFilterSpec *propertyFilterSpec, + esxVI_Boolean partialUpdates, + esxVI_ManagedObjectReference **propertyFilter); + +int esxVI_DestroyPropertyFilter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *propertyFilter); + +int esxVI_WaitForUpdates(virConnectPtr conn, esxVI_Context *ctx, + const char *version, esxVI_UpdateSet **updateSet); + +int esxVI_RebootGuest(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine); + +int esxVI_ShutdownGuest(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachine); + +int esxVI_ValidateMigration(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *virtualMachineList, + esxVI_VirtualMachinePowerState powerState, + esxVI_String *testTypeList, // FIXME: see ValidateMigrationTestType + esxVI_ManagedObjectReference *resourcePool, + esxVI_ManagedObjectReference *hostSystem, + esxVI_Event **eventList); + +int esxVI_FindByIp(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *datacenter, + const char *ip, esxVI_Boolean vmSearch, + esxVI_ManagedObjectReference **managedObjectReference); + +int esxVI_FindByUuid(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *datacenter, + const unsigned char *uuid, esxVI_Boolean vmSearch, + esxVI_ManagedObjectReference **managedObjectReference); + +int esxVI_QueryAvailablePerfMetric(virConnectPtr conn, esxVI_Context *ctx, + esxVI_ManagedObjectReference *entity, + esxVI_DateTime *beginTime, + esxVI_DateTime *endTime, + esxVI_Int *intervalId, + esxVI_PerfMetricId **perfMetricIdList); + +int esxVI_QueryPerfCounter(virConnectPtr conn, esxVI_Context *ctx, + esxVI_Int *counterIdList, + esxVI_PerfCounterInfo **perfCounterInfoList); + +int esxVI_QueryPerf(virConnectPtr conn, esxVI_Context *ctx, + esxVI_PerfQuerySpec *querySpecList, + esxVI_PerfEntityMetric **perfEntityMetricList); + +#endif /* __ESX_VI_METHODS_H__ */ diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c new file mode 100644 index 0000000..684b8c7 --- /dev/null +++ b/src/esx/esx_vi_types.c @@ -0,0 +1,2581 @@ + +/* + * esx_vi_types.c: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <libxml/parser.h> +#include <libxml/xpathInternals.h> + +#include "buf.h" +#include "datatypes.h" +#include "memory.h" +#include "logging.h" +#include "util.h" +#include "virterror_internal.h" +#include "esx_vi.h" +#include "esx_vi_types.h" + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_VI_ERROR(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + + + +#define ESV_VI__XML_TAG__OPEN(_buffer, _element, _type) \ + do { \ + virBufferAddLit(_buffer, "<"); \ + virBufferAdd(_buffer, _element, -1); \ + virBufferAddLit(_buffer, " xmlns=\"urn:vim25\" xsi:type=\""); \ + virBufferAdd(_buffer, _type, -1); \ + virBufferAddLit(_buffer, "\">"); \ + } while (0) + + + +#define ESV_VI__XML_TAG__CLOSE(_buffer, _element) \ + do { \ + virBufferAddLit(_buffer, "</"); \ + virBufferAdd(_buffer, _element, -1); \ + virBufferAddLit(_buffer, ">"); \ + } while (0) + + + +#define ESX_VI__TEMPLATE__ALLOC(_type) \ + int \ + esxVI_##_type##_Alloc(virConnectPtr conn, esxVI_##_type **ptrptr) \ + { \ + return esxVI_Alloc(conn, (void **)ptrptr, sizeof (esxVI_##_type)); \ + } + + + +#define ESX_VI__TEMPLATE__FREE(_type, _body) \ + void \ + esxVI_##_type##_Free(esxVI_##_type **ptrptr) \ + { \ + esxVI_##_type *item = NULL; \ + \ + if (ptrptr == NULL || *ptrptr == NULL) { \ + return; \ + } \ + \ + item = *ptrptr; \ + \ + _body \ + \ + VIR_FREE(*ptrptr); \ + } + + + +#define ESX_VI__TEMPLATE__LIST__APPEND(_type) \ + int \ + esxVI_##_type##_AppendToList(virConnectPtr conn, esxVI_##_type **list, \ + esxVI_##_type *item) \ + { \ + return esxVI_List_Append(conn, (esxVI_List **)list, \ + (esxVI_List *)item); \ + } + + + +#define ESX_VI__TEMPLATE__LIST__DEEP_COPY(_type) \ + int \ + esxVI_##_type##_DeepCopyList(virConnectPtr conn, \ + esxVI_##_type **destList, \ + esxVI_##_type *srcList) \ + { \ + return esxVI_List_DeepCopy \ + (conn, (esxVI_List **)destList, (esxVI_List *)srcList, \ + (esxVI_List_DeepCopyFunc)esxVI_##_type##_DeepCopy, \ + (esxVI_List_FreeFunc)esxVI_##_type##_Free); \ + } + + + +#define ESX_VI__TEMPLATE__LIST__SERIALIZE(_type) \ + int \ + esxVI_##_type##_SerializeList(virConnectPtr conn, esxVI_##_type *list, \ + const char* element, virBufferPtr output, \ + esxVI_Boolean required) \ + { \ + return esxVI_List_Serialize(conn, (esxVI_List *)list, \ + element, output, required, \ + (esxVI_List_SerializeFunc) \ + esxVI_##_type##_Serialize); \ + } + + + +#define ESX_VI__TEMPLATE__LIST__DESERIALIZE(_type) \ + int \ + esxVI_##_type##_DeserializeList(virConnectPtr conn, xmlNodePtr node, \ + esxVI_##_type **list) \ + { \ + return esxVI_List_Deserialize \ + (conn, node, (esxVI_List **)list, \ + (esxVI_List_DeserializeFunc)esxVI_##_type##_Deserialize, \ + (esxVI_List_FreeFunc)esxVI_##_type##_Free); \ + } + + + +#define ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(_type) \ + int \ + esxVI_##_type##_CastFromAnyType(virConnectPtr conn, \ + esxVI_AnyType *anyType, \ + esxVI_##_type **ptrptr) \ + { \ + if (anyType == NULL || ptrptr == NULL || *ptrptr != NULL) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); \ + return -1; \ + } \ + \ + if (STRNEQ(anyType->other, #_type)) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Expecting type '%s' but found '%s'", \ + #_type, anyType->other); \ + return -1; \ + } \ + \ + return esxVI_##_type##_Deserialize(conn, anyType->_node, ptrptr); \ + } + + + +#define ESX_VI__TEMPLATE__SERIALIZE_EXTRA(_type, _type_string, _serialize) \ + int \ + esxVI_##_type##_Serialize(virConnectPtr conn, \ + esxVI_##_type *item, \ + const char *element, virBufferPtr output, \ + esxVI_Boolean required) \ + { \ + if (element == NULL || output == NULL ) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); \ + return -1; \ + } \ + \ + if (item == NULL) { \ + return esxVI_CheckSerializationNecessity(conn, element, \ + required); \ + } \ + \ + ESV_VI__XML_TAG__OPEN(output, element, _type_string); \ + \ + _serialize \ + \ + ESV_VI__XML_TAG__CLOSE(output, element); \ + \ + return 0; \ + } + + + +#define ESX_VI__TEMPLATE__SERIALIZE(_type, _serialize) \ + ESX_VI__TEMPLATE__SERIALIZE_EXTRA(_type, #_type, _serialize) + + + +#define ESX_VI__TEMPLATE__DESERIALIZE(_type, _deserialize, _require) \ + int \ + esxVI_##_type##_Deserialize(virConnectPtr conn, xmlNodePtr node, \ + esxVI_##_type **ptrptr) \ + { \ + xmlNodePtr childNode = NULL; \ + \ + if (ptrptr == NULL || *ptrptr != NULL) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); \ + return -1; \ + } \ + \ + if (esxVI_##_type##_Alloc(conn, ptrptr) < 0) { \ + return -1; \ + } \ + \ + for (childNode = node->xmlChildrenNode; childNode != NULL; \ + childNode = childNode->next) { \ + if (childNode->type != XML_ELEMENT_NODE) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Wrong XML element type %d", childNode->type); \ + goto failure; \ + } \ + \ + _deserialize \ + \ + VIR_WARN("Unexpected '%s' property", childNode->name); \ + } \ + \ + _require \ + \ + return 0; \ + \ + failure: \ + esxVI_##_type##_Free(ptrptr); \ + \ + return -1; \ + } + + + +#define ESX_VI__TEMPLATE__DESERIALIZE_NUMBER(_type, _xsdType, _min, _max) \ + int \ + esxVI_##_type##_Deserialize(virConnectPtr conn, xmlNodePtr node, \ + esxVI_##_type **number) \ + { \ + int result = 0; \ + char *string; \ + long long value; \ + \ + if (number == NULL || *number != NULL) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); \ + return -1; \ + } \ + \ + if (esxVI_##_type##_Alloc(conn, number) < 0) { \ + return -1; \ + } \ + \ + string = (char *)xmlNodeListGetString(node->doc, \ + node->xmlChildrenNode, 1); \ + \ + if (string == NULL) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "XML node doesn't contain text, expecting an " \ + _xsdType" value"); \ + goto failure; \ + } \ + \ + if (virStrToLong_ll(string, NULL, 10, &value) < 0) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Unknown value '%s' for "_xsdType, string); \ + goto failure; \ + } \ + \ + if (value < (_min) || value > (_max)) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Value '%s' is not representable as "_xsdType, \ + (const char *) string); \ + goto failure; \ + } \ + \ + (*number)->value = value; \ + \ + cleanup: \ + VIR_FREE(string); \ + \ + return result; \ + \ + failure: \ + esxVI_##_type##_Free(number); \ + \ + result = -1; \ + \ + goto cleanup; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(_type, _name, _required) \ + if (esxVI_##_type##_Serialize(conn, item->_name, #_name, output, \ + esxVI_Boolean_##_required) < 0) { \ + return -1; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(_type, _name, _required) \ + if (esxVI_##_type##_SerializeValue(conn, item->_name, #_name, output, \ + esxVI_Boolean_##_required) < 0) { \ + return -1; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(_type, _name, _required) \ + if (esxVI_##_type##_SerializeList(conn, item->_name, #_name, output, \ + esxVI_Boolean_##_required) < 0) { \ + return -1; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(_type, _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + if (esxVI_##_type##_Deserialize(conn, childNode, \ + &(*ptrptr)->_name) < 0) { \ + goto failure; \ + } \ + \ + continue; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(_type, _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + if (esxVI_##_type##_DeserializeValue(conn, childNode, \ + &(*ptrptr)->_name) < 0) { \ + goto failure; \ + } \ + \ + continue; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(_type, _expected, \ + _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + if (esxVI_##_type##_Deserialize(conn, childNode, &(*ptrptr)->_name, \ + _expected) < 0) { \ + goto failure; \ + } \ + \ + continue; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(_name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + continue; \ + } + + + +#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(_type, _name) \ + if (xmlStrEqual(childNode->name, BAD_CAST #_name)) { \ + esxVI_##_type *_name##Item = NULL; \ + \ + if (esxVI_##_type##_Deserialize(conn, childNode, &_name##Item) < 0) { \ + goto failure; \ + } \ + \ + if (esxVI_##_type##_AppendToList(conn, &(*ptrptr)->_name, \ + _name##Item) < 0) { \ + esxVI_##_type##_Free(&_name##Item); \ + goto failure; \ + } \ + \ + continue; \ + } + + + +/* + * A required property must be != 0 (NULL for pointers, "undefined" == 0 for + * enumeration values). + */ +#define ESX_VI__TEMPLATE__PROPERTY__REQUIRED(_name) \ + if ((*ptrptr)->_name == 0) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Missing required '%s' property", #_name); \ + goto failure; \ + } + + + +#define ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(_type) \ + int \ + esxVI_##_type##_CastFromAnyType(virConnectPtr conn, \ + esxVI_AnyType *anyType, \ + esxVI_##_type *value) \ + { \ + return esxVI_Enumeration_CastFromAnyType \ + (conn, &_esxVI_##_type##_Enumeration, anyType, \ + (int *)value); \ + } + + + +#define ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(_type) \ + int \ + esxVI_##_type##_Serialize(virConnectPtr conn, esxVI_##_type value, \ + const char *element, virBufferPtr output, \ + esxVI_Boolean required) \ + { \ + return esxVI_Enumeration_Serialize(conn, \ + &_esxVI_##_type##_Enumeration, \ + value, element, output, \ + required); \ + } + + + +#define ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(_type) \ + int \ + esxVI_##_type##_Deserialize(virConnectPtr conn, xmlNodePtr node, \ + esxVI_##_type *value) \ + { \ + return esxVI_Enumeration_Deserialize(conn, \ + &_esxVI_##_type##_Enumeration, \ + node, (int *)value); \ + } + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSI: Type + */ + +const char * +esxVI_Type_Name(esxVI_Type type) +{ + switch (type) { + case esxVI_Type_Undefined: + return "undefined"; + + case esxVI_Type_Boolean: + return "xsd:boolean"; + + case esxVI_Type_String: + return "xsd:string"; + + case esxVI_Type_Short: + return "xsd:short"; + + case esxVI_Type_Int: + return "xsd:int"; + + case esxVI_Type_Long: + return "xsd:long"; + + case esxVI_Type_Other: + return "other"; + + default: + return "unknown"; + } +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Boolean + */ + +static const esxVI_Enumeration _esxVI_Boolean_Enumeration = { + "xsd:boolean", { + { "true", esxVI_Boolean_True }, + { "false", esxVI_Boolean_False }, + { NULL, -1 }, + }, +}; + +/* esxVI_Boolean_Serialize */ +ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(Boolean); + +/* esxVI_Boolean_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(Boolean); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: AnyType + */ + +/* esxVI_AnyType_Alloc */ +ESX_VI__TEMPLATE__ALLOC(AnyType); + +/* esxVI_AnyType_Free */ +ESX_VI__TEMPLATE__FREE(AnyType, +{ + xmlFreeNode(item->_node); + VIR_FREE(item->other); + VIR_FREE(item->value); +}); + +int +esxVI_AnyType_ExpectType(virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_Type type) +{ + if (anyType->type != type) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting type '%s' but found '%s'", + esxVI_Type_Name(type), + anyType->type != esxVI_Type_Other + ? esxVI_Type_Name(anyType->type) + : anyType->other); + return -1; + } + + return 0; +} + +int +esxVI_AnyType_DeepCopy(virConnectPtr conn, esxVI_AnyType **dest, + esxVI_AnyType *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_AnyType_Alloc(conn, dest) < 0) { + goto failure; + } + + (*dest)->_node = xmlCopyNode(src->_node, 1); + + if ((*dest)->_node == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not copy an XML node"); + goto failure; + } + + (*dest)->type = src->type; + + if (esxVI_String_DeepCopyValue(conn, &(*dest)->other, src->other) < 0 || + esxVI_String_DeepCopyValue(conn, &(*dest)->value, src->value) < 0) { + goto failure; + } + + switch (src->type) { + case esxVI_Type_Boolean: + (*dest)->boolean = src->boolean; + break; + + case esxVI_Type_String: + (*dest)->string = (*dest)->value; + break; + + case esxVI_Type_Short: + (*dest)->int16 = src->int16; + break; + + case esxVI_Type_Int: + (*dest)->int32 = src->int32; + break; + + case esxVI_Type_Long: + (*dest)->int64 = src->int64; + break; + + default: + break; + } + + return 0; + + failure: + esxVI_AnyType_Free(dest); + + return -1; +} + +int +esxVI_AnyType_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_AnyType **anyType) +{ + long long number; + + if (anyType == NULL || *anyType != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_AnyType_Alloc(conn, anyType) < 0) { + return -1; + } + + (*anyType)->_node = xmlCopyNode(node, 1); + + if ((*anyType)->_node == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not copy an XML node"); + goto failure; + } + + (*anyType)->other = + (char *)xmlGetNsProp + (node, BAD_CAST "type", + BAD_CAST "http://www.w3.org/2001/XMLSchema-instance"); + + if ((*anyType)->other == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing 'type' property"); + goto failure; + } + + (*anyType)->value = + (char *)xmlNodeListGetString(node->doc, node->xmlChildrenNode, 1); + + if ((*anyType)->value == NULL) { + (*anyType)->value = strdup(""); + + if ((*anyType)->value == NULL) { + virReportOOMError(conn); + goto failure; + } + } + + #define _DESERIALIZE_NUMBER(_type, _xsdType, _name, _min, _max) \ + do { \ + if (virStrToLong_ll((*anyType)->value, NULL, 10, &number) < 0) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Unknown value '%s' for "_xsdType, \ + (*anyType)->value); \ + goto failure; \ + } \ + \ + if (number < (_min) || number > (_max)) { \ + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, \ + "Value '%s' is out of "_xsdType" range", \ + (*anyType)->value); \ + goto failure; \ + } \ + \ + (*anyType)->type = esxVI_Type_##_type; \ + (*anyType)->_name = number; \ + } while (0) + + if (STREQ((*anyType)->other, "xsd:boolean")) { + (*anyType)->type = esxVI_Type_Boolean; + + if (STREQ((*anyType)->value, "true")) { + (*anyType)->boolean = esxVI_Boolean_True; + } else if (STREQ((*anyType)->value, "false")) { + (*anyType)->boolean = esxVI_Boolean_False; + } else { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unknown value '%s' for xsd:boolean", + (*anyType)->value); + goto failure; + } + } else if (STREQ((*anyType)->other, "xsd:string")) { + (*anyType)->type = esxVI_Type_String; + (*anyType)->string = (*anyType)->value; + } else if (STREQ((*anyType)->other, "xsd:short")) { + _DESERIALIZE_NUMBER(Short, "xsd:short", int16, INT16_MIN, INT16_MAX); + } else if (STREQ((*anyType)->other, "xsd:int")) { + _DESERIALIZE_NUMBER(Int, "xsd:int", int32, INT32_MIN, INT32_MAX); + } else if (STREQ((*anyType)->other, "xsd:long")) { + _DESERIALIZE_NUMBER(Long, "xsd:long", int64, INT64_MIN, INT64_MAX); + } + + #undef _DESERIALIZE_NUMBER + + return 0; + + failure: + esxVI_AnyType_Free(anyType); + + return -1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: String + */ + +/* esxVI_String_Alloc */ +ESX_VI__TEMPLATE__ALLOC(String); + +/* esxVI_String_Free */ +ESX_VI__TEMPLATE__FREE(String, +{ + esxVI_String_Free(&item->_next); + + VIR_FREE(item->value); +}); + +/* esxVI_String_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(String); + +int +esxVI_String_AppendValueToList(virConnectPtr conn, + esxVI_String **stringList, const char *value) +{ + esxVI_String *string = NULL; + + if (esxVI_String_Alloc(conn, &string) < 0) { + goto failure; + } + + string->value = strdup(value); + + if (string->value == NULL) { + virReportOOMError(conn); + goto failure; + } + + if (esxVI_String_AppendToList(conn, stringList, string) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_String_Free(&string); + + return -1; +} + +int +esxVI_String_AppendValueListToList(virConnectPtr conn, + esxVI_String **stringList, + const char *valueList) +{ + esxVI_String *stringListToAppend = NULL; + const char *value = valueList; + + while (value != NULL && *value != '\0') { + if (esxVI_String_AppendValueToList(conn, &stringListToAppend, + value) < 0) { + goto failure; + } + + value += strlen(value) + 1; + } + + if (esxVI_String_AppendToList(conn, stringList, stringListToAppend) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_String_Free(&stringListToAppend); + + return -1; +} + +int +esxVI_String_DeepCopy(virConnectPtr conn, esxVI_String **dest, + esxVI_String *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_String_Alloc(conn, dest) < 0 || + esxVI_String_DeepCopyValue(conn, &(*dest)->value, src->value)) { + goto failure; + } + + return 0; + + failure: + esxVI_String_Free(dest); + + return -1; +} + +/* esxVI_String_DeepCopyList */ +ESX_VI__TEMPLATE__LIST__DEEP_COPY(String); + +int +esxVI_String_DeepCopyValue(virConnectPtr conn, char **dest, const char *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + *dest = strdup(src); + + if (*dest == NULL) { + virReportOOMError(conn); + return -1; + } + + return 0; +} + +int +esxVI_String_Serialize(virConnectPtr conn, esxVI_String *string, + const char *element, virBufferPtr output, + esxVI_Boolean required) +{ + return esxVI_String_SerializeValue(conn, + string != NULL ? string->value : NULL, + element, output, required); +} + +/* esxVI_String_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(String); + +int +esxVI_String_SerializeValue(virConnectPtr conn, const char *value, + const char *element, virBufferPtr output, + esxVI_Boolean required) +{ + if (element == NULL || output == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (value == NULL) { + return esxVI_CheckSerializationNecessity(conn, element, required); + } + + ESV_VI__XML_TAG__OPEN(output, element, "xsd:string"); + + virBufferAdd(output, value, -1); + + ESV_VI__XML_TAG__CLOSE(output, element); + + return 0; +} + +int +esxVI_String_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_String **string) +{ + if (string == NULL || *string != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_String_Alloc(conn, string) < 0) { + return -1; + } + + (*string)->value = + (char *)xmlNodeListGetString(node->doc, node->xmlChildrenNode, 1); + + if ((*string)->value == NULL) { + (*string)->value = strdup(""); + + if ((*string)->value == NULL) { + virReportOOMError(conn); + goto failure; + } + } + + return 0; + + failure: + esxVI_String_Free(string); + + return -1; +} + +/* esxVI_String_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(String); + +int +esxVI_String_DeserializeValue(virConnectPtr conn, xmlNodePtr node, + char **value) +{ + if (value == NULL || *value != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + *value = (char *)xmlNodeListGetString(node->doc, node->xmlChildrenNode, 1); + + if (*value == NULL) { + *value = strdup(""); + + if (*value == NULL) { + virReportOOMError(conn); + return -1; + } + } + + return 0; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Int + */ + +/* esxVI_Int_Alloc */ +ESX_VI__TEMPLATE__ALLOC(Int); + +/* esxVI_Int_Free */ +ESX_VI__TEMPLATE__FREE(Int, +{ + esxVI_Int_Free(&item->_next); +}); + +/* esxVI_Int_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(Int); + +int +esxVI_Int_DeepCopy(virConnectPtr conn, esxVI_Int **dest, esxVI_Int *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_Int_Alloc(conn, dest) < 0) { + goto failure; + } + + (*dest)->value = src->value; + + return 0; + + failure: + esxVI_Int_Free(dest); + + return -1; +} + +/* esxVI_Int_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE_EXTRA(Int, "xsd:int", +{ + virBufferVSprintf(output, "%"PRIi32, item->value); +}); + +/* esxVI_Int_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(Int); + +/* esxVI_Int_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE_NUMBER(Int, "xsd:int", INT32_MIN, INT32_MAX); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Long + */ + +/* esxVI_Long_Alloc */ +ESX_VI__TEMPLATE__ALLOC(Long); + +/* esxVI_Long_Free */ +ESX_VI__TEMPLATE__FREE(Long, +{ + esxVI_Long_Free(&item->_next); +}); + +/* esxVI_Long_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(Long); + +/* esxVI_Long_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE_EXTRA(Long, "xsd:long", +{ + virBufferVSprintf(output, "%"PRIi64, item->value); +}); + +/* esxVI_Long_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(Long); + + +/* esxVI_Long_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE_NUMBER(Long, "xsd:long", INT64_MIN, INT64_MAX); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: DateTime + */ + +/* esxVI_DateTime_Alloc */ +ESX_VI__TEMPLATE__ALLOC(DateTime); + +/* esxVI_DateTime_Free */ +ESX_VI__TEMPLATE__FREE(DateTime, +{ + VIR_FREE(item->value); +}); + +/* esxVI_DateTime_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE_EXTRA(DateTime, "xsd:dateTime", +{ + virBufferAdd(output, item->value, -1); +}); + +int +esxVI_DateTime_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_DateTime **dateTime) +{ + if (dateTime == NULL || *dateTime != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_DateTime_Alloc(conn, dateTime) < 0) { + return -1; + } + + (*dateTime)->value = + (char *)xmlNodeListGetString(node->doc, node->xmlChildrenNode, 1); + + if ((*dateTime)->value == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "XML node doesn't contain text, expecting an " + "xsd:dateTime value"); + goto failure; + } + + return 0; + + failure: + esxVI_DateTime_Free(dateTime); + + return -1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: ObjectUpdateKind + */ + +static const esxVI_Enumeration _esxVI_ObjectUpdateKind_Enumeration = { + "ObjectUpdateKind", { + { "enter", esxVI_ObjectUpdateKind_Enter }, + { "leave", esxVI_ObjectUpdateKind_Leave }, + { "modify", esxVI_ObjectUpdateKind_Modify }, + { NULL, -1 }, + }, +}; + +/* esxVI_ObjectUpdateKind_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(ObjectUpdateKind); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PerfSummaryType + */ + +static const esxVI_Enumeration _esxVI_PerfSummaryType_Enumeration = { + "PerfSummaryType", { + { "average", esxVI_PerfSummaryType_Average }, + { "latest", esxVI_PerfSummaryType_Latest }, + { "maximum", esxVI_PerfSummaryType_Maximum }, + { "minimum", esxVI_PerfSummaryType_Minimum }, + { "none", esxVI_PerfSummaryType_None }, + { "summation", esxVI_PerfSummaryType_Summation }, + { NULL, -1 }, + }, +}; + +/* esxVI_PerfSummaryType_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(PerfSummaryType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PerfStatsType + */ + +static const esxVI_Enumeration _esxVI_PerfStatsType_Enumeration = { + "PerfStatsType", { + { "absolute", esxVI_PerfStatsType_Absolute }, + { "delta", esxVI_PerfStatsType_Delta }, + { "rate", esxVI_PerfStatsType_Rate }, + { NULL, -1 }, + }, +}; + +/* esxVI_PerfStatsType_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(PerfStatsType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PropertyChangeOp + */ + +static const esxVI_Enumeration _esxVI_PropertyChangeOp_Enumeration = { + "PropertyChangeOp", { + { "add", esxVI_PropertyChangeOp_Add }, + { "remove", esxVI_PropertyChangeOp_Remove }, + { "assign", esxVI_PropertyChangeOp_Assign }, + { "indirectRemove", esxVI_PropertyChangeOp_IndirectRemove }, + { NULL, -1 }, + }, +}; + +/* esxVI_PropertyChangeOp_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(PropertyChangeOp); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: SharesLevel + */ + +static const esxVI_Enumeration _esxVI_SharesLevel_Enumeration = { + "SharesLevel", { + { "custom", esxVI_SharesLevel_Custom }, + { "high", esxVI_SharesLevel_High }, + { "low", esxVI_SharesLevel_Low }, + { "normal", esxVI_SharesLevel_Normal }, + { NULL, -1 }, + }, +}; + +/* esxVI_SharesLevel_Serialize */ +ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(SharesLevel); + +/* esxVI_SharesLevel_Deserialize */ +ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(SharesLevel); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: TaskInfoState + */ + +static const esxVI_Enumeration _esxVI_TaskInfoState_Enumeration = { + "TaskInfoState", { + { "error", esxVI_TaskInfoState_Error }, + { "queued", esxVI_TaskInfoState_Queued }, + { "running", esxVI_TaskInfoState_Running }, + { "success", esxVI_TaskInfoState_Success }, + { NULL, -1 }, + }, +}; + +/* esxVI_TaskInfoState_CastFromAnyType */ +ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(TaskInfoState); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: VirtualMachineMovePriority + */ + +static const esxVI_Enumeration _esxVI_VirtualMachineMovePriority_Enumeration = { + "VirtualMachineMovePriority", { + { "lowPriority", esxVI_VirtualMachineMovePriority_LowPriority }, + { "highPriority", esxVI_VirtualMachineMovePriority_HighPriority }, + { "defaultPriority", esxVI_VirtualMachineMovePriority_DefaultPriority }, + { NULL, -1 }, + }, +}; + +/* esxVI_VirtualMachineMovePriority_Serialize */ +ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(VirtualMachineMovePriority); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: VirtualMachinePowerState + */ + +static const esxVI_Enumeration _esxVI_VirtualMachinePowerState_Enumeration = { + "VirtualMachinePowerState", { + { "poweredOff", esxVI_VirtualMachinePowerState_PoweredOff }, + { "poweredOn", esxVI_VirtualMachinePowerState_PoweredOn }, + { "suspended", esxVI_VirtualMachinePowerState_Suspended }, + { NULL, -1 }, + }, +}; + +/* esxVI_VirtualMachinePowerState_CastFromAnyType */ +ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(VirtualMachinePowerState); + +/* esxVI_VirtualMachinePowerState_Serialize */ +ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(VirtualMachinePowerState); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: Fault + */ + +/* esxVI_Fault_Alloc */ +ESX_VI__TEMPLATE__ALLOC(Fault); + +/* esxVI_Fault_Free */ +ESX_VI__TEMPLATE__FREE(Fault, +{ + VIR_FREE(item->faultcode); + VIR_FREE(item->faultstring); +}); + +/* esxVI_Fault_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(Fault, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, faultcode); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, faultstring); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(detail); /* FIXME */ +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(faultcode); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(faultstring); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ManagedObjectReference + */ + +/* esxVI_ManagedObjectReference_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ManagedObjectReference); + +/* esxVI_ManagedObjectReference_Free */ +ESX_VI__TEMPLATE__FREE(ManagedObjectReference, +{ + esxVI_ManagedObjectReference_Free(&item->_next); + + VIR_FREE(item->type); + VIR_FREE(item->value); +}); + +int +esxVI_ManagedObjectReference_DeepCopy(virConnectPtr conn, + esxVI_ManagedObjectReference **dest, + esxVI_ManagedObjectReference *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_ManagedObjectReference_Alloc(conn, dest) < 0 || + esxVI_String_DeepCopyValue(conn, &(*dest)->type, src->type) < 0 || + esxVI_String_DeepCopyValue(conn, &(*dest)->value, src->value) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_ManagedObjectReference_Free(dest); + + return -1; +} + +int +esxVI_ManagedObjectReference_CastFromAnyType + (virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_ManagedObjectReference **managedObjectReference, + const char *expectedType) +{ + if (anyType == NULL || managedObjectReference == NULL || + *managedObjectReference != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (STRNEQ(anyType->other, "ManagedObjectReference")) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting type 'ManagedObjectReference' but found '%s'", + anyType->other); + return -1; + } + + return esxVI_ManagedObjectReference_Deserialize(conn, anyType->_node, + managedObjectReference, + expectedType); +} + +int +esxVI_ManagedObjectReference_Serialize + (virConnectPtr conn, esxVI_ManagedObjectReference *managedObjectReference, + const char *element, virBufferPtr output, esxVI_Boolean required) +{ + if (element == NULL || output == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (managedObjectReference == NULL) { + return esxVI_CheckSerializationNecessity(conn, element, required); + } + + virBufferAddLit(output, "<"); + virBufferAdd(output, element, -1); + virBufferVSprintf(output, + " xmlns=\"urn:vim25\" " + "xsi:type=\"ManagedObjectReference\" type=\"%s\">", + managedObjectReference->type); + + virBufferAdd(output, managedObjectReference->value, -1); + + ESV_VI__XML_TAG__CLOSE(output, element); + + return 0; +} + +/* esxVI_ManagedObjectReference_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(ManagedObjectReference); + +int +esxVI_ManagedObjectReference_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_ManagedObjectReference **managedObjectReference, + const char *expectedType) +{ + if (managedObjectReference == NULL || *managedObjectReference != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (esxVI_ManagedObjectReference_Alloc(conn, managedObjectReference) < 0) { + return -1; + } + + (*managedObjectReference)->type = + (char *)xmlGetNoNsProp(node, BAD_CAST "type"); + + if ((*managedObjectReference)->type == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing 'type' property"); + goto failure; + } + + if (expectedType != NULL && + !STREQ(expectedType, (*managedObjectReference)->type)) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expected type '%s' but found '%s'", expectedType, + (*managedObjectReference)->type); + goto failure; + } + + if (esxVI_String_DeserializeValue(conn, node, + &(*managedObjectReference)->value) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_ManagedObjectReference_Free(managedObjectReference); + + return -1; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: DynamicProperty + */ + +/* esxVI_DynamicProperty_Alloc */ +ESX_VI__TEMPLATE__ALLOC(DynamicProperty); + +/* esxVI_DynamicProperty_Free */ +ESX_VI__TEMPLATE__FREE(DynamicProperty, +{ + esxVI_DynamicProperty_Free(&item->_next); + + VIR_FREE(item->name); + esxVI_AnyType_Free(&item->val); +}); + +int +esxVI_DynamicProperty_DeepCopy(virConnectPtr conn, + esxVI_DynamicProperty **dest, + esxVI_DynamicProperty *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_DynamicProperty_Alloc(conn, dest) < 0 || + esxVI_String_DeepCopyValue(conn, &(*dest)->name, src->name) < 0 || + esxVI_AnyType_DeepCopy(conn, &(*dest)->val, src->val) < 0) { + goto failure; + } + + return 0; + + failure: + esxVI_DynamicProperty_Free(dest); + + return -1; +} + +/* esxVI_DynamicProperty_DeepCopyList */ +ESX_VI__TEMPLATE__LIST__DEEP_COPY(DynamicProperty); + +/* esxVI_DynamicProperty_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(DynamicProperty); + +/* esxVI_DynamicProperty_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(DynamicProperty, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, name); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(AnyType, val); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(name); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(val); +}); + +/* esxVI_DynamicProperty_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(DynamicProperty); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: SelectionSpec + */ + +/* esxVI_SelectionSpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(SelectionSpec); + +void +esxVI_SelectionSpec_Free(esxVI_SelectionSpec **selectionSpec) +{ + esxVI_SelectionSpec *local = NULL; + + if (selectionSpec == NULL || *selectionSpec == NULL) { + return; + } + + esxVI_SelectionSpec_Free(&(*selectionSpec)->_next); + + if ((*selectionSpec)->_super != NULL) { + /* + * Explicitly set this pointer to NULL here, otherwise this is will + * result in a dangling pointer. The actual memory of this object is + * freed by a call from the esxVI_TraversalSpec_Free function to the + * esxVI_SelectionSpec_Free function with the base pointer. + * + * Use a local copy of the pointer and set the reference to NULL, + * otherwise Valgrind complains about invalid writes. + */ + local = *selectionSpec; + *selectionSpec = NULL; + + esxVI_TraversalSpec_Free(&local->_super); + } else { + VIR_FREE((*selectionSpec)->name); + + VIR_FREE(*selectionSpec); + } +} + +/* esxVI_SelectionSpec_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(SelectionSpec); + +int +esxVI_SelectionSpec_Serialize(virConnectPtr conn, + esxVI_SelectionSpec *selectionSpec, + const char *element, virBufferPtr output, + esxVI_Boolean required) +{ + if (element == NULL || output == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (selectionSpec == NULL) { + return esxVI_CheckSerializationNecessity(conn, element, required); + } + + if (selectionSpec->_super != NULL) { + return esxVI_TraversalSpec_Serialize(conn, selectionSpec->_super, + element, output, required); + } + + ESV_VI__XML_TAG__OPEN(output, element, "SelectionSpec"); + + if (esxVI_String_SerializeValue(conn, selectionSpec->name, "name", output, + esxVI_Boolean_False) < 0) { + return -1; + } + + ESV_VI__XML_TAG__CLOSE(output, element); + + return 0; +} + +/* esxVI_SelectionSpec_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(SelectionSpec); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: TraversalSpec extends SelectionSpec + */ + +int +esxVI_TraversalSpec_Alloc(virConnectPtr conn, + esxVI_TraversalSpec **traversalSpec) +{ + if (esxVI_Alloc(conn, (void **)traversalSpec, + sizeof (esxVI_TraversalSpec)) < 0) { + return -1; + } + + if (esxVI_SelectionSpec_Alloc(conn, &(*traversalSpec)->_base) < 0) { + esxVI_TraversalSpec_Free(traversalSpec); + return -1; + } + + (*traversalSpec)->_base->_super = *traversalSpec; + + return 0; +} + +void +esxVI_TraversalSpec_Free(esxVI_TraversalSpec **traversalSpec) +{ + esxVI_TraversalSpec *local = NULL; + + if (traversalSpec == NULL || *traversalSpec == NULL) { + return; + } + + /* + * Need to store the traversalSpec pointer in a local variable here, + * because it is possible that the traversalSpec pointer and the _super + * pointer represent the same location in memory, e.g. if + * esxVI_SelectionSpec_Free calls esxVI_TraversalSpec_Free with the _super + * pointer as argument. Setting the _super pointer to NULL sets the + * traversalSpec pointer also to NULL, because we're working on a reference + * to this pointer here. + * + * Also use a local copy of the pointer and set the reference to NULL, + * otherwise Valgrind complains about invalid writes. + */ + local = *traversalSpec; + *traversalSpec = NULL; + + /* + * Setting the _super pointer to NULL here is important, otherwise + * esxVI_SelectionSpec_Free would call esxVI_TraversalSpec_Free again, + * resulting in both functions calling each other trying to free the + * _base/_super object until a stackoverflow occurs. + */ + local->_base->_super = NULL; + + esxVI_SelectionSpec_Free(&local->_base); + VIR_FREE(local->type); + VIR_FREE(local->path); + esxVI_SelectionSpec_Free(&local->selectSet); + + VIR_FREE(local); +} + +/* esxVI_TraversalSpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(TraversalSpec, +{ + if (esxVI_String_SerializeValue(conn, item->_base->name, "name", output, + esxVI_Boolean_False) < 0) { + return -1; + } + + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, type, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, path, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Boolean, skip, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(SelectionSpec, selectSet, False); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectSpec + */ + +/* esxVI_ObjectSpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ObjectSpec); + +/* esxVI_ObjectSpec_Free */ +ESX_VI__TEMPLATE__FREE(ObjectSpec, +{ + esxVI_ObjectSpec_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->obj); + esxVI_SelectionSpec_Free(&item->selectSet); +}); + +/* esxVI_ObjectSpec_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(ObjectSpec); + +/* esxVI_ObjectSpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(ObjectSpec, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(ManagedObjectReference, obj, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Boolean, skip, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(SelectionSpec, selectSet, False); +}); + +/* esxVI_ObjectSpec_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(ObjectSpec); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyChange + */ + +/* esxVI_PropertyChange_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PropertyChange); + +/* esxVI_PropertyChange_Free */ +ESX_VI__TEMPLATE__FREE(PropertyChange, +{ + esxVI_PropertyChange_Free(&item->_next); + + VIR_FREE(item->name); + esxVI_AnyType_Free(&item->val); +}); + +/* esxVI_PropertyChange_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PropertyChange); + +/* esxVI_PropertyChange_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PropertyChange, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, name); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(PropertyChangeOp, op); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(AnyType, val); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(name); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(op); +}); + +/* esxVI_PropertyChange_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PropertyChange); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertySpec + */ + +/* esxVI_PropertySpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PropertySpec); + +/* esxVI_PropertySpec_Free */ +ESX_VI__TEMPLATE__FREE(PropertySpec, +{ + esxVI_PropertySpec_Free(&item->_next); + + VIR_FREE(item->type); + esxVI_String_Free(&item->pathSet); +}); + +/* esxVI_PropertySpec_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PropertySpec); + +/* esxVI_PropertySpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(PropertySpec, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, type, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Boolean, all, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(String, pathSet, False); +}); + +/* esxVI_PropertySpec_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(PropertySpec); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyFilterSpec + */ + +/* esxVI_PropertyFilterSpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PropertyFilterSpec); + +/* esxVI_PropertyFilterSpec_Free */ +ESX_VI__TEMPLATE__FREE(PropertyFilterSpec, +{ + esxVI_PropertyFilterSpec_Free(&item->_next); + + esxVI_PropertySpec_Free(&item->propSet); + esxVI_ObjectSpec_Free(&item->objectSet); +}); + +/* esxVI_PropertyFilterSpec_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PropertyFilterSpec); + +/* esxVI_PropertyFilterSpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(PropertyFilterSpec, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(PropertySpec, propSet, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(ObjectSpec, objectSet, True); +}); + +/* esxVI_PropertyFilterSpec_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(PropertyFilterSpec); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectContent + */ + +/* esxVI_ObjectContent_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ObjectContent); + +/* esxVI_ObjectContent_Free */ +ESX_VI__TEMPLATE__FREE(ObjectContent, +{ + esxVI_ObjectContent_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->obj); + esxVI_DynamicProperty_Free(&item->propSet); + /*esxVI_MissingProperty_Free(&item->missingSet);*//* FIXME */ +}); + +/* esxVI_ObjectContent_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(ObjectContent); + +int +esxVI_ObjectContent_DeepCopy(virConnectPtr conn, + esxVI_ObjectContent **dest, + esxVI_ObjectContent *src) +{ + if (dest == NULL || *dest != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (src == NULL) { + return 0; + } + + if (esxVI_ObjectContent_Alloc(conn, dest) < 0 || + esxVI_ManagedObjectReference_DeepCopy(conn, &(*dest)->obj, + src->obj) < 0 || + esxVI_DynamicProperty_DeepCopyList(conn, &(*dest)->propSet, + src->propSet) < 0) { + goto failure; + } + +#if 0 /* FIXME */ + if (esxVI_MissingProperty_DeepCopyList(&(*dest)->missingSet, + src->missingSet) < 0) { + goto failure; + } +#endif + + return 0; + + failure: + esxVI_ObjectContent_Free(dest); + + return -1; +} + +/* esxVI_ObjectContent_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(ObjectContent, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + NULL, obj); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(DynamicProperty, propSet); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(missingSet); /* FIXME */ +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(obj); +}); + +/* esxVI_ObjectContent_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(ObjectContent); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectUpdate + */ + +/* esxVI_ObjectUpdate_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ObjectUpdate); + +/* esxVI_ObjectUpdate_Free */ +ESX_VI__TEMPLATE__FREE(ObjectUpdate, +{ + esxVI_ObjectUpdate_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->obj); + esxVI_PropertyChange_Free(&item->changeSet); + /*esxVI_MissingProperty_Free(&item->missingSet);*//* FIXME */ +}); + +/* esxVI_ObjectUpdate_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(ObjectUpdate); + +/* esxVI_ObjectUpdate_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(ObjectUpdate, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(ObjectUpdateKind, kind); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + NULL, obj); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(PropertyChange, changeSet); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(missingSet); /* FIXME */ +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(kind); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(obj); +}); + +/* esxVI_ObjectUpdate_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(ObjectUpdate); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyFilterUpdate + */ + +/* esxVI_PropertyFilterUpdate_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PropertyFilterUpdate); + +/* esxVI_PropertyFilterUpdate_Free */ +ESX_VI__TEMPLATE__FREE(PropertyFilterUpdate, +{ + esxVI_PropertyFilterUpdate_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->filter); + esxVI_ObjectUpdate_Free(&item->objectSet); + /*esxVI_MissingProperty_Free(&item->missingSet);*//* FIXME */ +}); + +/* esxVI_PropertyFilterUpdate_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PropertyFilterUpdate); + +/* esxVI_PropertyFilterUpdate_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PropertyFilterUpdate, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + NULL, filter); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(ObjectUpdate, objectSet); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(missingSet); /* FIXME */ +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(filter); +}); + +/* esxVI_PropertyFilterUpdate_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PropertyFilterUpdate); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: AboutInfo + */ + +/* esxVI_AboutInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(AboutInfo); + +/* esxVI_AboutInfo_Free */ +ESX_VI__TEMPLATE__FREE(AboutInfo, +{ + VIR_FREE(item->name); + VIR_FREE(item->fullName); + VIR_FREE(item->vendor); + VIR_FREE(item->version); + VIR_FREE(item->build); + VIR_FREE(item->localeVersion); + VIR_FREE(item->localeBuild); + VIR_FREE(item->osType); + VIR_FREE(item->productLineId); + VIR_FREE(item->apiType); + VIR_FREE(item->apiVersion); +}); + +/* esxVI_AboutInfo_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(AboutInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, name); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, fullName); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, vendor); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, version); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, build); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, localeVersion); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, localeBuild); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, osType); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, productLineId); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, apiType); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, apiVersion); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(name); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(fullName); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(vendor); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(version); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(build); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(localeVersion); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(localeBuild); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(osType); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(productLineId); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(apiType); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(apiVersion); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ServiceContent + */ + +/* esxVI_ServiceContent_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ServiceContent); + +/* esxVI_ServiceContent_Free */ +ESX_VI__TEMPLATE__FREE(ServiceContent, +{ + esxVI_ManagedObjectReference_Free(&item->rootFolder); + esxVI_ManagedObjectReference_Free(&item->propertyCollector); + esxVI_ManagedObjectReference_Free(&item->viewManager); + esxVI_AboutInfo_Free(&item->about); + esxVI_ManagedObjectReference_Free(&item->setting); + esxVI_ManagedObjectReference_Free(&item->userDirectory); + esxVI_ManagedObjectReference_Free(&item->sessionManager); + esxVI_ManagedObjectReference_Free(&item->authorizationManager); + esxVI_ManagedObjectReference_Free(&item->perfManager); + esxVI_ManagedObjectReference_Free(&item->scheduledTaskManager); + esxVI_ManagedObjectReference_Free(&item->alarmManager); + esxVI_ManagedObjectReference_Free(&item->eventManager); + esxVI_ManagedObjectReference_Free(&item->taskManager); + esxVI_ManagedObjectReference_Free(&item->extensionManager); + esxVI_ManagedObjectReference_Free(&item->customizationSpecManager); + esxVI_ManagedObjectReference_Free(&item->customFieldsManager); + esxVI_ManagedObjectReference_Free(&item->accountManager); + esxVI_ManagedObjectReference_Free(&item->diagnosticManager); + esxVI_ManagedObjectReference_Free(&item->licenseManager); + esxVI_ManagedObjectReference_Free(&item->searchIndex); + esxVI_ManagedObjectReference_Free(&item->fileManager); + esxVI_ManagedObjectReference_Free(&item->virtualDiskManager); + esxVI_ManagedObjectReference_Free(&item->virtualizationManager); +}); + +/* esxVI_ServiceContent_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(ServiceContent, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "Folder", rootFolder); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "PropertyCollector", + propertyCollector); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "ViewManager", + viewManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(AboutInfo, about); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "OptionManager", setting); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "UserDirectory", + userDirectory); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "SessionManager", + sessionManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "AuthorizationManager", + authorizationManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "PerformanceManager", + perfManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "ScheduledTaskManager", + scheduledTaskManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "AlarmManager", + alarmManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "EventManager", + eventManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "TaskManager", + taskManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "ExtensionManager", + extensionManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "CustomizationSpecManager", + customizationSpecManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "CustomFieldsManager", + customFieldsManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "HostLocalAccountManager", + accountManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "DiagnosticManager", + diagnosticManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "LicenseManager", + licenseManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "SearchIndex", + searchIndex); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "FileManager", + fileManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "VirtualDiskManager", + virtualDiskManager); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + "VirtualizationManager", + virtualizationManager); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(rootFolder); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(propertyCollector); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(about); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: UpdateSet + */ + +/* esxVI_UpdateSet_Alloc */ +ESX_VI__TEMPLATE__ALLOC(UpdateSet); + +/* esxVI_UpdateSet_Free */ +ESX_VI__TEMPLATE__FREE(UpdateSet, +{ + VIR_FREE(item->version); + esxVI_PropertyFilterUpdate_Free(&item->filterSet); +}); + +/* esxVI_UpdateSet_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(UpdateSet, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, version); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(PropertyFilterUpdate, + filterSet); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(version); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: SharesInfo + */ + +/* esxVI_SharesInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(SharesInfo); + +/* esxVI_SharesInfo_Free */ +ESX_VI__TEMPLATE__FREE(SharesInfo, +{ + esxVI_Int_Free(&item->shares); +}); + +/* esxVI_SharesInfo_CastFromAnyType */ +ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(SharesInfo); + +/* esxVI_SharesInfo_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(SharesInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, shares); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(SharesLevel, level); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(shares); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(level); +}); + +/* esxVI_SharesInfo_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(SharesInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Int, shares, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(SharesLevel, level, True); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ResourceAllocationInfo + */ + +/* esxVI_ResourceAllocationInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ResourceAllocationInfo); + +/* esxVI_ResourceAllocationInfo_Free */ +ESX_VI__TEMPLATE__FREE(ResourceAllocationInfo, +{ + esxVI_Long_Free(&item->reservation); + esxVI_Long_Free(&item->limit); + esxVI_SharesInfo_Free(&item->shares); + esxVI_Long_Free(&item->overheadLimit); +}); + +/* esxVI_ResourceAllocationInfo_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(ResourceAllocationInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Long, reservation, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Boolean, expandableReservation, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Long, limit, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(SharesInfo, shares, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Long, overheadLimit, False); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: VirtualMachineConfigSpec + */ + +/* esxVI_VirtualMachineConfigSpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(VirtualMachineConfigSpec); + +/* esxVI_VirtualMachineConfigSpec_Free */ +ESX_VI__TEMPLATE__FREE(VirtualMachineConfigSpec, +{ + VIR_FREE(item->changeVersion); + VIR_FREE(item->name); + VIR_FREE(item->version); + VIR_FREE(item->uuid); + esxVI_Long_Free(&item->npivNodeWorldWideName); + esxVI_Long_Free(&item->npivPortWorldWideName); + VIR_FREE(item->npivWorldWideNameType); + VIR_FREE(item->npivWorldWideNameOp); + VIR_FREE(item->locationId); + VIR_FREE(item->guestId); + VIR_FREE(item->alternateGuestName); + VIR_FREE(item->annotation); + /* FIXME: implement missing */ + esxVI_Int_Free(&item->numCPUs); + esxVI_Long_Free(&item->memoryMB); + /* FIXME: implement missing */ + esxVI_ResourceAllocationInfo_Free(&item->cpuAllocation); + esxVI_ResourceAllocationInfo_Free(&item->memoryAllocation); + /* FIXME: implement missing */ + VIR_FREE(item->swapPlacement); + /* FIXME: implement missing */ +}); + +/* esxVI_VirtualMachineConfigSpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(VirtualMachineConfigSpec, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, changeVersion, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, name, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, version, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, uuid, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(Long, npivNodeWorldWideName, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(Long, npivPortWorldWideName, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, npivWorldWideNameType, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, npivWorldWideNameOp, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, locationId, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, guestId, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, alternateGuestName, + False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, annotation, False); + /* FIXME: implement missing */ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Int, numCPUs, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Long, memoryMB, False); + /* FIXME: implement missing */ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(ResourceAllocationInfo, + cpuAllocation, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(ResourceAllocationInfo, + memoryAllocation, False); + /* FIXME: implement missing */ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, swapPlacement, False); + /* FIXME: implement missing */ +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: Event + */ + +/* esxVI_Event_Alloc */ +ESX_VI__TEMPLATE__ALLOC(Event); + +/* esxVI_Event_Free */ +ESX_VI__TEMPLATE__FREE(Event, +{ + esxVI_Event_Free(&item->_next); + + /* FIXME: implement the rest */ + esxVI_Int_Free(&item->key); + esxVI_Int_Free(&item->chainId); + esxVI_DateTime_Free(&item->createdTime); + VIR_FREE(item->userName); + VIR_FREE(item->fullFormattedMessage); +}); + +/* esxVI_Event_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(Event, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, key); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, chainId); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, createdTime); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, userName); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(datacenter); /* FIXME */ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(computeResource); /* FIXME */ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(host); /* FIXME */ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(vm); /* FIXME */ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, fullFormattedMessage); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(key); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(chainId); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(createdTime); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(userName); +}); + +/* esxVI_Event_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(Event); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: UserSession + */ + +/* esxVI_UserSession_Alloc */ +ESX_VI__TEMPLATE__ALLOC(UserSession); + +/* esxVI_UserSession_Free */ +ESX_VI__TEMPLATE__FREE(UserSession, +{ + VIR_FREE(item->key); + VIR_FREE(item->userName); + VIR_FREE(item->fullName); + esxVI_DateTime_Free(&item->loginTime); + esxVI_DateTime_Free(&item->lastActiveTime); + VIR_FREE(item->locale); + VIR_FREE(item->messageLocale); +}); + +/* esxVI_UserSession_CastFromAnyType */ +ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(UserSession); + +/* esxVI_UserSession_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(UserSession, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, key); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, userName); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, fullName); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, loginTime); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, lastActiveTime); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, locale); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, messageLocale); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(key); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(userName); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(fullName); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(loginTime); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(lastActiveTime); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(locale); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(messageLocale); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ElementDescription extends Description + * + * In contrast to SelectionSpec and TraversalSpec just merge + * Description into ElementDescription for simplicity, because + * only ElementDescription is used. + */ + +/* esxVI_ElementDescription_Alloc */ +ESX_VI__TEMPLATE__ALLOC(ElementDescription); + +/* esxVI_ElementDescription_Free */ +ESX_VI__TEMPLATE__FREE(ElementDescription, +{ + esxVI_ElementDescription_Free(&item->_next); + + VIR_FREE(item->label); + VIR_FREE(item->summary); + VIR_FREE(item->key); +}); + +/* esxVI_ElementDescription_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(ElementDescription, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, label); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, summary); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, key); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(label); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(summary); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(key); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfMetricId + */ + +/* esxVI_PerfMetricId_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfMetricId); + +/* esxVI_PerfMetricId_Free */ +ESX_VI__TEMPLATE__FREE(PerfMetricId, +{ + esxVI_PerfMetricId_Free(&item->_next); + + esxVI_Int_Free(&item->counterId); + VIR_FREE(item->instance); +}); + +/* esxVI_PerfMetricId_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(PerfMetricId, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Int, counterId, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, instance, True); +}); + +/* esxVI_PerfMetricId_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(PerfMetricId); + +/* esxVI_PerfMetricId_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PerfMetricId, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, counterId); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, instance); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(counterId); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(instance); +}); + +/* esxVI_PerfMetricId_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PerfMetricId); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfCounterInfo + */ + +/* esxVI_PerfCounterInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfCounterInfo); + +/* esxVI_PerfCounterInfo_Free */ +ESX_VI__TEMPLATE__FREE(PerfCounterInfo, +{ + esxVI_PerfCounterInfo_Free(&item->_next); + + esxVI_Int_Free(&item->key); + esxVI_ElementDescription_Free(&item->nameInfo); + esxVI_ElementDescription_Free(&item->groupInfo); + esxVI_ElementDescription_Free(&item->unitInfo); + esxVI_Int_Free(&item->level); + esxVI_Int_Free(&item->associatedCounterId); +}); + +/* esxVI_PerfCounterInfo_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PerfCounterInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, key); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(ElementDescription, nameInfo); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(ElementDescription, groupInfo); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(ElementDescription, unitInfo); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(PerfSummaryType, rollupType); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(PerfStatsType, statsType); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, level); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(Int, associatedCounterId); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(key); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(nameInfo); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(groupInfo); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(unitInfo); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(rollupType); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(statsType); +}); + +/* esxVI_PerfCounterInfo_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PerfCounterInfo); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfQuerySpec + */ + +/* esxVI_PerfQuerySpec_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfQuerySpec); + +/* esxVI_PerfQuerySpec_Free */ +ESX_VI__TEMPLATE__FREE(PerfQuerySpec, +{ + esxVI_PerfQuerySpec_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->entity); + esxVI_DateTime_Free(&item->startTime); + esxVI_DateTime_Free(&item->endTime); + esxVI_Int_Free(&item->maxSample); + esxVI_PerfMetricId_Free(&item->metricId); + esxVI_Int_Free(&item->intervalId); + VIR_FREE(item->format); +}); + +/* esxVI_PerfQuerySpec_Serialize */ +ESX_VI__TEMPLATE__SERIALIZE(PerfQuerySpec, +{ + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(ManagedObjectReference, entity, True); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(DateTime, startTime, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(DateTime, endTime, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Int, maxSample, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(PerfMetricId, metricId, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(Int, intervalId, False); + ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, format, False); +}); + +/* esxVI_PerfQuerySpec_SerializeList */ +ESX_VI__TEMPLATE__LIST__SERIALIZE(PerfQuerySpec); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfSampleInfo + */ + +/* esxVI_PerfSampleInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfSampleInfo); + +/* esxVI_PerfSampleInfo_Free */ +ESX_VI__TEMPLATE__FREE(PerfSampleInfo, +{ + esxVI_PerfSampleInfo_Free(&item->_next); + + esxVI_DateTime_Free(&item->timestamp); + esxVI_Int_Free(&item->interval); +}); + +/* esxVI_PerfSampleInfo_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PerfSampleInfo); + +/* esxVI_PerfSampleInfo_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PerfSampleInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, timestamp); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, interval); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(timestamp); + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(interval); +}); + +/* esxVI_PerfSampleInfo_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PerfSampleInfo); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfMetricIntSeries extends PerfMetricSeries + * + * In contrast to SelectionSpec and TraversalSpec just merge + * PerfMetricSeries into PerfMetricIntSeries for simplicity, because + * only PerfMetricIntSeries is used and the other type inheriting + * PerfMetricSeries (PerfMetricSeriesCSV) is not used. + */ + +/* esxVI_PerfMetricIntSeries_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfMetricIntSeries); + +/* esxVI_PerfMetricIntSeries_Free */ +ESX_VI__TEMPLATE__FREE(PerfMetricIntSeries, +{ + esxVI_PerfMetricIntSeries_Free(&item->_next); + + esxVI_PerfMetricId_Free(&item->id); + esxVI_Long_Free(&item->value); +}); + +/* esxVI_PerfMetricIntSeries_AppendToList */ +ESX_VI__TEMPLATE__LIST__APPEND(PerfMetricIntSeries); + +/* esxVI_PerfMetricIntSeries_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PerfMetricIntSeries, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(PerfMetricId, id); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(Long, value); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(id); +}); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfEntityMetric extends PerfEntityMetricBase + * + * In contrast to SelectionSpec and TraversalSpec just merge + * PerfEntityMetricBase into PerfEntityMetric for simplicity, because + * only PerfEntityMetric is used and the other type inheriting + * PerfEntityMetric (PerfEntityMetricCSV) is not used. + * + * Also use PerfMetricIntSeries instead of the correct base type + * PerfMetricSeries for the value property, because only + * PerfMetricIntSeries is used. + */ + +/* esxVI_PerfEntityMetric_Alloc */ +ESX_VI__TEMPLATE__ALLOC(PerfEntityMetric); + +/* esxVI_PerfEntityMetric_Free */ +ESX_VI__TEMPLATE__FREE(PerfEntityMetric, +{ + esxVI_PerfEntityMetric_Free(&item->_next); + + esxVI_ManagedObjectReference_Free(&item->entity); + esxVI_PerfSampleInfo_Free(&item->sampleInfo); + esxVI_PerfMetricIntSeries_Free(&item->value); +}); + +/* esxVI_PerfEntityMetric_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(PerfEntityMetric, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference, + NULL, entity); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(PerfSampleInfo, sampleInfo); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(PerfMetricIntSeries, value); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(entity); +}); + +/* esxVI_PerfEntityMetric_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(PerfEntityMetric); diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h new file mode 100644 index 0000000..84d657d --- /dev/null +++ b/src/esx/esx_vi_types.h @@ -0,0 +1,1195 @@ + +/* + * esx_vi_types.h: client for the VMware VI API 2.5 to manage ESX hosts + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_VI_TYPES_H__ +#define __ESX_VI_TYPES_H__ + +#include "buf.h" + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSI + */ + +typedef enum _esxVI_Type esxVI_Type; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD + */ + +typedef enum _esxVI_Boolean esxVI_Boolean; +typedef struct _esxVI_AnyType esxVI_AnyType; +typedef struct _esxVI_String esxVI_String; +typedef struct _esxVI_Int esxVI_Int; +typedef struct _esxVI_Long esxVI_Long; +typedef struct _esxVI_DateTime esxVI_DateTime; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enums + */ + +typedef enum _esxVI_ObjectUpdateKind esxVI_ObjectUpdateKind; +typedef enum _esxVI_PerfSummaryType esxVI_PerfSummaryType; +typedef enum _esxVI_PerfStatsType esxVI_PerfStatsType; +typedef enum _esxVI_PropertyChangeOp esxVI_PropertyChangeOp; +typedef enum _esxVI_SharesLevel esxVI_SharesLevel; +typedef enum _esxVI_TaskInfoState esxVI_TaskInfoState; +typedef enum _esxVI_VirtualMachineMovePriority esxVI_VirtualMachineMovePriority; +typedef enum _esxVI_VirtualMachinePowerState esxVI_VirtualMachinePowerState; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Types + */ + +typedef struct _esxVI_Fault esxVI_Fault; +typedef struct _esxVI_ManagedObjectReference esxVI_ManagedObjectReference; +typedef struct _esxVI_DynamicProperty esxVI_DynamicProperty; +typedef struct _esxVI_SelectionSpec esxVI_SelectionSpec; +typedef struct _esxVI_TraversalSpec esxVI_TraversalSpec; +typedef struct _esxVI_ObjectSpec esxVI_ObjectSpec; +typedef struct _esxVI_PropertyChange esxVI_PropertyChange; +typedef struct _esxVI_PropertySpec esxVI_PropertySpec; +typedef struct _esxVI_PropertyFilterSpec esxVI_PropertyFilterSpec; +typedef struct _esxVI_ObjectContent esxVI_ObjectContent; +typedef struct _esxVI_ObjectUpdate esxVI_ObjectUpdate; +typedef struct _esxVI_PropertyFilterUpdate esxVI_PropertyFilterUpdate; +typedef struct _esxVI_AboutInfo esxVI_AboutInfo; +typedef struct _esxVI_ServiceContent esxVI_ServiceContent; +typedef struct _esxVI_UpdateSet esxVI_UpdateSet; +typedef struct _esxVI_SharesInfo esxVI_SharesInfo; +typedef struct _esxVI_ResourceAllocationInfo esxVI_ResourceAllocationInfo; +typedef struct _esxVI_VirtualMachineConfigSpec esxVI_VirtualMachineConfigSpec; +typedef struct _esxVI_Event esxVI_Event; +typedef struct _esxVI_UserSession esxVI_UserSession; +typedef struct _esxVI_ElementDescription esxVI_ElementDescription; +typedef struct _esxVI_PerfMetricId esxVI_PerfMetricId; +typedef struct _esxVI_PerfCounterInfo esxVI_PerfCounterInfo; +typedef struct _esxVI_PerfQuerySpec esxVI_PerfQuerySpec; +typedef struct _esxVI_PerfSampleInfo esxVI_PerfSampleInfo; +typedef struct _esxVI_PerfMetricIntSeries esxVI_PerfMetricIntSeries; +typedef struct _esxVI_PerfEntityMetric esxVI_PerfEntityMetric; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSI: Type + */ + +enum _esxVI_Type { + esxVI_Type_Undefined = 0, + esxVI_Type_Boolean, + esxVI_Type_String, + esxVI_Type_Short, + esxVI_Type_Int, + esxVI_Type_Long, + esxVI_Type_Other, +}; + +const char *esxVI_Type_Name(esxVI_Type type); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Boolean + */ + +enum _esxVI_Boolean { + esxVI_Boolean_Undefined = 0, + esxVI_Boolean_True, + esxVI_Boolean_False, +}; + +int esxVI_Boolean_Serialize(virConnectPtr conn, esxVI_Boolean boolean, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_Boolean_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_Boolean *boolean); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: AnyType + */ + +struct _esxVI_AnyType { + xmlNodePtr _node; /* required */ + + esxVI_Type type; /* required */ + char *other; /* required */ + char *value; /* required */ + union { + esxVI_Boolean boolean; /* optional */ + char *string; /* optional */ + int16_t int16; /* optional */ + int32_t int32; /* optional */ + int64_t int64; /* optional */ + }; +}; + +int esxVI_AnyType_Alloc(virConnectPtr conn, esxVI_AnyType **anyType); +void esxVI_AnyType_Free(esxVI_AnyType **anyType); +int esxVI_AnyType_ExpectType(virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_Type type); +int esxVI_AnyType_DeepCopy(virConnectPtr conn, esxVI_AnyType **dest, + esxVI_AnyType *src); +int esxVI_AnyType_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_AnyType **anyType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: String + */ + +struct _esxVI_String { + esxVI_String *_next; /* optional */ + + char *value; /* required */ +}; + +int esxVI_String_Alloc(virConnectPtr conn, esxVI_String **string); +void esxVI_String_Free(esxVI_String **stringList); +int esxVI_String_AppendToList(virConnectPtr conn, esxVI_String **stringList, + esxVI_String *string); +int esxVI_String_AppendValueToList(virConnectPtr conn, + esxVI_String **stringList, + const char *value); +int esxVI_String_AppendValueListToList(virConnectPtr conn, + esxVI_String **stringList, + const char *valueList); +int esxVI_String_DeepCopy(virConnectPtr conn, esxVI_String **dest, + esxVI_String *src); +int esxVI_String_DeepCopyList(virConnectPtr conn, esxVI_String **destList, + esxVI_String *srcList); +int esxVI_String_DeepCopyValue(virConnectPtr conn, char **dest, + const char *src); +int esxVI_String_Serialize(virConnectPtr conn, esxVI_String *string, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_String_SerializeList(virConnectPtr conn, esxVI_String *stringList, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_String_SerializeValue(virConnectPtr conn, const char *value, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_String_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_String **string); +int esxVI_String_DeserializeList(virConnectPtr conn, xmlNodePtr node, + esxVI_String **stringList); +int esxVI_String_DeserializeValue(virConnectPtr conn, xmlNodePtr node, + char **value); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Int + */ + +struct _esxVI_Int { + esxVI_Int *_next; /* optional */ + + int32_t value; /* required */ +}; + +int esxVI_Int_Alloc(virConnectPtr conn, esxVI_Int **number); +void esxVI_Int_Free(esxVI_Int **numberList); +int esxVI_Int_AppendToList(virConnectPtr conn, esxVI_Int **numberList, + esxVI_Int *number); +int esxVI_Int_DeepCopy(virConnectPtr conn, esxVI_Int **dest, esxVI_Int *src); +int esxVI_Int_Serialize(virConnectPtr conn, esxVI_Int *number, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_Int_SerializeList(virConnectPtr conn, esxVI_Int *numberList, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_Int_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_Int **number); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: Long + */ + +struct _esxVI_Long { + esxVI_Long *_next; /* optional */ + + int64_t value; /* required */ +}; + +int esxVI_Long_Alloc(virConnectPtr conn, esxVI_Long **number); +void esxVI_Long_Free(esxVI_Long **numberList); +int esxVI_Long_AppendToList(virConnectPtr conn, esxVI_Long **numberList, + esxVI_Long *number); +int esxVI_Long_Serialize(virConnectPtr conn, esxVI_Long *number, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_Long_SerializeList(virConnectPtr conn, esxVI_Long *numberList, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_Long_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_Long **number); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * XSD: DateTime + */ + +struct _esxVI_DateTime { + char *value; /* required */ +}; + +int esxVI_DateTime_Alloc(virConnectPtr conn, esxVI_DateTime **dateTime); +void esxVI_DateTime_Free(esxVI_DateTime **dateTime); +int esxVI_DateTime_Serialize(virConnectPtr conn, esxVI_DateTime *dateTime, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_DateTime_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_DateTime **dateTime); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: ObjectUpdateKind + */ + +enum _esxVI_ObjectUpdateKind { + esxVI_ObjectUpdateKind_Undefined = 0, + esxVI_ObjectUpdateKind_Enter, + esxVI_ObjectUpdateKind_Leave, + esxVI_ObjectUpdateKind_Modify, +}; + +int esxVI_ObjectUpdateKind_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_ObjectUpdateKind *objectUpdateKind); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PerfSummaryType + */ + +enum _esxVI_PerfSummaryType { + esxVI_PerfSummaryType_Undefined = 0, + esxVI_PerfSummaryType_Average, + esxVI_PerfSummaryType_Latest, + esxVI_PerfSummaryType_Maximum, + esxVI_PerfSummaryType_Minimum, + esxVI_PerfSummaryType_None, + esxVI_PerfSummaryType_Summation, +}; + +int esxVI_PerfSummaryType_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfSummaryType *perfSummaryType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PerfStatsType + */ + +enum _esxVI_PerfStatsType { + esxVI_PerfStatsType_Undefined = 0, + esxVI_PerfStatsType_Absolute, + esxVI_PerfStatsType_Delta, + esxVI_PerfStatsType_Rate, +}; + +int esxVI_PerfStatsType_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfStatsType *perfStatsType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: PropertyChangeOp + */ + +enum _esxVI_PropertyChangeOp { + esxVI_PropertyChangeOp_Undefined = 0, + esxVI_PropertyChangeOp_Add, + esxVI_PropertyChangeOp_Remove, + esxVI_PropertyChangeOp_Assign, + esxVI_PropertyChangeOp_IndirectRemove, +}; + +int esxVI_PropertyChangeOp_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_PropertyChangeOp *propertyChangeOp); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: SharesLevel + */ + +enum _esxVI_SharesLevel { + esxVI_SharesLevel_Undefined = 0, + esxVI_SharesLevel_Custom, + esxVI_SharesLevel_High, + esxVI_SharesLevel_Low, + esxVI_SharesLevel_Normal, +}; + +int esxVI_SharesLevel_Serialize(virConnectPtr conn, + esxVI_SharesLevel sharesLevel, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_SharesLevel_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_SharesLevel *sharesLevel); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: TaskInfoState + */ + +enum _esxVI_TaskInfoState { + esxVI_TaskInfoState_Undefined = 0, + esxVI_TaskInfoState_Error, + esxVI_TaskInfoState_Queued, + esxVI_TaskInfoState_Running, + esxVI_TaskInfoState_Success, +}; + +int esxVI_TaskInfoState_CastFromAnyType(virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_TaskInfoState *taskInfoState); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: VirtualMachineMovePriority + */ + +enum _esxVI_VirtualMachineMovePriority { + esxVI_VirtualMachineMovePriority_Undefined = 0, + esxVI_VirtualMachineMovePriority_LowPriority, + esxVI_VirtualMachineMovePriority_HighPriority, + esxVI_VirtualMachineMovePriority_DefaultPriority, +}; + +int esxVI_VirtualMachineMovePriority_Serialize + (virConnectPtr conn, + esxVI_VirtualMachineMovePriority virtualMachineMovePriority, + const char *element, virBufferPtr output, esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Enum: VirtualMachinePowerState + */ + +enum _esxVI_VirtualMachinePowerState { + esxVI_VirtualMachinePowerState_Undefined = 0, + esxVI_VirtualMachinePowerState_PoweredOff, + esxVI_VirtualMachinePowerState_PoweredOn, + esxVI_VirtualMachinePowerState_Suspended, +}; + +int esxVI_VirtualMachinePowerState_CastFromAnyType + (virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_VirtualMachinePowerState *virtualMachinePowerState); +int esxVI_VirtualMachinePowerState_Serialize + (virConnectPtr conn, + esxVI_VirtualMachinePowerState virtualMachinePowerState, + const char *element, virBufferPtr output, esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: Fault + */ + +struct _esxVI_Fault { + char *faultcode; /* required */ + char *faultstring; /* required */ +}; + +int esxVI_Fault_Alloc(virConnectPtr conn, esxVI_Fault **fault); +void esxVI_Fault_Free(esxVI_Fault **fault); +int esxVI_Fault_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_Fault **fault); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ManagedObjectReference + */ + +struct _esxVI_ManagedObjectReference { + esxVI_ManagedObjectReference *_next; /* optional */ + + char *type; /* required */ + char *value; /* required */ +}; + +int esxVI_ManagedObjectReference_Alloc + (virConnectPtr conn, + esxVI_ManagedObjectReference **managedObjectReference); +void esxVI_ManagedObjectReference_Free + (esxVI_ManagedObjectReference **managedObjectReferenceList); +int esxVI_ManagedObjectReference_DeepCopy(virConnectPtr conn, + esxVI_ManagedObjectReference **dest, + esxVI_ManagedObjectReference *src); +int esxVI_ManagedObjectReference_CastFromAnyType(virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_ManagedObjectReference + **managedObjectReference, + const char *expectedType); +int esxVI_ManagedObjectReference_Serialize + (virConnectPtr conn, + esxVI_ManagedObjectReference *managedObjectReference, + const char *element, virBufferPtr output, esxVI_Boolean required); +int esxVI_ManagedObjectReference_SerializeList + (virConnectPtr conn, + esxVI_ManagedObjectReference *managedObjectReference, + const char *element, virBufferPtr output, esxVI_Boolean required); +int esxVI_ManagedObjectReference_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_ManagedObjectReference **managedObjectReference, + const char *expectedType); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: DynamicProperty + */ + +struct _esxVI_DynamicProperty { + esxVI_DynamicProperty *_next; /* optional */ + + char *name; /* required */ + esxVI_AnyType *val; /* required */ +}; + +int esxVI_DynamicProperty_Alloc(virConnectPtr conn, + esxVI_DynamicProperty **dynamicProperty); +void esxVI_DynamicProperty_Free + (esxVI_DynamicProperty **dynamicPropertyList); +int esxVI_DynamicProperty_DeepCopy(virConnectPtr conn, + esxVI_DynamicProperty **dest, + esxVI_DynamicProperty *src); +int esxVI_DynamicProperty_DeepCopyList(virConnectPtr conn, + esxVI_DynamicProperty **destList, + esxVI_DynamicProperty *srcList); +int esxVI_DynamicProperty_AppendToList + (virConnectPtr conn, esxVI_DynamicProperty **dynamicPropertyList, + esxVI_DynamicProperty *dynamicProperty); +int esxVI_DynamicProperty_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_DynamicProperty **dynamicProperty); +int esxVI_DynamicProperty_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_DynamicProperty **dynamicProperty); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: SelectionSpec + */ + +struct _esxVI_SelectionSpec { + esxVI_SelectionSpec *_next; /* optional */ + esxVI_TraversalSpec *_super; /* optional */ + + char *name; /* optional */ +}; + +int esxVI_SelectionSpec_Alloc(virConnectPtr conn, + esxVI_SelectionSpec **selectionSpec); +void esxVI_SelectionSpec_Free(esxVI_SelectionSpec **selectionSpecList); +int esxVI_SelectionSpec_AppendToList(virConnectPtr conn, + esxVI_SelectionSpec **selectionSpecList, + esxVI_SelectionSpec *selectionSpec); +int esxVI_SelectionSpec_Serialize(virConnectPtr conn, + esxVI_SelectionSpec *selectionSpec, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_SelectionSpec_SerializeList(virConnectPtr conn, + esxVI_SelectionSpec *selectionSpecList, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: TraversalSpec extends SelectionSpec + */ + +struct _esxVI_TraversalSpec { + esxVI_SelectionSpec *_base; /* required */ + + char *type; /* required */ + char *path; /* required */ + esxVI_Boolean skip; /* optional */ + esxVI_SelectionSpec *selectSet; /* optional, list */ +}; + +int esxVI_TraversalSpec_Alloc(virConnectPtr conn, + esxVI_TraversalSpec **traversalSpec); +void esxVI_TraversalSpec_Free(esxVI_TraversalSpec **traversalSpec); +int esxVI_TraversalSpec_Serialize(virConnectPtr conn, + esxVI_TraversalSpec *traversalSpec, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectSpec + */ + +struct _esxVI_ObjectSpec { + esxVI_ObjectSpec *_next; /* optional */ + + esxVI_ManagedObjectReference *obj; /* required */ + esxVI_Boolean skip; /* optional */ + esxVI_SelectionSpec *selectSet; /* optional, list */ +}; + +int esxVI_ObjectSpec_Alloc(virConnectPtr conn, esxVI_ObjectSpec **objectSpec); +void esxVI_ObjectSpec_Free(esxVI_ObjectSpec **objectSpecList); +int esxVI_ObjectSpec_AppendToList(virConnectPtr conn, + esxVI_ObjectSpec **objectSpecList, + esxVI_ObjectSpec *objectSpec); +int esxVI_ObjectSpec_Serialize(virConnectPtr conn, + esxVI_ObjectSpec *objectSpec, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_ObjectSpec_SerializeList(virConnectPtr conn, + esxVI_ObjectSpec *objectSpecList, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyChange + */ + +struct _esxVI_PropertyChange { + esxVI_PropertyChange *_next; /* optional */ + + char *name; /* required */ + esxVI_PropertyChangeOp op; /* required */ + esxVI_AnyType *val; /* optional */ +}; + +int esxVI_PropertyChange_Alloc(virConnectPtr conn, + esxVI_PropertyChange **propertyChange); +void esxVI_PropertyChange_Free(esxVI_PropertyChange **propertyChangeList); +int esxVI_PropertyChange_AppendToList + (virConnectPtr conn, esxVI_PropertyChange **propertyChangeList, + esxVI_PropertyChange *propertyChange); +int esxVI_PropertyChange_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PropertyChange **propertyChange); +int esxVI_PropertyChange_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_PropertyChange **propertyChange); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertySpec + */ + +struct _esxVI_PropertySpec { + esxVI_PropertySpec *_next; /* optional */ + + char *type; /* required */ + esxVI_Boolean all; /* optional */ + esxVI_String *pathSet; /* optional, list */ +}; + +int esxVI_PropertySpec_Alloc(virConnectPtr conn, + esxVI_PropertySpec **propertySpec); +void esxVI_PropertySpec_Free(esxVI_PropertySpec **propertySpecList); +int esxVI_PropertySpec_AppendToList(virConnectPtr conn, + esxVI_PropertySpec **propertySpecList, + esxVI_PropertySpec *propertySpec); +int esxVI_PropertySpec_Serialize(virConnectPtr conn, + esxVI_PropertySpec *propertySpec, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_PropertySpec_SerializeList(virConnectPtr conn, + esxVI_PropertySpec *propertySpecList, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyFilterSpec + */ + +struct _esxVI_PropertyFilterSpec { + esxVI_PropertyFilterSpec *_next; /* optional */ + + esxVI_PropertySpec *propSet; /* required, list */ + esxVI_ObjectSpec *objectSet; /* required, list */ +}; + +int esxVI_PropertyFilterSpec_Alloc + (virConnectPtr conn, esxVI_PropertyFilterSpec **propertyFilterSpec); +void esxVI_PropertyFilterSpec_Free + (esxVI_PropertyFilterSpec **propertyFilterSpecList); +int esxVI_PropertyFilterSpec_AppendToList + (virConnectPtr conn, esxVI_PropertyFilterSpec **propertyFilterSpecList, + esxVI_PropertyFilterSpec *propertyFilterSpec); +int esxVI_PropertyFilterSpec_Serialize + (virConnectPtr conn, esxVI_PropertyFilterSpec *propertyFilterSpec, + const char *element, virBufferPtr output, esxVI_Boolean required); +int esxVI_PropertyFilterSpec_SerializeList + (virConnectPtr conn, esxVI_PropertyFilterSpec *propertyFilterSpecList, + const char *element, virBufferPtr output, esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectContent + */ + +struct _esxVI_ObjectContent { + esxVI_ObjectContent *_next; /* optional */ + + esxVI_ManagedObjectReference *obj; /* required */ + esxVI_DynamicProperty *propSet; /* optional, list */ + /*esxVI_MissingProperty *missingSet; *//* optional, list *//* FIXME */ +}; + +int esxVI_ObjectContent_Alloc(virConnectPtr conn, + esxVI_ObjectContent **objectContent); +void esxVI_ObjectContent_Free(esxVI_ObjectContent **objectContentList); +int esxVI_ObjectContent_AppendToList(virConnectPtr conn, + esxVI_ObjectContent **objectContentList, + esxVI_ObjectContent *objectContent); +int esxVI_ObjectContent_DeepCopy(virConnectPtr conn, + esxVI_ObjectContent **dest, + esxVI_ObjectContent *src); +int esxVI_ObjectContent_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_ObjectContent **objectContent); +int esxVI_ObjectContent_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_ObjectContent **objectContentList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ObjectUpdate + */ + +struct _esxVI_ObjectUpdate { + esxVI_ObjectUpdate *_next; /* optional */ + + esxVI_ObjectUpdateKind kind; /* required */ + esxVI_ManagedObjectReference *obj; /* required */ + esxVI_PropertyChange *changeSet; /* optional, list */ + /*esxVI_MissingProperty *missingSet; *//* optional, list *//* FIXME */ +}; + +int esxVI_ObjectUpdate_Alloc(virConnectPtr conn, + esxVI_ObjectUpdate **objectUpdate); +void esxVI_ObjectUpdate_Free(esxVI_ObjectUpdate **objectUpdateList); +int esxVI_ObjectUpdate_AppendToList(virConnectPtr conn, + esxVI_ObjectUpdate **objectUpdateList, + esxVI_ObjectUpdate *objectUpdate); +int esxVI_ObjectUpdate_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_ObjectUpdate **objectUpdate); +int esxVI_ObjectUpdate_DeserializeList(virConnectPtr conn, xmlNodePtr node, + esxVI_ObjectUpdate **objectUpdateList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PropertyFilterUpdate + */ + +struct _esxVI_PropertyFilterUpdate { + esxVI_PropertyFilterUpdate *_next; /* optional */ + + esxVI_ManagedObjectReference *filter; /* required */ + esxVI_ObjectUpdate *objectSet; /* optional, list */ + /*esxVI_MissingProperty *missingSet; *//* optional, list *//* FIXME */ +}; + +int esxVI_PropertyFilterUpdate_Alloc + (virConnectPtr conn, + esxVI_PropertyFilterUpdate **propertyFilterUpdate); +void esxVI_PropertyFilterUpdate_Free + (esxVI_PropertyFilterUpdate **propertyFilterUpdateList); +int esxVI_PropertyFilterUpdate_AppendToList + (virConnectPtr conn, + esxVI_PropertyFilterUpdate **propertyFilterUpdateList, + esxVI_PropertyFilterUpdate *propertyFilterUpdate); +int esxVI_PropertyFilterUpdate_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_PropertyFilterUpdate **propertyFilterUpdate); +int esxVI_PropertyFilterUpdate_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_PropertyFilterUpdate **propertyFilterUpdateList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: AboutInfo + */ + +struct _esxVI_AboutInfo { + char *name; /* required */ + char *fullName; /* required */ + char *vendor; /* required */ + char *version; /* required */ + char *build; /* required */ + char *localeVersion; /* optional */ + char *localeBuild; /* optional */ + char *osType; /* required */ + char *productLineId; /* required */ + char *apiType; /* required */ + char *apiVersion; /* required */ +}; + +int esxVI_AboutInfo_Alloc(virConnectPtr conn, esxVI_AboutInfo **aboutInfo); +void esxVI_AboutInfo_Free(esxVI_AboutInfo **aboutInfo); +int esxVI_AboutInfo_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_AboutInfo **aboutInfo); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ServiceContent + */ + +struct _esxVI_ServiceContent { + esxVI_ManagedObjectReference *rootFolder; /* required */ + esxVI_ManagedObjectReference *propertyCollector; /* required */ + esxVI_ManagedObjectReference *viewManager; /* optional */ + esxVI_AboutInfo *about; /* required */ + esxVI_ManagedObjectReference *setting; /* optional */ + esxVI_ManagedObjectReference *userDirectory; /* optional */ + esxVI_ManagedObjectReference *sessionManager; /* optional */ + esxVI_ManagedObjectReference *authorizationManager; /* optional */ + esxVI_ManagedObjectReference *perfManager; /* optional */ + esxVI_ManagedObjectReference *scheduledTaskManager; /* optional */ + esxVI_ManagedObjectReference *alarmManager; /* optional */ + esxVI_ManagedObjectReference *eventManager; /* optional */ + esxVI_ManagedObjectReference *taskManager; /* optional */ + esxVI_ManagedObjectReference *extensionManager; /* optional */ + esxVI_ManagedObjectReference *customizationSpecManager; /* optional */ + esxVI_ManagedObjectReference *customFieldsManager; /* optional */ + esxVI_ManagedObjectReference *accountManager; /* optional */ + esxVI_ManagedObjectReference *diagnosticManager; /* optional */ + esxVI_ManagedObjectReference *licenseManager; /* optional */ + esxVI_ManagedObjectReference *searchIndex; /* optional */ + esxVI_ManagedObjectReference *fileManager; /* optional */ + esxVI_ManagedObjectReference *virtualDiskManager; /* optional */ + esxVI_ManagedObjectReference *virtualizationManager; /* optional */ +}; + +int esxVI_ServiceContent_Alloc(virConnectPtr conn, + esxVI_ServiceContent **serviceContent); +void esxVI_ServiceContent_Free(esxVI_ServiceContent **serviceContent); +int esxVI_ServiceContent_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_ServiceContent **serviceContent); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: UpdateSet + */ + +struct _esxVI_UpdateSet { + char *version; /* required */ + esxVI_PropertyFilterUpdate *filterSet; /* optional, list */ +}; + +int esxVI_UpdateSet_Alloc(virConnectPtr conn, esxVI_UpdateSet **updateSet); +void esxVI_UpdateSet_Free(esxVI_UpdateSet **updateSet); +int esxVI_UpdateSet_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_UpdateSet **updateSet); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: SharesInfo + */ + +struct _esxVI_SharesInfo { + esxVI_Int *shares; /* required */ + esxVI_SharesLevel level; /* required */ +}; + +int esxVI_SharesInfo_Alloc(virConnectPtr conn, esxVI_SharesInfo **sharesInfo); +void esxVI_SharesInfo_Free(esxVI_SharesInfo **sharesInfo); +int esxVI_SharesInfo_CastFromAnyType(virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_SharesInfo **sharesInfo); +int esxVI_SharesInfo_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_SharesInfo **sharesInfo); +int esxVI_SharesInfo_Serialize(virConnectPtr conn, + esxVI_SharesInfo *sharesInfo, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ResourceAllocationInfo + */ + +struct _esxVI_ResourceAllocationInfo { + esxVI_Long *reservation; /* optional */ + esxVI_Boolean expandableReservation; /* optional */ + esxVI_Long *limit; /* optional */ + esxVI_SharesInfo *shares; /* optional */ + esxVI_Long *overheadLimit; /* optional */ +}; + +int esxVI_ResourceAllocationInfo_Alloc + (virConnectPtr conn, + esxVI_ResourceAllocationInfo **resourceAllocationInfo); +void esxVI_ResourceAllocationInfo_Free + (esxVI_ResourceAllocationInfo **resourceAllocationInfo); +int esxVI_ResourceAllocationInfo_Serialize + (virConnectPtr conn, esxVI_ResourceAllocationInfo *resourceAllocationInfo, + const char *element, virBufferPtr output, esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: VirtualMachineConfigSpec + */ + +/* FIXME: implement the rest */ +struct _esxVI_VirtualMachineConfigSpec { + char *changeVersion; /* optional */ + char *name; /* optional */ + char *version; /* optional */ + char *uuid; /* optional */ + esxVI_Long *npivNodeWorldWideName; /* optional, list */ + esxVI_Long *npivPortWorldWideName; /* optional, list */ + char *npivWorldWideNameType; /* optional */ + char *npivWorldWideNameOp; /* optional */ + char *locationId; /* optional */ + char *guestId; /* optional */ + char *alternateGuestName; /* optional */ + char *annotation; /* optional */ + //esxVI_VirtualMachineFileInfo *files; /* optional */ + //esxVI_ToolsConfigInfo *tools; /* optional */ + //esxVI_VirtualMachineFlagInfo *flags; /* optional */ + //esxVI_VirtualMachineConsolePreferences *consolePreferences; /* optional */ + //esxVI_VirtualMachineDefaultPowerOpInfo *powerOpInfo; /* optional */ + esxVI_Int *numCPUs; /* optional */ + esxVI_Long *memoryMB; /* optional */ + //esxVI_VirtualDeviceConfigSpec *deviceChange; /* optional, list */ + esxVI_ResourceAllocationInfo *cpuAllocation; /* optional */ + esxVI_ResourceAllocationInfo *memoryAllocation; /* optional */ + //esxVI_VirtualMachineAffinityInfo *cpuAffinity; /* optional */ + //esxVI_VirtualMachineAffinityInfo *memoryAffinity; /* optional */ + //esxVI_VirtualMachineNetworkShaperInfo *networkShaper; /* optional */ + //esxVI_VirtualMachineCpuIdInfoSpec *cpuFeatureMask; /* optional, list */ + //esxVI_OptionValue *extraConfig; /* optional, list */ + char *swapPlacement; /* optional */ + //esxVI_VirtualMachineBootOptions *bootOptions; /* optional */ +}; + +int esxVI_VirtualMachineConfigSpec_Alloc + (virConnectPtr conn, + esxVI_VirtualMachineConfigSpec **virtualMachineConfigSpec); +void esxVI_VirtualMachineConfigSpec_Free + (esxVI_VirtualMachineConfigSpec **virtualMachineConfigSpec); +int esxVI_VirtualMachineConfigSpec_Serialize + (virConnectPtr conn, + esxVI_VirtualMachineConfigSpec *virtualMachineConfigSpec, + const char *element, virBufferPtr output, esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: Event + */ + +/* FIXME: implement the rest */ +struct _esxVI_Event { + esxVI_Event *_next; /* optional */ + + esxVI_Int *key; /* required */ + esxVI_Int *chainId; /* required */ + esxVI_DateTime *createdTime; /* required */ + char *userName; /* required */ + //??? datacenter; /* optional */ + //??? computeResource; /* optional */ + //??? host; /* optional */ + //??? vm; /* optional */ + char *fullFormattedMessage; /* optional */ +}; + +int esxVI_Event_Alloc(virConnectPtr conn, esxVI_Event **event); +void esxVI_Event_Free(esxVI_Event **eventList); +int esxVI_Event_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_Event **event); +int esxVI_Event_DeserializeList(virConnectPtr conn, xmlNodePtr node, + esxVI_Event **eventList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: UserSession + */ + +struct _esxVI_UserSession { + char *key; /* required */ + char *userName; /* required */ + char *fullName; /* required */ + esxVI_DateTime *loginTime; /* required */ + esxVI_DateTime *lastActiveTime; /* required */ + char *locale; /* required */ + char *messageLocale; /* required */ +}; + +int esxVI_UserSession_Alloc(virConnectPtr conn, + esxVI_UserSession **userSession); +void esxVI_UserSession_Free(esxVI_UserSession **userSession); +int esxVI_UserSession_CastFromAnyType(virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_UserSession **userSession); +int esxVI_UserSession_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_UserSession **userSession); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: ElementDescription extends Description + * + * In contrast to SelectionSpec and TraversalSpec just merge + * Description into ElementDescription for simplicity, because + * only ElementDescription is used. + */ + +struct _esxVI_ElementDescription { + esxVI_ElementDescription *_next; /* optional */ + + /* Description */ + char *label; /* required */ + char *summary; /* required */ + + /* ElementDescription */ + char *key; /* required */ +}; + +int esxVI_ElementDescription_Alloc + (virConnectPtr conn, esxVI_ElementDescription **elementDescription); +void esxVI_ElementDescription_Free + (esxVI_ElementDescription **elementDescription); +int esxVI_ElementDescription_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_ElementDescription **elementDescription); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfMetricId + */ + +struct _esxVI_PerfMetricId { + esxVI_PerfMetricId *_next; /* optional */ + + esxVI_Int *counterId; /* required */ + char *instance; /* required */ +}; + +int esxVI_PerfMetricId_Alloc(virConnectPtr conn, + esxVI_PerfMetricId **perfMetricId); +void esxVI_PerfMetricId_Free(esxVI_PerfMetricId **perfMetricId); +int esxVI_PerfMetricId_Serialize(virConnectPtr conn, + esxVI_PerfMetricId *perfMetricId, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_PerfMetricId_SerializeList(virConnectPtr conn, + esxVI_PerfMetricId *perfMetricIdList, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_PerfMetricId_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfMetricId **perfMetricId); +int esxVI_PerfMetricId_DeserializeList(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfMetricId **perfMetricIdList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfCounterInfo + */ + +struct _esxVI_PerfCounterInfo { + esxVI_PerfCounterInfo *_next; /* optional */ + + esxVI_Int *key; /* required */ + esxVI_ElementDescription *nameInfo; /* required */ + esxVI_ElementDescription *groupInfo; /* required */ + esxVI_ElementDescription *unitInfo; /* required */ + esxVI_PerfSummaryType rollupType; /* required */ + esxVI_PerfStatsType statsType; /* required */ + esxVI_Int *level; /* optional */ + esxVI_Int *associatedCounterId; /* optional, list */ +}; + +int esxVI_PerfCounterInfo_Alloc(virConnectPtr conn, + esxVI_PerfCounterInfo **perfCounterInfo); +void esxVI_PerfCounterInfo_Free(esxVI_PerfCounterInfo **perfCounterInfo); +int esxVI_PerfCounterInfo_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfCounterInfo **perfCounterInfo); +int esxVI_PerfCounterInfo_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_PerfCounterInfo **perfCounterInfoList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfQuerySpec + */ + +struct _esxVI_PerfQuerySpec { + esxVI_PerfQuerySpec *_next; /* optional */ + + esxVI_ManagedObjectReference* entity; /* required */ + esxVI_DateTime* startTime; /* optional */ + esxVI_DateTime* endTime; /* optional */ + esxVI_Int *maxSample; /* optional */ + esxVI_PerfMetricId *metricId; /* optional, list */ + esxVI_Int *intervalId; /* optional */ + char* format; /* optional */ // FIXME: see PerfFormat +}; + +int esxVI_PerfQuerySpec_Alloc(virConnectPtr conn, + esxVI_PerfQuerySpec **perfQuerySpec); +void esxVI_PerfQuerySpec_Free(esxVI_PerfQuerySpec **perfQuerySpec); +int esxVI_PerfQuerySpec_Serialize(virConnectPtr conn, + esxVI_PerfQuerySpec *perfQuerySpec, + const char *element, virBufferPtr output, + esxVI_Boolean required); +int esxVI_PerfQuerySpec_SerializeList(virConnectPtr conn, + esxVI_PerfQuerySpec *perfQuerySpecList, + const char *element, virBufferPtr output, + esxVI_Boolean required); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfSampleInfo + */ + +struct _esxVI_PerfSampleInfo { + esxVI_PerfSampleInfo *_next; /* optional */ + + esxVI_DateTime* timestamp; /* required */ + esxVI_Int* interval; /* required */ +}; + +int esxVI_PerfSampleInfo_Alloc(virConnectPtr conn, + esxVI_PerfSampleInfo **perfSampleInfo); +void esxVI_PerfSampleInfo_Free(esxVI_PerfSampleInfo **perfSampleInfo); +int esxVI_PerfSampleInfo_AppendToList(virConnectPtr conn, + esxVI_PerfSampleInfo **perfSampleInfoList, + esxVI_PerfSampleInfo *perfSampleInfo); +int esxVI_PerfSampleInfo_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_PerfSampleInfo **perfSampleInfo); +int esxVI_PerfSampleInfo_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_PerfSampleInfo **perfSampleInfoList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfMetricIntSeries extends PerfMetricSeries + * + * In contrast to SelectionSpec and TraversalSpec just merge + * PerfMetricSeries into PerfMetricIntSeries for simplicity, because + * only PerfMetricIntSeries is used and the other type inheriting + * PerfMetricSeries (PerfMetricSeriesCSV) is not used. + */ + +struct _esxVI_PerfMetricIntSeries { + esxVI_PerfMetricIntSeries *_next; /* optional */ + + /* PerfMetricSeries */ + esxVI_PerfMetricId *id; /* required */ + + /* PerfMetricIntSeries */ + esxVI_Long *value; /* optional, list */ +}; + +int esxVI_PerfMetricIntSeries_Alloc + (virConnectPtr conn, esxVI_PerfMetricIntSeries **perfMetricIntSeries); +void esxVI_PerfMetricIntSeries_Free + (esxVI_PerfMetricIntSeries **perfMetricIntSeries); +int esxVI_PerfMetricIntSeries_AppendToList + (virConnectPtr conn, esxVI_PerfMetricIntSeries **perfMetricIntSeriesList, + esxVI_PerfMetricIntSeries *perfMetricIntSeries); +int esxVI_PerfMetricIntSeries_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_PerfMetricIntSeries **perfMetricIntSeries); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: PerfEntityMetric extends PerfEntityMetricBase + * + * In contrast to SelectionSpec and TraversalSpec just merge + * PerfEntityMetricBase into PerfEntityMetric for simplicity, because + * only PerfEntityMetric is used and the other type inheriting + * PerfEntityMetric (PerfEntityMetricCSV) is not used. + * + * Also use PerfMetricIntSeries instead of the correct base type + * PerfMetricSeries for the value property, because only + * PerfMetricIntSeries is used. + */ + +struct _esxVI_PerfEntityMetric { + esxVI_PerfEntityMetric *_next; /* optional */ + + /* PerfEntityMetricBase */ + esxVI_ManagedObjectReference *entity; /* required */ + + /* PerfEntityMetric */ + esxVI_PerfSampleInfo *sampleInfo; /* optional, list */ + esxVI_PerfMetricIntSeries *value; /* optional, list */ +}; + +int esxVI_PerfEntityMetric_Alloc(virConnectPtr conn, + esxVI_PerfEntityMetric **perfEntityMetric); +void esxVI_PerfEntityMetric_Free + (esxVI_PerfEntityMetric **perfEntityMetric); +int esxVI_PerfEntityMetric_Deserialize + (virConnectPtr conn, xmlNodePtr node, + esxVI_PerfEntityMetric **perfEntityMetric); +int esxVI_PerfEntityMetric_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_PerfEntityMetric **perfEntityMetricList); + +#endif /* __ESX_VI_TYPES_H__ */ diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c new file mode 100644 index 0000000..635a483 --- /dev/null +++ b/src/esx/esx_vmx.c @@ -0,0 +1,1666 @@ + +/* + * esx_vmx.c: VMX related methods for the VMware ESX driver + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "virterror_internal.h" +#include "memory.h" +#include "logging.h" +#include "esx_util.h" +#include "esx_vmx.h" + +/* + +mapping: + +domain-xml <=> vmx + + + config.version = "8" # essential + virtualHW.version = "4" # essential + + +??? <=> guestOS = "<value>" # essential, FIXME: not representable +def->id = <value> <=> ??? # not representable +def->uuid = <value> <=> uuid.bios = "<value>" +def->name = <value> <=> displayName = "<value>" +def->maxmem = <value kilobyte> <=> memsize = "<value megabyte>" # must be a multiple of 4, defaults to 32 +def->memory = <value kilobyte> <=> sched.mem.max = "<value megabyte>" # defaults to "unlimited" -> def->memory = def->maxmem +def->vcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1 +def->cpumask = <uint list> <=> sched.cpu.affinity = "<uint list>" + + + +################################################################################ +## os ########################################################################## + +def->os + +->type = "hvm" +->arch +->machine +->nBootDevs +->bootDevs +->init +->kernel +->initrd +->cmdline +->root +->loader +->bootloader +->bootloaderArgs + + + +################################################################################ +## disks ####################################################################### + + scsi[0..3]:[0..6,8..15] -> <controller>:<id> + ide[0..1]:[0..1] -> <controller>:<id> + floppy[0..1] -> <controller> + +def->disks[0]... + +## disks: scsi hard drive from .vmdk image ##################################### + + scsi0.present = "true" # defaults to "false" + scsi0:0.present = "true" # defaults to "false" + scsi0:0.startConnected = "true" # defaults to "true" + +??? <=> scsi0:0.mode = "persistent" # defaults to "persistent" + scsi0:0.mode = "undoable" + scsi0:0.mode = "independent-persistent" + scsi0:0.mode = "independent-nonpersistent" + +... +->type = _DISK_TYPE_FILE <=> scsi0:0.deviceType = "scsi-hardDisk" # defaults to ? +->device = _DISK_DEVICE_DISK <=> scsi0:0.deviceType = "scsi-hardDisk" # defaults to ? +->bus = _DISK_BUS_SCSI +->src = <value>.vmdk <=> scsi0:0.fileName = "<value>.vmdk" +->dst = sd[<controller> * 16 + <id> mapped to [a-z]+] +->driverName = <driver> <=> scsi0.virtualDev = "<driver>" # default depends on guestOS value +->driverType +->cachemode <=> scsi0:0.writeThrough = "<value>" # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT +->readonly +->shared +->slotnum + + +## disks: ide hard drive from .vmdk image ###################################### + + ide0.present = "true" # defaults to "false" + ide0:0.present = "true" # defaults to "false" + ide0:0.startConnected = "true" # defaults to "true" + +??? <=> ide0:0.mode = "persistent" # defaults to "persistent" + ide0:0.mode = "undoable" + ide0:0.mode = "independent-persistent" + ide0:0.mode = "independent-nonpersistent" + +... +->type = _DISK_TYPE_FILE <=> ide0:0.deviceType = "ata-hardDisk" # defaults to ? +->device = _DISK_DEVICE_DISK <=> ide0:0.deviceType = "ata-hardDisk" # defaults to ? +->bus = _DISK_BUS_IDE +->src = <value>.vmdk <=> ide0:0.fileName = "<value>.vmdk" +->dst = hd[<controller> * 2 + <id> mapped to [a-z]+] +->driverName +->driverType +->cachemode <=> ide0:0.writeThrough = "<value>" # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT +->readonly +->shared +->slotnum + + +## disks: scsi cdrom from .iso image ########################################### + + scsi0.present = "true" # defaults to "false" + scsi0:0.present = "true" # defaults to "false" + scsi0:0.startConnected = "true" # defaults to "true" + +... +->type = _DISK_TYPE_FILE <=> scsi0:0.deviceType = "cdrom-image" # defaults to ? +->device = _DISK_DEVICE_CDROM <=> scsi0:0.deviceType = "cdrom-image" # defaults to ? +->bus = _DISK_BUS_SCSI +->src = <value>.iso <=> scsi0:0.fileName = "<value>.iso" +->dst = sd[<controller> * 16 + <id> mapped to [a-z]+] +->driverName = <driver> <=> scsi0.virtualDev = "<driver>" # default depends on guestOS value +->driverType +->cachemode +->readonly +->shared +->slotnum + + +## disks: ide cdrom from .iso image ############################################ + + ide0.present = "true" # defaults to "false" + ide0:0.present = "true" # defaults to "false" + ide0:0.startConnected = "true" # defaults to "true" + +... +->type = _DISK_TYPE_FILE <=> ide0:0.deviceType = "cdrom-image" # defaults to ? +->device = _DISK_DEVICE_CDROM <=> ide0:0.deviceType = "cdrom-image" # defaults to ? +->bus = _DISK_BUS_IDE +->src = <value>.iso <=> ide0:0.fileName = "<value>.iso" +->dst = hd[<controller> * 2 + <id> mapped to [a-z]+] +->driverName +->driverType +->cachemode +->readonly +->shared +->slotnum + + +## disks: scsi cdrom from host device ########################################## + + scsi0.present = "true" # defaults to "false" + scsi0:0.present = "true" # defaults to "false" + scsi0:0.startConnected = "true" # defaults to "true" + +... +->type = _DISK_TYPE_BLOCK <=> scsi0:0.deviceType = "atapi-cdrom" # defaults to ? +->device = _DISK_DEVICE_CDROM <=> scsi0:0.deviceType = "atapi-cdrom" # defaults to ? +->bus = _DISK_BUS_SCSI +->src = <value> <=> scsi0:0.fileName = "<value>" # e.g. "/dev/scd0" ? +->dst = sd[<controller> * 16 + <id> mapped to [a-z]+] +->driverName = <driver> <=> scsi0.virtualDev = "<driver>" # default depends on guestOS value +->driverType +->cachemode +->readonly +->shared +->slotnum + + +## disks: ide cdrom from host device ########################################### + + ide0.present = "true" # defaults to "false" + ide0:0.present = "true" # defaults to "false" + ide0:0.startConnected = "true" # defaults to "true" + ide0:0.clientDevice = "false" # defaults to "false" + +... +->type = _DISK_TYPE_BLOCK <=> ide0:0.deviceType = "atapi-cdrom" # defaults to ? +->device = _DISK_DEVICE_CDROM <=> ide0:0.deviceType = "atapi-cdrom" # defaults to ? +->bus = _DISK_BUS_IDE +->src = <value> <=> ide0:0.fileName = "<value>" # e.g. "/dev/scd0" +->dst = hd[<controller> * 2 + <id> mapped to [a-z]+] +->driverName +->driverType +->cachemode +->readonly +->shared +->slotnum + + +## disks: floppy from .flp image ############################################### + + floppy0.present = "true" # defaults to "false" + floppy0.startConnected = "true" # defaults to "true" + floppy0.clientDevice = "false" # defaults to "false" + +... +->type = _DISK_TYPE_FILE <=> floppy0.fileType = "file" # defaults to ? +->device = _DISK_DEVICE_FLOPPY +->bus = _DISK_BUS_FDC +->src = <value>.flp <=> floppy0.fileName = "<value>.flp" +->dst = fd[<controller> mapped to [a-z]+] +->driverName +->driverType +->cachemode +->readonly +->shared +->slotnum + + +## disks: floppy from host device ############################################## + + floppy0.present = "true" # defaults to "false" + floppy0.startConnected = "true" # defaults to "true" + floppy0.clientDevice = "false" # defaults to "false" + +... +->type = _DISK_TYPE_BLOCK <=> floppy0.fileType = "device" # defaults to ? +->device = _DISK_DEVICE_FLOPPY +->bus = _DISK_BUS_FDC +->src = <value> <=> floppy0.fileName = "<value>" # e.g. "/dev/fd0" +->dst = fd[<controller> mapped to [a-z]+] +->driverName +->driverType +->cachemode +->readonly +->shared +->slotnum + + + +################################################################################ +## nets ######################################################################## + + ethernet[0..3] -> <controller> + + ethernet0.present = "true" # defaults to "false" + ethernet0.startConnected = "true" # defaults to "true" + + ethernet0.networkName = "VM Network" # FIXME + +def->nets[0]... +->model = <model> <=> ethernet0.virtualDev = "<model>" # default depends on guestOS value + + + ethernet0.addressType = "generated" # default to "generated" + ethernet0.generatedAddressOffset = "0" # ? +->mac = <value> <=> ethernet0.generatedAddress = "<value>" + + + ethernet0.addressType = "static" # default to "generated" +->mac = <value> <=> ethernet0.address = "<value>" + + # 00:0c:29 prefix for autogenerated mac's + # 00:50:56 prefix for manual configured mac's + # 00:05:69 old prefix from esx 1.5 + + +## nets: bridged ############################################################### + +... +->type = _NET_TYPE_BRIDGE <=> ethernet0.connectionType = "bridged" # defaults to "bridged" + + +## nets: hostonly ############################################################## + +... # FIXME: maybe not supported by ESX? +->type = _NET_TYPE_NETWORK <=> ethernet0.connectionType = "hostonly" # defaults to "bridged" + + +## nets: nat ################################################################### + +... # FIXME: maybe not supported by ESX? +->type = _NET_TYPE_USER <=> ethernet0.connectionType = "nat" # defaults to "bridged" + + +## nets: custom ################################################################ + +... +->type = _NET_TYPE_BRIDGE <=> ethernet0.connectionType = "custom" # defaults to "bridged" +->data.bridge.brname = <value> <=> ethernet0.vnet = "<value>" + + + +################################################################################ +## serials ##################################################################### + + serial[0..3] -> <port> + + serial0.present = "true" # defaults to "false" + serial0.startConnected = "true" # defaults to "true" + +def->serials[0]... +->dstPort = <port> + + +## serials: device ############################################################# + +->type = _CHR_TYPE_DEV <=> serial0.fileType = "device" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "/dev/ttyS0" +??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable + + +## serials: file ############################################################### + +->type = _CHR_TYPE_FILE <=> serial0.fileType = "file" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.file" +??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable + + +## serials: pipe, far end -> app ############################################### + +->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" +??? <=> serial0.pipe.endPoint = "client" # defaults to "server", FIXME: not representable +??? <=> serial0.tryNoRxLoss = "true" # defaults to "false", FIXME: not representable + +->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" +??? <=> serial0.pipe.endPoint = "server" # defaults to "server", FIXME: not representable +??? <=> serial0.tryNoRxLoss = "true" # defaults to "false", FIXME: not representable + + +## serials: pipe, far end -> vm ################################################ + +->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" +??? <=> serial0.pipe.endPoint = "client" # defaults to "server", FIXME: not representable +??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable + +->type = _CHR_TYPE_PIPE <=> serial0.fileType = "pipe" +->data.file.path = <value> <=> serial0.fileName = "<value>" # e.g. "serial0.pipe" +??? <=> serial0.pipe.endPoint = "server" # defaults to "server", FIXME: not representable +??? <=> serial0.tryNoRxLoss = "false" # defaults to "false", FIXME: not representable + + + +################################################################################ +## parallels ################################################################### + + parallel[0..2] -> <port> + + parallel0.present = "true" # defaults to "false" + parallel0.startConnected = "true" # defaults to "true" + +def->parallels[0]... +->dstPort = <port> + + +## parallels: device ############################################################# + +->type = _CHR_TYPE_DEV <=> parallel0.fileType = "device" +->data.file.path = <value> <=> parallel0.fileName = "<value>" # e.g. "/dev/parport0" +??? <=> parallel0.bidirectional = "<value>" # defaults to ?, FIXME: not representable + + +## parallels: file ############################################################# + +->type = _CHR_TYPE_FILE <=> parallel0.fileType = "file" +->data.file.path = <value> <=> parallel0.fileName = "<value>" # e.g. "parallel0.file" +??? <=> parallel0.bidirectional = "<value>" # must be "false" for fileType = "file", FIXME: not representable + +*/ + +#define VIR_FROM_THIS VIR_FROM_ESX + +#define ESX_ERROR(conn, code, fmt...) \ + virReportErrorHelper (conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \ + __LINE__, fmt) + + + +#define ESX_BUILD_VMX_NAME(_suffix) \ + do { \ + strncpy(_suffix##_name, prefix, sizeof (_suffix##_name) - 1); \ + _suffix##_name[sizeof (_suffix##_name) - 1] = '\0'; \ + strncat(_suffix##_name, "."#_suffix, \ + sizeof (_suffix##_name) - 1 - strlen(_suffix##_name)); \ + } while (0) + + + +virDomainDefPtr +esxVMX_ParseConfig(virConnectPtr conn, const char *vmx) +{ + virConfPtr conf = NULL; + virDomainDefPtr def = NULL; + long long config_version = 0; + long long virtualHW_version = 0; + long long memsize = 0; + long long memory = 0; + long long numvcpus = 0; + char *sched_cpu_affinity = NULL; + int controller; + int port; + int present; + char *scsi_virtualDev = NULL; + int id; + + conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT); + + if (conf == NULL) { + return NULL; + } + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(conn); + goto failure; + } + + def->virtType = VIR_DOMAIN_VIRT_VMWARE; /* FIXME: maybe add VIR_DOMAIN_VIRT_ESX ? */ + def->id = -1; + + if (esxUtil_GetConfigLong(conn, conf, "config.version", + &config_version, 0, 0) < 0) { + goto failure; + } + + if (config_version != 8) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'config.version' to be \"8\" but " + "found \"%lld\"", config_version); + goto failure; + } + + if (esxUtil_GetConfigLong(conn, conf, "virtualHW.version", + &virtualHW_version, 0, 0) < 0) { + goto failure; + } + + if (virtualHW_version != 4) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'virtualHW.version' to be \"4\" but " + "found \"%lld\"", virtualHW_version); + goto failure; + } + + /* def:uuid */ + /* FIXME: Need to handle 'uuid.action = "create"' */ + if (esxUtil_GetConfigUUID(conn, conf, "uuid.bios", def->uuid, 1) < 0) { + goto failure; + } + + /* def:name */ + if (esxUtil_GetConfigString(conn, conf, "displayName", + &def->name, 1) < 0) { + goto failure; + } + + /* def:maxmem */ + if (esxUtil_GetConfigLong(conn, conf, "memsize", &memsize, 32, 1) < 0) { + goto failure; + } + + if (memsize <= 0 || memsize % 4 != 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'memsize' to be an unsigned " + "integer (multiple of 4) but found %lld", memsize); + goto failure; + } + + def->maxmem = memsize * 1024; /* Scale from megabytes to kilobytes */ + + /* def:memory */ + if (esxUtil_GetConfigLong(conn, conf, "sched.mem.max", &memory, + memsize, 1) < 0) { + goto failure; + } + + if (memory < 0) { + memory = memsize; + } + + def->memory = memory * 1024; /* Scale from megabytes to kilobytes */ + + if (def->memory > def->maxmem) { + def->memory = def->maxmem; + } + + /* def:vcpus */ + if (esxUtil_GetConfigLong(conn, conf, "numvcpus", &numvcpus, 1, 1) < 0) { + goto failure; + } + + if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'numvcpus' to be an unsigned " + "integer (1 or a multiple of 2) but found %lld", numvcpus); + goto failure; + } + + def->vcpus = numvcpus; + + /* def:cpumask */ + // VirtualMachine:config.cpuAffinity.affinitySet + if (esxUtil_GetConfigString(conn, conf, "sched.cpu.affinity", + &sched_cpu_affinity, 1) < 0) { + goto failure; + } + + if (sched_cpu_affinity != NULL && STRNEQ(sched_cpu_affinity, "all")) { + const char *current = sched_cpu_affinity; + int number, count = 0; + + def->cpumasklen = 0; + + if (VIR_ALLOC_N(def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) { + virReportOOMError(conn); + goto failure; + } + + while (*current != '\0') { + virSkipSpaces(¤t); + + number = virParseNumber(¤t); + + if (number < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'sched.cpu.affinity' to be " + "a comma separated list of unsigned integers but " + "found '%s'", sched_cpu_affinity); + goto failure; + } + + if (number >= VIR_DOMAIN_CPUMASK_LEN) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "VMX entry 'sched.cpu.affinity' contains a %d, this " + "value is too large", number); + goto failure; + } + + if (number + 1 > def->cpumasklen) { + def->cpumasklen = number + 1; + } + + def->cpumask[number] = 1; + ++count; + + virSkipSpaces(¤t); + + if (*current == ',') { + ++current; + } else if (*current == '\0') { + break; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'sched.cpu.affinity' to be " + "a comma separated list of unsigned integers but " + "found '%s'", sched_cpu_affinity); + goto failure; + } + + virSkipSpaces(¤t); + } + + if (count < numvcpus) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry 'sched.cpu.affinity' to contain " + "at least as many values as 'numvcpus' (%lld) but " + "found only %d value(s)", numvcpus, count); + goto failure; + } + } + + /* def:lifecycle */ + def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; + def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; + def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; + + /* def:os */ + def->os.type = strdup("hvm"); + + if (def->os.type == NULL) { + virReportOOMError(conn); + goto failure; + } + +/* + def->emulator + def->features*/ + +/* + def->localtime*/ + + /* def:graphics */ + /* FIXME */ + + /* def:disks: 4 * 16 scsi + 2 * 2 ide + 2 floppy = 70 */ + if (VIR_ALLOC_N(def->disks, 72) < 0) { + virReportOOMError(conn); + goto failure; + } + + def->ndisks = 0; + + /* def:disks (scsi) */ + for (controller = 0; controller < 4; ++controller) { + VIR_FREE(scsi_virtualDev); + + if (esxVMX_ParseSCSIController(conn, conf, controller, + &present, &scsi_virtualDev) < 0) { + goto failure; + } + + if (! present) { + continue; + } + + for (id = 0; id < 16; ++id) { + if (id == 7) { + /* + * SCSI ID 7 is assigned to the SCSI controller and cannot be + * used for disk devices. + */ + continue; + } + + if (esxVMX_ParseDisk(conn, conf, VIR_DOMAIN_DISK_DEVICE_DISK, + VIR_DOMAIN_DISK_BUS_SCSI, controller, id, + scsi_virtualDev, + &def->disks[def->ndisks]) < 0) { + goto failure; + } + + if (def->disks[def->ndisks] != NULL) { + ++def->ndisks; + continue; + } + + if (esxVMX_ParseDisk(conn, conf, VIR_DOMAIN_DISK_DEVICE_CDROM, + VIR_DOMAIN_DISK_BUS_SCSI, controller, id, + scsi_virtualDev, + &def->disks[def->ndisks]) < 0) { + goto failure; + } + + if (def->disks[def->ndisks] != NULL) { + ++def->ndisks; + } + } + } + + /* def:disks (ide) */ + for (controller = 0; controller < 2; ++controller) { + for (id = 0; id < 2; ++id) { + if (esxVMX_ParseDisk(conn, conf, VIR_DOMAIN_DISK_DEVICE_DISK, + VIR_DOMAIN_DISK_BUS_IDE, controller, id, + NULL, &def->disks[def->ndisks]) < 0) { + goto failure; + } + + if (def->disks[def->ndisks] != NULL) { + ++def->ndisks; + continue; + } + + if (esxVMX_ParseDisk(conn, conf, VIR_DOMAIN_DISK_DEVICE_CDROM, + VIR_DOMAIN_DISK_BUS_IDE, controller, id, + NULL, &def->disks[def->ndisks]) < 0) { + goto failure; + } + + if (def->disks[def->ndisks] != NULL) { + ++def->ndisks; + } + } + } + + /* def:disks (floppy) */ + for (controller = 0; controller < 2; ++controller) { + if (esxVMX_ParseDisk(conn, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY, + VIR_DOMAIN_DISK_BUS_FDC, controller, -1, NULL, + &def->disks[def->ndisks]) < 0) { + goto failure; + } + + if (def->disks[def->ndisks] != NULL) { + ++def->ndisks; + } + } + + /* def:fss */ + /* FIXME */ + + /* def:nets */ + if (VIR_ALLOC_N(def->nets, 4) < 0) { + virReportOOMError(conn); + goto failure; + } + + def->nnets = 0; + + for (controller = 0; controller < 4; ++controller) { + if (esxVMX_ParseEthernet(conn, conf, controller, + &def->nets[def->nnets]) < 0) { + goto failure; + } + + if (def->nets[def->nnets] != NULL) { + ++def->nnets; + } + } + + /* def:inputs */ + /* FIXME */ + + /* def:sounds */ + /* FIXME */ + + /* def:hostdevs */ + /* FIXME */ + + /* def:serials */ + if (VIR_ALLOC_N(def->serials, 4) < 0) { + virReportOOMError(conn); + goto failure; + } + + def->nserials = 0; + + for (port = 0; port < 4; ++port) { + if (esxVMX_ParseSerial(conn, conf, port, + &def->serials[def->nserials]) < 0) { + goto failure; + } + + if (def->serials[def->nserials] != NULL) { + ++def->nserials; + } + } + + /* def:parallels */ + if (VIR_ALLOC_N(def->parallels, 3) < 0) { + virReportOOMError(conn); + goto failure; + } + + def->nparallels = 0; + + for (port = 0; port < 3; ++port) { + if (esxVMX_ParseParallel(conn, conf, port, + &def->parallels[def->nparallels]) < 0) { + goto failure; + } + + if (def->parallels[def->nparallels] != NULL) { + ++def->nparallels; + } + } + +cleanup: + virConfFree(conf); + VIR_FREE(sched_cpu_affinity); + VIR_FREE(scsi_virtualDev); + + return def; + +failure: + virDomainDefFree(def); + def = NULL; + + goto cleanup; +} + + + +int +esxVMX_ParseSCSIController(virConnectPtr conn, virConfPtr conf, int controller, + int *present, char **virtualDev) +{ + char present_name[32]; + char virtualDev_name[32]; + + if (virtualDev == NULL || *virtualDev != NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + if (controller < 0 || controller > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "SCSI controller index %d out of [0..3] range", + controller); + goto failure; + } + + strncpy(present_name, "scsiX.present", sizeof (virtualDev_name)); + strncpy(virtualDev_name, "scsiX.virtualDev", sizeof (virtualDev_name)); + + present_name[4] = '0' + controller; + virtualDev_name[4] = '0' + controller; + + if (esxUtil_GetConfigBoolean(conn, conf, present_name, present, 0, 1) < 0) { + goto failure; + } + + if (! *present) { + return 0; + } + + if (esxUtil_GetConfigString(conn, conf, virtualDev_name, + virtualDev, 0) < 0) { + goto failure; + } + + if (*virtualDev != NULL && + STRCASENEQ(*virtualDev, "buslogic") && + STRCASENEQ(*virtualDev, "lsilogic")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' " + "but found '%s'", virtualDev_name, *virtualDev); + goto failure; + } + + return 0; + +failure: + VIR_FREE(*virtualDev); + + return -1; +} + + + +char * +esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix) +{ + char buffer[32] = ""; + char *name = NULL; + size_t length = strlen(prefix); + + if (length > sizeof (buffer) - 2 - 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Disk name prefix '%s' is too long", prefix); + return NULL; + } + + strncpy(buffer, prefix, sizeof (buffer) - 1); + buffer[sizeof (buffer) - 1] = '\0'; + + if (idx < 26) { + buffer[length] = 'a' + idx; + } else if (idx < 702) { + buffer[length] = 'a' + idx / 26 - 1; + buffer[length + 1] = 'a' + idx % 26; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Disk index %d is too large", idx); + return NULL; + } + + name = strdup(buffer); + + if (name == NULL) { + virReportOOMError(conn); + return NULL; + } + + return name; +} + + + +/* +struct _virDomainDiskDef { + int type; // partly done + int device; // done + int bus; // done + char *src; // done + char *dst; // done + char *driverName; // done + char *driverType; + int cachemode; // done + unsigned int readonly : 1; + unsigned int shared : 1; + int slotnum; +};*/ + +int +esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, + int controller, int id, const char *virtualDev, + virDomainDiskDefPtr *def) +{ + /* + * device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM} + * bus = VIR_DOMAIN_DISK_BUS_SCSI + * controller = [0..3] + * id = [0..6,8..15] + * virtualDev = {'buslogic', 'lsilogic'} + * + * device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM} + * bus = VIR_DOMAIN_DISK_BUS_IDE + * controller = [0..1] + * id = [0..1] + * virtualDev = NULL + * + * device = VIR_DOMAIN_DISK_DEVICE_FLOPPY + * bus = VIR_DOMAIN_DISK_BUS_FDC + * controller = [0..1] + * id = -1 + * virtualDev = NULL + */ + + int result = 0; + char *prefix = NULL; + + char present_name[32] = ""; + int present = 0; + + char startConnected_name[32] = ""; + int startConnected = 0; + + char deviceType_name[32] = ""; + char *deviceType = NULL; + + char clientDevice_name[32] = ""; + int clientDevice = 0; + + char fileType_name[32] = ""; + char *fileType = NULL; + + char fileName_name[32] = ""; + char *fileName = NULL; + + char writeThrough_name[32] = ""; + int writeThrough = 0; + + if (def == NULL || *def != NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (VIR_ALLOC(*def) < 0) { + virReportOOMError(conn); + goto failure; + } + + (*def)->device = device; + (*def)->bus = bus; + + /* def:dst, def:driverName */ + if (device == VIR_DOMAIN_DISK_DEVICE_DISK || + device == VIR_DOMAIN_DISK_DEVICE_CDROM) { + if (bus == VIR_DOMAIN_DISK_BUS_SCSI) { + if (controller < 0 || controller > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "SCSI controller index %d out of [0..3] range", + controller); + goto failure; + } + + if (id < 0 || id > 15 || id == 7) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "SCSI ID %d out of [0..6,8..15] range", id); + goto failure; + } + + if (virAsprintf(&prefix, "scsi%d:%d", controller, id) < 0) { + virReportOOMError(conn); + goto failure; + } + + (*def)->dst = esxVMX_IndexToDiskName(conn, controller * 16 + id, + "sd"); + + if ((*def)->dst == NULL) { + goto failure; + } + + if (virtualDev != NULL) { + (*def)->driverName = strdup(virtualDev); + + if ((*def)->driverName == NULL) { + virReportOOMError(conn); + goto failure; + } + } + } else if (bus == VIR_DOMAIN_DISK_BUS_IDE) { + if (controller < 0 || controller > 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "IDE controller index %d out of [0..1] range", + controller); + goto failure; + } + + if (id < 0 || id > 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "IDE ID %d out of [0..1] range", id); + goto failure; + } + + if (virAsprintf(&prefix, "ide%d:%d", controller, id) < 0) { + virReportOOMError(conn); + goto failure; + } + + (*def)->dst = esxVMX_IndexToDiskName(conn, controller * 2 + id, + "hd"); + + if ((*def)->dst == NULL) { + goto failure; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported bus type '%s' for '%s' device type", + virDomainDiskBusTypeToString (bus), + virDomainDiskDeviceTypeToString (device)); + goto failure; + } + } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { + if (bus == VIR_DOMAIN_DISK_BUS_FDC) { + if (controller < 0 || controller > 1) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Floppy controller index %d out of [0..1] range", + controller); + goto failure; + } + + if (virAsprintf(&prefix, "floppy%d", controller) < 0) { + virReportOOMError(conn); + goto failure; + } + + (*def)->dst = esxVMX_IndexToDiskName(conn, controller, "fd"); + + if ((*def)->dst == NULL) { + goto failure; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported bus type '%s' for '%s' device type", + virDomainDiskBusTypeToString (bus), + virDomainDiskDeviceTypeToString (device)); + goto failure; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported device type '%s'", + virDomainDiskDeviceTypeToString (device)); + goto failure; + } + + ESX_BUILD_VMX_NAME(present); + ESX_BUILD_VMX_NAME(startConnected); + ESX_BUILD_VMX_NAME(deviceType); + ESX_BUILD_VMX_NAME(clientDevice); + ESX_BUILD_VMX_NAME(fileType); + ESX_BUILD_VMX_NAME(fileName); + ESX_BUILD_VMX_NAME(writeThrough); + + /* vmx:present */ + if (esxUtil_GetConfigBoolean(conn, conf, present_name, + &present, 0, 1) < 0) { + goto failure; + } + + /* vmx:startConnected */ + if (esxUtil_GetConfigBoolean(conn, conf, startConnected_name, + &startConnected, 1, 1) < 0) { + goto failure; + } + + /* FIXME: Need to distiguish between active and inactive domains here */ + if (! present/* && ! startConnected*/) { + goto ignore; + } + + /* vmx:deviceType -> def:type */ + if (esxUtil_GetConfigString(conn, conf, deviceType_name, + &deviceType, 1) < 0) { + goto failure; + } + + /* vmx:clientDevice */ + if (esxUtil_GetConfigBoolean(conn, conf, clientDevice_name, + &clientDevice, 0, 1) < 0) { + goto failure; + } + + if (clientDevice) { + /* + * Just ignore devices in client mode, because I have no clue how to + * handle them (e.g. assign an image) without the VI client GUI. + */ + goto ignore; + } + + /* vmx:fileType -> def:type */ + if (esxUtil_GetConfigString(conn, conf, fileType_name, &fileType, 1) < 0) { + goto failure; + } + + /* vmx:fileName -> def:src, def:type */ + if (esxUtil_GetConfigString(conn, conf, fileName_name, + &fileName, 0) < 0) { + goto failure; + } + + /* vmx:writeThrough -> def:cachemode */ + if (esxUtil_GetConfigBoolean(conn, conf, writeThrough_name, + &writeThrough, 0, 1) < 0) { + goto failure; + } + + /* Setup virDomainDiskDef */ + /* FIXME: Need the datastore name for fileName */ + if (device == VIR_DOMAIN_DISK_DEVICE_DISK) { + if (esxUtil_EqualSuffix(fileName, ".vmdk")) { + if (deviceType != NULL) { + if (bus == VIR_DOMAIN_DISK_BUS_SCSI && + STRCASENEQ(deviceType, "scsi-hardDisk")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'scsi-hardDisk' " + "but found '%s'", deviceType_name, deviceType); + goto failure; + } else if (bus == VIR_DOMAIN_DISK_BUS_IDE && + STRCASENEQ(deviceType, "ata-hardDisk")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'ata-hardDisk' " + "but found '%s'", deviceType_name, deviceType); + goto failure; + } + } + + (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE; + (*def)->src = fileName; + (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU + : VIR_DOMAIN_DISK_CACHE_DEFAULT; + + fileName = NULL; + } else if (esxUtil_EqualSuffix(fileName, ".iso") || + STREQ(deviceType, "atapi-cdrom")) { + /* + * This function was called in order to parse a harddisk device, + * but .iso files and 'atapi-cdrom' devices are for CDROM devices + * only. Just ignore it, another call to this function to parse a + * CDROM device may handle it. + */ + goto ignore; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Invalid or not yet handled value '%s' for VMX entry " + "'%s'", fileName, fileName_name); + goto failure; + } + } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) { + if (esxUtil_EqualSuffix(fileName, ".iso")) { + if (deviceType != NULL) { + if (STRCASENEQ(deviceType, "cdrom-image")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'cdrom-image' " + "but found '%s'", deviceType_name, deviceType); + goto failure; + } + } + + (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE; + (*def)->src = fileName; + + fileName = NULL; + } else if (esxUtil_EqualSuffix(fileName, ".vmdk")) { + /* + * This function was called in order to parse a CDROM device, but + * .vmdk files are for harddisk devices only. Just ignore it, + * another call to this function to parse a harddisk device may + * handle it. + */ + goto ignore; + } else if (STREQ(deviceType, "atapi-cdrom")) { + (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK; + (*def)->src = fileName; + + fileName = NULL; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Invalid or not yet handled value '%s' for VMX entry " + "'%s'", fileName, fileName_name); + goto failure; + } + } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { + if (esxUtil_EqualSuffix(fileName, ".flp")) { + if (fileType != NULL) { + if (STRCASENEQ(fileType, "file")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'file' but " + "found '%s'", fileType_name, fileType); + goto failure; + } + } + + (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE; + (*def)->src = fileName; + + fileName = NULL; + } else if (fileType != NULL && STREQ(fileType, "device")) { + (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK; + (*def)->src = fileName; + + fileName = NULL; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Invalid or not yet handled value '%s' for VMX entry " + "'%s'", fileName, fileName_name); + goto failure; + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Unsupported device type '%s'", + virDomainDiskDeviceTypeToString (device)); + goto failure; + } + +cleanup: + VIR_FREE(prefix); + VIR_FREE(deviceType); + VIR_FREE(fileType); + VIR_FREE(fileName); + + return result; + +failure: + result = -1; + +ignore: + virDomainDiskDefFree(*def); + *def = NULL; + + goto cleanup; +} + + + +int +esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, + virDomainNetDefPtr *def) +{ + int result = 0; + char prefix[48] = ""; + + char present_name[48] = ""; + int present = 0; + + char startConnected_name[48] = ""; + int startConnected = 0; + + char connectionType_name[48] = ""; + char *connectionType = NULL; + + char addressType_name[48] = ""; + char *addressType = NULL; + + char generatedAddress_name[48] = ""; + char *generatedAddress = NULL; + + char address_name[48] = ""; + char *address = NULL; + + char virtualDev_name[48] = ""; + char *virtualDev = NULL; + + char vnet_name[48] = ""; + char *vnet = NULL; + + if (def == NULL || *def != NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (controller < 0 || controller > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Ethernet controller index %d out of [0..3] range", + controller); + goto failure; + } + + if (VIR_ALLOC(*def) < 0) { + virReportOOMError(conn); + goto failure; + } + + strncpy(prefix, "ethernetX", sizeof (prefix)); + prefix[8] = '0' + controller; + + ESX_BUILD_VMX_NAME(present); + ESX_BUILD_VMX_NAME(startConnected); + ESX_BUILD_VMX_NAME(connectionType); + ESX_BUILD_VMX_NAME(addressType); + ESX_BUILD_VMX_NAME(generatedAddress); + ESX_BUILD_VMX_NAME(address); + ESX_BUILD_VMX_NAME(virtualDev); + + /* vmx:present */ + if (esxUtil_GetConfigBoolean(conn, conf, present_name, + &present, 0, 1) < 0) { + goto failure; + } + + /* vmx:startConnected */ + if (esxUtil_GetConfigBoolean(conn, conf, startConnected_name, + &startConnected, 1, 1) < 0) { + goto failure; + } + + /* FIXME: Need to distiguish between active and inactive domains here */ + if (! present/* && ! startConnected*/) { + goto ignore; + } + + /* vmx:connectionType -> def:type */ + if (esxUtil_GetConfigString(conn, conf, connectionType_name, + &connectionType, 1) < 0) { + goto failure; + } + + /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */ + if (esxUtil_GetConfigString(conn, conf, addressType_name, + &addressType, 1) < 0 || + esxUtil_GetConfigString(conn, conf, generatedAddress_name, + &generatedAddress, 1) < 0 || + esxUtil_GetConfigString(conn, conf, address_name, &address, 1) < 0) { + goto failure; + } + + if (addressType == NULL || STRCASEEQ(addressType, "generated")) { + if (generatedAddress != NULL) { + if (virParseMacAddr(generatedAddress, (*def)->mac) < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be MAC address but " + "found '%s'", generatedAddress_name, + generatedAddress); + goto failure; + } + } + } else if (STRCASEEQ(addressType, "static")) { + if (address != NULL) { + if (virParseMacAddr(address, (*def)->mac) < 0) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be MAC address but " + "found '%s'", address_name, address); + goto failure; + } + } + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'generated' or 'static' but " + "found '%s'", addressType_name, addressType); + goto failure; + } + + /* vmx:virtualDev -> def:model */ + if (esxUtil_GetConfigString(conn, conf, virtualDev_name, + &virtualDev, 1) < 0) { + goto failure; + } + + if (virtualDev != NULL && + STRCASENEQ(virtualDev, "vlance") && + STRCASENEQ(virtualDev, "vmxnet") && + STRCASENEQ(virtualDev, "e1000")) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or " + "'e1000' but found '%s'", virtualDev_name, virtualDev); + goto failure; + } + + /* vmx:vnet -> def:data.bridge.brname */ + if (connectionType != NULL && STRCASEEQ(connectionType, "custom") && + esxUtil_GetConfigString(conn, conf, vnet_name, &vnet, 0) < 0) { + goto failure; + } + + /* Setup virDomainNetDef */ + if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) { + (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + (*def)->model = virtualDev; + + virtualDev = NULL; + } else if (STRCASEEQ(connectionType, "hostonly")) { + /* FIXME */ + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "No yet handled value '%s' for VMX entry '%s'", + connectionType, connectionType_name); + goto failure; + } else if (STRCASEEQ(connectionType, "nat")) { + /* FIXME */ + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "No yet handled value '%s' for VMX entry '%s'", + connectionType, connectionType_name); + goto failure; + } else if (STRCASEEQ(connectionType, "custom")) { + (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + (*def)->model = virtualDev; + (*def)->data.bridge.brname = vnet; + + virtualDev = NULL; + vnet = NULL; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Invalid value '%s' for VMX entry '%s'", connectionType, + connectionType_name); + goto failure; + } + +cleanup: + VIR_FREE(connectionType); + VIR_FREE(addressType); + VIR_FREE(generatedAddress); + VIR_FREE(address); + VIR_FREE(virtualDev); + VIR_FREE(vnet); + + return result; + +failure: + result = -1; + +ignore: + virDomainNetDefFree(*def); + *def = NULL; + + goto cleanup; +} + + + +int +esxVMX_ParseSerial(virConnectPtr conn, virConfPtr conf, int port, + virDomainChrDefPtr *def) +{ + int result = 0; + char prefix[48] = ""; + + char present_name[48] = ""; + int present = 0; + + char startConnected_name[48] = ""; + int startConnected = 0; + + char fileType_name[48] = ""; + char *fileType = NULL; + + char fileName_name[48] = ""; + char *fileName = NULL; + + if (def == NULL || *def != NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (port < 0 || port > 3) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Serial port index %d out of [0..3] range", port); + goto failure; + } + + if (VIR_ALLOC(*def) < 0) { + virReportOOMError(conn); + goto failure; + } + + strncpy(prefix, "serialX", sizeof (prefix)); + prefix[6] = '0' + port; + + ESX_BUILD_VMX_NAME(present); + ESX_BUILD_VMX_NAME(startConnected); + ESX_BUILD_VMX_NAME(fileType); + ESX_BUILD_VMX_NAME(fileName); + + /* vmx:present */ + if (esxUtil_GetConfigBoolean(conn, conf, present_name, + &present, 0, 1) < 0) { + goto failure; + } + + /* vmx:startConnected */ + if (esxUtil_GetConfigBoolean(conn, conf, startConnected_name, + &startConnected, 1, 1) < 0) { + goto failure; + } + + /* FIXME: Need to distiguish between active and inactive domains here */ + if (! present/* && ! startConnected*/) { + goto ignore; + } + + /* vmx:fileType -> def:type */ + if (esxUtil_GetConfigString(conn, conf, fileType_name, &fileType, 0) < 0) { + goto failure; + } + + /* vmx:fileName -> def:data.file.path */ + if (esxUtil_GetConfigString(conn, conf, fileName_name, &fileName, 0) < 0) { + goto failure; + } + + /* Setup virDomainChrDef */ + if (STRCASEEQ(fileType, "device")) { + (*def)->dstPort = port; + (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV; + (*def)->data.file.path = fileName; + + fileName = NULL; + } else if (STRCASEEQ(fileType, "file")) { + (*def)->dstPort = port; + (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE; + (*def)->data.file.path = fileName; + + fileName = NULL; + } else if (STRCASEEQ(fileType, "pipe")) { + /* FIXME */ + VIR_WARN("Serial port %d has currently unsupported type '%s', " + "ignoring it", port, fileType); + goto ignore; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' " + "but found '%s'", fileType_name, fileType); + goto failure; + } + +cleanup: + VIR_FREE(fileType); + VIR_FREE(fileName); + + return result; + +failure: + result = -1; + +ignore: + virDomainChrDefFree(*def); + *def = NULL; + + goto cleanup; +} + + + +int +esxVMX_ParseParallel(virConnectPtr conn, virConfPtr conf, int port, + virDomainChrDefPtr *def) +{ + int result = 0; + char prefix[48] = ""; + + char present_name[48] = ""; + int present = 0; + + char startConnected_name[48] = ""; + int startConnected = 0; + + char fileType_name[48] = ""; + char *fileType = NULL; + + char fileName_name[48] = ""; + char *fileName = NULL; + + if (def == NULL || *def != NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + return -1; + } + + if (port < 0 || port > 2) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Parallel port index %d out of [0..2] range", port); + goto failure; + } + + if (VIR_ALLOC(*def) < 0) { + virReportOOMError(conn); + goto failure; + } + + strncpy(prefix, "parallelX", sizeof (prefix)); + prefix[8] = '0' + port; + + ESX_BUILD_VMX_NAME(present); + ESX_BUILD_VMX_NAME(startConnected); + ESX_BUILD_VMX_NAME(fileType); + ESX_BUILD_VMX_NAME(fileName); + + /* vmx:present */ + if (esxUtil_GetConfigBoolean(conn, conf, present_name, + &present, 0, 1) < 0) { + goto failure; + } + + /* vmx:startConnected */ + if (esxUtil_GetConfigBoolean(conn, conf, startConnected_name, + &startConnected, 1, 1) < 0) { + goto failure; + } + + /* FIXME: Need to distiguish between active and inactive domains here */ + if (! present/* && ! startConnected*/) { + goto ignore; + } + + /* vmx:fileType -> def:type */ + if (esxUtil_GetConfigString(conn, conf, fileType_name, &fileType, 0) < 0) { + goto failure; + } + + /* vmx:fileName -> def:data.file.path */ + if (esxUtil_GetConfigString(conn, conf, fileName_name, &fileName, 0) < 0) { + goto failure; + } + + /* Setup virDomainChrDef */ + if (STRCASEEQ(fileType, "device")) { + (*def)->dstPort = port; + (*def)->type = VIR_DOMAIN_CHR_TYPE_DEV; + (*def)->data.file.path = fileName; + + fileName = NULL; + } else if (STRCASEEQ(fileType, "file")) { + (*def)->dstPort = port; + (*def)->type = VIR_DOMAIN_CHR_TYPE_FILE; + (*def)->data.file.path = fileName; + + fileName = NULL; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting VMX entry '%s' to be 'device' or 'file' but " + "found '%s'", fileType_name, fileType); + goto failure; + } + +cleanup: + VIR_FREE(fileType); + VIR_FREE(fileName); + + return result; + +failure: + result = -1; + +ignore: + virDomainChrDefFree(*def); + *def = NULL; + + goto cleanup; +} diff --git a/src/esx/esx_vmx.h b/src/esx/esx_vmx.h new file mode 100644 index 0000000..f32a50a --- /dev/null +++ b/src/esx/esx_vmx.h @@ -0,0 +1,55 @@ + +/* + * esx_vmx.c: VMX related methods for the VMware ESX driver + * + * Copyright (C) 2009 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ESX_VMX_H__ +#define __ESX_VMX_H__ + +#include "internal.h" +#include "domain_conf.h" + +virDomainDefPtr +esxVMX_ParseConfig(virConnectPtr conn, const char *vmx); + +int +esxVMX_ParseSCSIController(virConnectPtr conn, virConfPtr conf, + int controller, int *present, char **virtualDev); + +char * +esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix); + +int +esxVMX_ParseDisk(virConnectPtr conn, virConfPtr conf, int device, int bus, + int controller, int id, const char *virtualDev, + virDomainDiskDefPtr *def); +int +esxVMX_ParseEthernet(virConnectPtr conn, virConfPtr conf, int controller, + virDomainNetDefPtr *def); + +int +esxVMX_ParseSerial(virConnectPtr conn, virConfPtr conf, int port, + virDomainChrDefPtr *def); + +int +esxVMX_ParseParallel(virConnectPtr conn, virConfPtr conf, int port, + virDomainChrDefPtr *def); + +#endif /* __ESX_VMX_H__ */
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list