[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] VMware ESX driver announcement



Hello,

I'm participate in a project of the Paderborn Center for Parallel
Computing, an institute of the University of Paderborn:
http://pc2.uni-paderborn.de

The project's goal is to use virtualization in a supercomputer
environment. We've decided to use libvirt to manage different
hypervisor. A subgoal is to extend the driver base of libvirt. We've
started an VMware ESX driver and are investigating Hyper-V support
(see next mail).

The ESX driver isn't complete yet, currently it supports:

- domain lookup by ID, UUID and name
- domain listing
- domain suspend and resume
- domain reboot, if the VMware tools are installed inside the domain
- domain start and shutdown
- domain migration

The driver uses the SOAP based VMware VI API. We've tried to generate
SOAP client code with gSOAP and looked at other SOAP libraries, but
the VI API uses inheritance in a way that gSOAP fails to generate C
code for. Because of this we wrote a minimal SOAP client based on
libcurl and libxml2 that can handle this inheritance problem in C.

The next item on the todo list is domain creation, because currently
the driver can only deal with prior existing domains.

We think this code might be useful for others and would be glad if the
driver could be merged into libvirt in medium term.

All of our work is licensed under LGPLv2+.
diff --git a/configure.in b/configure.in
index 8116fc8..59ed846 100644
--- a/configure.in
+++ b/configure.in
@@ -189,6 +189,8 @@ AC_ARG_WITH([vbox],
 [  --with-vbox             add VirtualBox support (on)],[],[with_vbox=yes])
 AC_ARG_WITH([lxc],
 [  --with-lxc              add Linux Container support (on)],[],[with_lxc=yes])
+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],
@@ -308,6 +310,11 @@ if test "$with_uml" = "yes" ; then
 fi
 AM_CONDITIONAL([WITH_UML], [test "$with_uml" = "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
@@ -997,6 +1004,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.2"
+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
@@ -1375,6 +1402,7 @@ AC_MSG_NOTICE([     UML: $with_uml])
 AC_MSG_NOTICE([  OpenVZ: $with_openvz])
 AC_MSG_NOTICE([    VBox: $with_vbox])
 AC_MSG_NOTICE([     LXC: $with_lxc])
+AC_MSG_NOTICE([     ESX: $with_esx])
 AC_MSG_NOTICE([    Test: $with_test])
 AC_MSG_NOTICE([  Remote: $with_remote])
 AC_MSG_NOTICE([ Network: $with_network])
@@ -1446,6 +1474,11 @@ AC_MSG_NOTICE([  devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS])
 else
 AC_MSG_NOTICE([  devkit: 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([Test suite])
 AC_MSG_NOTICE([])
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 4677ebc..8870255 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -63,6 +63,7 @@ typedef enum {
     VIR_FROM_XEN_INOTIFY, /* Error from xen inotify layer */
     VIR_FROM_SECURITY,  /* Error from security framework */
     VIR_FROM_VBOX,    /* Error from VirtualBox driver */
+    VIR_FROM_ESX,	/* Error from ESX driver */
 } virErrorDomain;
 
 
diff --git a/src/Makefile.am b/src/Makefile.am
index fd692b4..1dc7882 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -144,6 +144,11 @@ UML_DRIVER_SOURCES =						\
 		uml_conf.c uml_conf.h				\
 		uml_driver.c uml_driver.h
 
+ESX_DRIVER_SOURCES =						\
+		esx_driver.c esx_driver.h			\
+		esx_util.c esx_util.h				\
+		esx_vi.c esx_vi.h
+
 NETWORK_DRIVER_SOURCES =					\
 		network_driver.h network_driver.c
 
@@ -337,6 +342,21 @@ endif
 libvirt_driver_uml_la_SOURCES = $(UML_DRIVER_SOURCES)
 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
@@ -431,6 +451,7 @@ EXTRA_DIST +=							\
 		$(UML_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 b8e0a04..544329a 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -21,6 +21,7 @@ typedef enum {
     VIR_DRV_LXC = 6,
     VIR_DRV_UML = 7,
     VIR_DRV_VBOX = 8,
+    VIR_DRV_ESX = 9,
 } virDrvNo;
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index f1f81b3..135e090 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_driver.h"
+#endif
 #endif
 
 #define VIR_FROM_THIS VIR_FROM_NONE
@@ -310,6 +313,7 @@ virInitialize(void)
     virDriverLoadModule("xen");
     virDriverLoadModule("openvz");
     virDriverLoadModule("vbox");
+    virDriverLoadModule("esx");
     virDriverLoadModule("remote");
 #else
 #ifdef WITH_TEST
@@ -324,6 +328,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
@@ -845,6 +852,10 @@ virGetVersion(unsigned long *libVer, const char *type,
         if (STRCASEEQ(type, "UML"))
             *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 e12608d..4b73c2c 100644
--- a/src/virterror.c
+++ b/src/virterror.c
@@ -157,6 +157,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_VBOX:
             dom = "VBOX ";
             break;
+        case VIR_FROM_ESX:
+            dom = "ESX ";
+            break;
     }
     return(dom);
 }
diff --git a/src/esx_driver.c b/src/esx_driver.c
new file mode 100644
index 0000000..28500b8
--- /dev/null
+++ b/src/esx_driver.c
@@ -0,0 +1,1385 @@
+
+/*
+ * esx_driver.c: core driver methods for managing VMware ESX hosts
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias bolte googlemail com>
+ * Copyright (C) 2009 Maximilian Wilhelm <max rfc2324 org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "qparams.h"
+#include "uuid.h"
+#include "esx_driver.h"
+#include "esx_vi.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_ESX
+
+#define ESX_ERROR(conn, code, fmt...)                                \
+    /* FIXME: remove this VIR_DEBUG0 line when libvirt provides */   \
+    /*        file and line information in error messages       */   \
+    VIR_DEBUG0 ("this is a dummy message to provide a source "       \
+                "position for the following error...");              \
+    virReportErrorHelper (conn, VIR_FROM_ESX, code, __FILE__,        \
+                          __FUNCTION__, __LINE__, fmt)
+
+static int esxDomainGetMaxVcpus(virDomainPtr domain);
+
+typedef struct _esxPrivate {
+    esxVI_Context *host;
+    esxVI_Context *center;
+} esxPrivate;
+
+static virDrvOpenStatus
+esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
+{
+    int i;
+    esxPrivate *priv = NULL;
+    struct qparam_set *queryParamSet = NULL;
+    struct qparam *queryParam = NULL;
+    char *url = NULL;
+    const char *transport = NULL;
+    const char *center = NULL;
+    char *username = NULL;
+    char *password = NULL;
+
+    if (conn->uri == NULL ||
+        conn->uri->scheme == NULL ||
+        conn->uri->server == NULL ||
+        conn->uri->path == NULL ||
+        STRNEQ(conn->uri->scheme, "esx") ||
+        STRNEQ(conn->uri->path, "/sdk") || auth == NULL || auth->cb == NULL) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+#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 = queryParam->value;
+
+            if (STRNEQ(transport, "http") && STRNEQ(transport, "https")) {
+                ESX_ERROR(conn, VIR_ERR_INVALID_ARG,
+                          "esxOpen: query parameter 'transport' has unexpected "
+                          "value '%s' (should be http|https)", transport);
+                goto failure;
+            }
+        } else if (STRCASEEQ(queryParam->name, "center")) {
+            center = queryParam->value;
+        } else {
+            VIR_DEBUG("Unknown query parameter '%s'", queryParam->name);
+        }
+    }
+
+    if (transport == NULL) {
+        transport = "https";
+    }
+
+    /* Allocate per-connection private data. */
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (virAsprintf(&url, "%s://%s%s", transport, conn->uri->server,
+                    conn->uri->path) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    VIR_DEBUG("URL to ESX host: %s", url);
+
+    if (conn->uri->user != NULL) {
+        username = esxUtil_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 (center != NULL) {
+        if (virAsprintf(&url, "%s://%s%s", transport, center,
+                        conn->uri->path) < 0) {
+            virReportOOMError(conn);
+            goto failure;
+        }
+
+        VIR_DEBUG("URL to ESX center: %s", url);
+
+        if (esxVI_Context_Alloc(conn, &priv->center) < 0) {
+            goto failure;
+        }
+
+        username = esxUtil_RequestUsername(auth, "administrator",
+                                           queryParam->value);
+
+        if (username == NULL) {
+            ESX_ERROR(conn, VIR_ERR_AUTH_FAILED,
+                      "Username request failed");
+            goto failure;
+        }
+
+        password = esxUtil_RequestPassword(auth, username,
+                                           queryParam->value);
+
+        if (password == NULL) {
+            ESX_ERROR(conn, VIR_ERR_AUTH_FAILED,
+                      "Password request failed");
+            goto failure;
+        }
+
+        if (esxVI_Context_Connect(conn, priv->center, url, username,
+                                  password) < 0) {
+            goto failure;
+        }
+
+        VIR_FREE(url);
+        VIR_FREE(password);
+        VIR_FREE(username);
+    }
+
+    if (queryParamSet != NULL) {
+        free_qparam_set(queryParamSet);
+    }
+
+    conn->privateData = priv;
+
+    return VIR_DRV_OPEN_SUCCESS;
+
+  failure:
+    VIR_FREE(url);
+    VIR_FREE(password);
+    VIR_FREE(username);
+
+    if (queryParamSet != NULL) {
+        free_qparam_set(queryParamSet);
+    }
+
+    if (priv != NULL) {
+        esxVI_Context_Free(&priv->host);
+        esxVI_Context_Free(&priv->center);
+
+        VIR_FREE(priv);
+    }
+
+    return VIR_DRV_OPEN_ERROR;
+}
+
+static int
+esxClose(virConnectPtr conn)
+{
+    esxPrivate *priv = (esxPrivate *) conn->privateData;
+
+    esxVI_Logout(conn, priv->host);
+    esxVI_Context_Free(&priv->host);
+
+    if (priv->center != NULL) {
+        esxVI_Logout(conn, priv->center);
+        esxVI_Context_Free(&priv->center);
+    }
+
+    VIR_FREE(priv);
+
+    conn->privateData = NULL;
+
+    return 0;
+}
+
+/* Which features are supported by this driver? */
+static int
+esxSupportsFeature(virConnectPtr conn, int feature)
+{
+    esxPrivate *priv = (esxPrivate *) conn->privateData;
+
+    switch (feature) {
+    case VIR_DRV_FEATURE_MIGRATION_V1:
+        /* Migration is only possible via a Virtual Center */
+        return priv->center != NULL ? 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 = (char *) priv->host->service->about->version;
+    unsigned int major, minor, release;
+
+    /* 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 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 (ids == NULL || maxids < 0) {
+        goto failure;
+    }
+
+    if (maxids == 0) {
+        return 0;
+    }
+
+    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
+esxNumOfDomains(virConnectPtr conn)
+{
+    esxPrivate *priv = (esxPrivate *) conn->privateData;
+
+    return esxVI_NumOfDomainsByPowerState
+           (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;
+    const char *name_ = NULL;
+    unsigned char uuid_[VIR_UUID_BUFLEN];
+    virDomainPtr domain = NULL;
+
+    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;
+    const char *name_ = NULL;
+    unsigned char uuid_[VIR_UUID_BUFLEN];
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virDomainPtr domain = NULL;
+
+    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;
+    const char *name_ = NULL;
+    unsigned char uuid_[VIR_UUID_BUFLEN];
+    virDomainPtr domain = NULL;
+
+    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 (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           propertyNameList,
+                                           &virtualMachine) < 0 ||
+        esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
+                                          &powerState) < 0) {
+        goto failure;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, "Domain is not running");
+        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 (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           propertyNameList,
+                                           &virtualMachine) < 0 ||
+        esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
+                                          &powerState) < 0) {
+        goto failure;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_Suspended) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG,
+                  "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;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+
+    if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           propertyNameList,
+                                           &virtualMachine) < 0 ||
+        esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
+                                          &powerState) < 0) {
+        goto failure;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, "Domain is not running");
+        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 shutdown 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
+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 (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           propertyNameList,
+                                           &virtualMachine) < 0 ||
+        esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
+                                          &powerState) < 0) {
+        goto failure;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, "Domain is not running");
+        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
+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;
+    int integer = 0;
+
+    if (esxVI_String_AppendValueListToList(domain->conn, &propertyNameList,
+                                           "runtime.powerState\0"
+                                           "summary.config.memorySizeMB\0"
+                                           "summary.config.numCpu\0"
+                                           "summary.quickStats.guestMemoryUsage\0") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           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->value, &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, "summary.config.memorySizeMB")) {
+            if (esxVI_Int_CastValueFromAnyType(domain->conn,
+                                               dynamicProperty->value,
+                                               &integer) < 0) {
+                goto failure;
+            }
+
+            info->maxMem = integer * 1024;
+        } else if (STREQ(dynamicProperty->name, "summary.config.numCpu")) {
+            if (esxVI_Int_CastValueFromAnyType(domain->conn,
+                                               dynamicProperty->value,
+                                               &integer) < 0) {
+                goto failure;
+            }
+
+            info->nrVirtCpu = integer;
+        } else if (STREQ(dynamicProperty->name, "summary.quickStats.guestMemoryUsage")) {
+            if (esxVI_Int_CastValueFromAnyType(domain->conn,
+                                               dynamicProperty->value,
+                                               &integer) < 0) {
+                goto failure;
+            }
+
+            info->memory = integer * 1024;
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&virtualMachine);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static int
+esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+    int result = 0;
+    esxPrivate *priv = (esxPrivate *) domain->conn->privateData;
+    unsigned int nvcpus_max;
+    esxVI_ObjectContent *virtualMachine = NULL;
+    esxVI_VirtualMachineConfigSpec *spec = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+
+    if (nvcpus < 1) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG,
+                  "Requested number of virtual CPUs must al least be 1");
+        goto failure;
+    }
+
+    /* FIXME: When esxDomainGetMaxVcpus() is coded error handling might be
+     *        required here
+     */
+    nvcpus_max = esxDomainGetMaxVcpus(domain);
+
+    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_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           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");
+        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 ATTRIBUTE_UNUSED)
+{
+    /* FIXME: need a method to query the host via VI API for this limit */
+    int nvcpus_max = 4;
+
+    return nvcpus_max;
+}
+
+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 (names == NULL || maxnames < 0) {
+        goto failure;
+    }
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    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")) {
+                names[count] = esxUtil_Strdup(dynamicProperty->value->value);
+
+                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
+esxNumOfDefinedDomains(virConnectPtr conn)
+{
+    esxPrivate *priv = (esxPrivate *) conn->privateData;
+
+    return esxVI_NumOfDomainsByPowerState
+           (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 (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+                                       "runtime.powerState") < 0 ||
+        esxVI_LookupVirtualMachineByDomain(domain->conn, priv->host, domain,
+                                           propertyNameList,
+                                           &virtualMachine) < 0 ||
+        esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
+                                          &powerState) < 0) {
+        goto failure;
+    }
+
+    if (powerState != esxVI_VirtualMachinePowerState_PoweredOff) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG, "Domain is not shutdown");
+        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 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)
+{
+    if (uri_in == NULL) {
+        if (virAsprintf(uri_out, "%s://%s%s",
+                        dconn->uri->scheme + 4, dconn->uri->server,
+                        dconn->uri->path) < 0) {
+            virReportOOMError(dconn);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+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;
+    esxVI_ObjectContent *virtualMachine = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *hostSystemList = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_ObjectContent *matchingHostSystem = NULL;
+    esxVI_ObjectContent *resourcePoolList = NULL;
+    esxVI_ObjectContent *resourcePool = NULL;
+    esxVI_ObjectContent *matchingResourcePool = NULL;
+    const char *parentName = NULL;
+    xmlURI *xmlUri = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+
+    VIR_DEBUG("uri %s", uri);
+
+    if (priv->center == 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;
+    }
+
+    /* Query Virtual Center for the domain to be migrated */
+    if (esxVI_LookupVirtualMachineByDomain(domain->conn, priv->center, domain,
+                                           NULL, &virtualMachine) < 0) {
+        goto failure;
+    }
+
+    /* Query Virtual Center for all known host systems */
+    if (esxVI_String_AppendValueListToList(domain->conn, &propertyNameList,
+                                           "name\0"
+                                           "parent\0") < 0 ||
+        esxVI_GetObjectContent(domain->conn, priv->center,
+                               priv->center->service->rootFolder,
+                               "HostSystem", propertyNameList,
+                               esxVI_Boolean_True, &hostSystemList) < 0) {
+        goto failure;
+    }
+
+    /* Iterate over all host systems and search correct one */
+    xmlUri = xmlParseURI(uri);
+
+    if (xmlUri == NULL) {
+        virReportOOMError(domain->conn);
+        goto failure;
+    }
+
+    for (hostSystem = hostSystemList; hostSystem != NULL;
+         hostSystem = hostSystem->_next) {
+        for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "name")) {
+                /* Check if this host system is the one we are looking for */
+                /* FIXME: use correct datatype here */
+                if (STRCASEEQ(dynamicProperty->value->value, xmlUri->server)) {
+                    matchingHostSystem = hostSystem;
+                    break;
+                }
+            }
+        }
+
+        if (matchingHostSystem != NULL) {
+            for (dynamicProperty = matchingHostSystem->propSet;
+                 dynamicProperty != NULL;
+                 dynamicProperty = dynamicProperty->_next) {
+                if (STREQ(dynamicProperty->name, "parent")) {
+                    /* FIXME: use correct datatype here */
+                    parentName = dynamicProperty->value->value;
+                    break;
+                }
+            }
+
+            break;
+        }
+    }
+
+    xmlFreeURI(xmlUri);
+
+    if (matchingHostSystem == NULL) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG,
+                  "No host system with name '%s' in Virtual Center", uri);
+        goto failure;
+    }
+
+    if (parentName == NULL) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG,
+                  "Compute resource of host system '%s' has no name", uri);
+        goto failure;
+    }
+
+    /* Query Virtual Center for all known resource pools */
+    esxVI_String_Free(&propertyNameList);
+
+    if (esxVI_String_AppendValueListToList(domain->conn, &propertyNameList,
+                                           "name\0"
+                                           "parent\0") < 0 ||
+        esxVI_GetObjectContent(domain->conn, priv->center,
+                               priv->center->service->rootFolder,
+                               "ResourcePool", propertyNameList,
+                               esxVI_Boolean_True, &resourcePoolList) < 0) {
+        goto failure;
+    }
+
+    /* Iterate over all resource pools and search correct one */
+    for (resourcePool = resourcePoolList; resourcePool != NULL;
+         resourcePool = resourcePool->_next) {
+        for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "parent")) {
+                /* Check if this resource pool is the one we are looking for */
+                /* FIXME: use correct datatype here */
+                if (STREQ(dynamicProperty->value->value, parentName)) {
+                    matchingResourcePool = resourcePool;
+                    break;
+                }
+            }
+        }
+
+        if (matchingResourcePool != NULL) {
+            break;
+        }
+    }
+
+    if (matchingResourcePool == NULL) {
+        ESX_ERROR(domain->conn, VIR_ERR_INVALID_ARG,
+                  "No resource pool in compute resource of host system '%s'",
+                  uri);
+        goto failure;
+    }
+
+    if (esxVI_MigrateVM_Task(domain->conn, priv->center, virtualMachine->obj,
+                             matchingResourcePool->obj,
+                             matchingHostSystem->obj, &task) < 0 ||
+        esxVI_WaitForTaskCompletion(domain->conn, priv->center, task,
+                                    &taskInfoState) < 0) {
+        goto failure;
+    }
+
+    if (taskInfoState != esxVI_TaskInfoState_Success) {
+        ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                  "Could not migrate domain");
+        goto failure;
+    }
+
+  cleanup:
+    esxVI_ObjectContent_Free(&virtualMachine);
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ManagedObjectReference_Free(&task);
+    esxVI_ObjectContent_Free(&hostSystemList);
+    esxVI_ObjectContent_Free(&resourcePoolList);
+
+    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 */
+    NULL,                       /* hostname */
+    NULL,                       /* getMaxVcpus */
+    NULL,                       /* nodeGetInfo */
+    NULL,                       /* getCapabilities */
+    esxListDomains,             /* listDomains */
+    esxNumOfDomains,            /* numOfDomains */
+    NULL,                       /* domainCreateXML */
+    esxDomainLookupByID,        /* domainLookupByID */
+    esxDomainLookupByUUID,      /* domainLookupByUUID */
+    esxDomainLookupByName,      /* domainLookupByName */
+    esxDomainSuspend,           /* domainSuspend */
+    esxDomainResume,            /* domainResume */
+    esxDomainShutdown,          /* domainShutdown */
+    esxDomainReboot,            /* domainReboot */
+    NULL,                       /* domainDestroy */
+    NULL,                       /* domainGetOSType */
+    NULL,                       /* domainGetMaxMemory */
+    NULL,                       /* domainSetMaxMemory */
+    NULL,                       /* domainSetMemory */
+    esxDomainGetInfo,           /* domainGetInfo */
+    NULL,                       /* domainSave */
+    NULL,                       /* domainRestore */
+    NULL,                       /* domainCoreDump */
+    esxDomainSetVcpus,          /* domainSetVcpus */
+    NULL,                       /* domainPinVcpu */
+    NULL,                       /* domainGetVcpus */
+    esxDomainGetMaxVcpus,       /* domainGetMaxVcpus */
+    NULL,                       /* domainGetSecurityLabel */
+    NULL,                       /* nodeGetSecurityModel */
+    NULL,                       /* domainDumpXML */
+    esxListDefinedDomains,      /* listDefinedDomains */
+    esxNumOfDefinedDomains,     /* numOfDefinedDomains */
+    esxDomainCreate,            /* domainCreate */
+    NULL,                       /* domainDefineXML */
+    NULL,                       /* domainUndefine */
+    NULL,                       /* domainAttachDevice */
+    NULL,                       /* domainDetachDevice */
+    NULL,                       /* domainGetAutostart */
+    NULL,                       /* domainSetAutostart */
+    NULL,                       /* domainGetSchedulerType */
+    NULL,                       /* domainGetSchedulerParameters */
+    NULL,                       /* 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_driver.h b/src/esx_driver.h
new file mode 100644
index 0000000..85f4b32
--- /dev/null
+++ b/src/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 googlemail com>
+ * Copyright (C) 2009 Maximilian Wilhelm <max rfc2324 org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#ifndef __ESX_DRIVER_H__
+#define __ESX_DRIVER_H__
+
+int esxRegister(void);
+
+#endif /* __ESX_DRIVER_H__ */
diff --git a/src/esx_util.c b/src/esx_util.c
new file mode 100644
index 0000000..c2e492c
--- /dev/null
+++ b/src/esx_util.c
@@ -0,0 +1,170 @@
+
+/*
+ * esx_util.c: utility methods for the VMware ESX driver
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias bolte googlemail com>
+ * Copyright (C) 2009 Maximilian Wilhelm <max rfc2324 org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <config.h>
+
+#include <libxml/tree.h>
+
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "esx_util.h"
+
+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_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;
+}
+
+char *
+esxUtil_MigrateStringFromLibXML(xmlChar *xmlString)
+{
+    char *esxString = NULL;
+    size_t length = 0;
+
+    if (xmlString == NULL) {
+        return NULL;
+    }
+
+    length = xmlStrlen(xmlString);
+
+    if (VIR_ALLOC_N(esxString, length + 1) >= 0) {
+        strncpy(esxString, (const char *) xmlString, length);
+    }
+
+    xmlFree(xmlString);
+
+    return esxString;
+}
+
+char *
+esxUtil_Strdup(const char *string)
+{
+    char *duplicate = NULL;
+    size_t length = 0;
+
+    if (string == NULL) {
+        return NULL;
+    }
+
+    length = strlen(string);
+
+    if (VIR_ALLOC_N(duplicate, length + 1) >= 0) {
+        strncpy(duplicate, string, length);
+    }
+
+    return duplicate;
+}
diff --git a/src/esx_util.h b/src/esx_util.h
new file mode 100644
index 0000000..d3a6346
--- /dev/null
+++ b/src/esx_util.h
@@ -0,0 +1,43 @@
+
+/*
+ * esx_driver.c: utility methods for the VMware ESX driver
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias bolte googlemail com>
+ *
+ * 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"
+
+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_ParseVirtualMachineIDString(const char *id_string, int *id);
+
+char *esxUtil_MigrateStringFromLibXML(xmlChar *xmlString);
+
+char *esxUtil_Strdup(const char *string);
+
+#endif /* __ESX_UTIL_H__ */
diff --git a/src/esx_vi.c b/src/esx_vi.c
new file mode 100644
index 0000000..26a7d85
--- /dev/null
+++ b/src/esx_vi.c
@@ -0,0 +1,4437 @@
+
+/*
+ * esx_vi.c: client for the VMware VI API 2.5 to manage ESX hosts
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias bolte googlemail com>
+ *
+ * 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 <libxml/parser.h>
+#include <libxml/xpathInternals.h>
+
+#include "buf.h"
+#include "datatypes.h"
+#include "memory.h"
+#include "logging.h"
+#include "util.h"
+#include "uuid.h"
+#include "virterror_internal.h"
+#include "threads.h"
+#include "esx_vi.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_ESX
+
+#define ESX_VI_ERROR(conn, code, fmt...)                             \
+    /* FIXME: remove this VIR_DEBUG0 line when libvirt provides */   \
+    /*        file and line information in error messages       */   \
+    VIR_DEBUG0 ("this is a dummy message to provide a source "       \
+                "position for the following error...");              \
+    virReportErrorHelper (conn, VIR_FROM_ESX, code, __FILE__,        \
+                          __FUNCTION__, __LINE__, fmt)
+
+#define ESX_VI__TEMPLATE__ALLOC(type, name)                                \
+    int                                                                    \
+    esxVI_##type##_Alloc (virConnectPtr conn, esxVI_##type **name)         \
+    {                                                                      \
+        return _esxVI_Alloc (conn, (void **) name, sizeof (esxVI_##type)); \
+    }
+
+#define ESX_VI__TEMPLATE__APPEND_TO_LIST(type, name)                            \
+    int                                                                         \
+    esxVI_##type##_AppendToList (virConnectPtr conn, esxVI_##type **name##List, \
+                                 esxVI_##type *name)                            \
+    {                                                                           \
+        return esxVI_List_Append (conn, (esxVI_List **) name##List,             \
+                                  (esxVI_List *) name);                         \
+    }
+
+#define ESX_VI__TEMPLATE__DEEP_COPY_LIST(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__SERIALIZE_LIST(type, name)                                       \
+    int                                                                                    \
+    esxVI_##type##_SerializeList (virConnectPtr conn, esxVI_##type *name##List,            \
+                                  const char* element, char **output,                      \
+                                  esxVI_Boolean required)                                  \
+    {                                                                                      \
+        return esxVI_List_Serialize (conn, (esxVI_List *) name##List,                      \
+                                     element, output, required,                            \
+                                     (esxVI_List_SerializeFunc) esxVI_##type##_Serialize); \
+    }
+
+#define ESX_VI__TEMPLATE__DESERIALIZE_LIST(type, name)                                          \
+    int                                                                                         \
+    esxVI_##type##_DeserializeList (virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,         \
+                                    esxVI_##type **name##List)                                  \
+    {                                                                                           \
+        return esxVI_List_Deserialize (conn, doc, node, (esxVI_List **) name##List,             \
+                                       (esxVI_List_DeserializeFunc) esxVI_##type##_Deserialize, \
+                                       (esxVI_List_FreeFunc) esxVI_##type##_Free);              \
+    }
+
+static int
+_esxVI_Alloc(virConnectPtr conn, void **pointer, size_t size)
+{
+    if (pointer == NULL || *pointer != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (virAllocN(pointer, size, 1) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+_esxVI_CheckSerializationNecessity(virConnectPtr conn, const char *element,
+                                   char **output, esxVI_Boolean required)
+{
+    if (element == NULL || output == NULL || *output != 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 {
+        *output = esxUtil_Strdup("");
+
+        if (*output == NULL) {
+            virReportOOMError(conn);
+            return -1;
+        }
+
+        return 0;
+    }
+}
+
+/*
+ * Context
+ */
+
+ESX_VI__TEMPLATE__ALLOC(Context, ctx);
+
+void
+esxVI_Context_Free(esxVI_Context **ctx)
+{
+    if (ctx == NULL || *ctx == NULL) {
+        return;
+    }
+
+    VIR_FREE((*ctx)->url);
+
+    if ((*ctx)->curl_handle != NULL) {
+        curl_easy_cleanup((*ctx)->curl_handle);
+    }
+
+    if ((*ctx)->curl_headers != NULL) {
+        curl_slist_free_all((*ctx)->curl_headers);
+    }
+
+    virMutexDestroy(&(*ctx)->curl_lock);
+
+    esxVI_ServiceContent_Free(&(*ctx)->service);
+    esxVI_ManagedObjectReference_Free(&(*ctx)->datacenter);
+    esxVI_ManagedObjectReference_Free(&(*ctx)->vmFolder);
+    esxVI_ManagedObjectReference_Free(&(*ctx)->hostFolder);
+    esxVI_SelectionSpec_Free(&(*ctx)->fullTraversalSpecList);
+
+    VIR_FREE(*ctx);
+}
+
+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_DEBUGOUTPUT 0
+
+#if ESX_VI_CURL_ENABLE_DEBUGOUTPUT
+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, (const char **) &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_DEBUGOUTPUT
+    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;
+    }
+
+    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) < 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->value, &ctx->vmFolder, "Folder")) {
+                goto failure;
+            }
+        } else if (STREQ(dynamicProperty->name, "hostFolder")) {
+            if (esxVI_ManagedObjectReference_CastFromAnyType
+                (conn, dynamicProperty->value, &ctx->hostFolder, "Folder")) {
+                goto failure;
+            }
+        }
+    }
+
+    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;
+}
+
+/*
+ * Internal: RemoteRequest
+ */
+
+ESX_VI__TEMPLATE__ALLOC(RemoteRequest, remoteRequest);
+
+void
+esxVI_RemoteRequest_Free(esxVI_RemoteRequest **remoteRequest)
+{
+    if (remoteRequest == NULL || *remoteRequest == NULL) {
+        return;
+    }
+
+    VIR_FREE((*remoteRequest)->request);
+    VIR_FREE((*remoteRequest)->xpathExpression);
+
+    VIR_FREE(*remoteRequest);
+}
+
+int
+esxVI_RemoteRequest_Execute(virConnectPtr conn, esxVI_Context *ctx,
+                            esxVI_RemoteRequest *remoteRequest,
+                            esxVI_RemoteResponse **remoteResponse)
+{
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    esxVI_Fault *fault = NULL;
+
+    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_ERRORBUFFER,
+                     (*remoteResponse)->error);
+    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));
+
+    if (curl_easy_perform(ctx->curl_handle) != CURLE_OK) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "curl_easy_perform returned an error");
+        goto unlock;
+    }
+
+    if (curl_easy_getinfo(ctx->curl_handle, CURLINFO_RESPONSE_CODE,
+                          &(*remoteResponse)->code) != CURLE_OK) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "curl_easy_getinfo returned an error");
+        goto unlock;
+    }
+
+    virMutexUnlock(&ctx->curl_lock);
+
+    (*remoteResponse)->response = virBufferContentAndReset(&buffer);
+
+    if (remoteRequest->xpathExpression != NULL ||
+        (*remoteResponse)->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)->code != 200) {
+            (*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)->code, fault->code,
+                         fault->string);
+
+            goto failure;
+        } else {
+            (*remoteResponse)->xpathObject =
+                xmlXPathEval(BAD_CAST remoteRequest->xpathExpression,
+                             (*remoteResponse)->xpathContext);
+        }
+    }
+
+    return 0;
+
+  failure:
+    esxVI_RemoteResponse_Free(remoteResponse);
+    esxVI_Fault_Free(&fault);
+
+    return -1;
+
+  unlock:
+    virMutexUnlock(&ctx->curl_lock);
+
+    goto failure;
+}
+
+/*
+ * Internal: RemoteResponse
+ */
+
+ESX_VI__TEMPLATE__ALLOC(RemoteResponse, remoteResponse);
+
+void
+esxVI_RemoteResponse_Free(esxVI_RemoteResponse **remoteResponse)
+{
+    if (remoteResponse == NULL || *remoteResponse == NULL) {
+        return;
+    }
+
+    VIR_FREE((*remoteResponse)->response);
+
+    if ((*remoteResponse)->xpathObject != NULL) {
+        xmlXPathFreeObject((*remoteResponse)->xpathObject);
+    }
+
+    if ((*remoteResponse)->xpathContext != NULL) {
+        xmlXPathFreeContext((*remoteResponse)->xpathContext);
+    }
+
+    if ((*remoteResponse)->document != NULL) {
+        xmlFreeDoc((*remoteResponse)->document);
+    }
+
+    VIR_FREE(*remoteResponse);
+}
+
+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, remoteResponse->document, node, item) < 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,
+                                                     remoteResponse->document,
+                                                     node,
+                                                     managedObjectReference,
+                                                     expectedType) < 0) {
+            return -1;
+        }
+    } else {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "XPath error");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * XSD: Boolean
+ */
+
+int
+esxVI_Boolean_Serialize(virConnectPtr conn, esxVI_Boolean boolean,
+                        const char *element, char **output,
+                        esxVI_Boolean required)
+{
+    const char *string = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    switch (boolean) {
+    case esxVI_Boolean_Undefined:
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+
+    case esxVI_Boolean_True:
+        string = "true";
+        break;
+
+    case esxVI_Boolean_False:
+        string = "false";
+        break;
+
+    default:
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"xsd:boolean\">%s</%s>",
+                    element, string, element) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Internal: 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, char **output,
+                     esxVI_Boolean required,
+                     esxVI_List_SerializeFunc serializeFunc)
+{
+    esxVI_List *item = NULL;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    char *serialized = NULL;
+
+    if (element == NULL || output == 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, output,
+                                                  required);
+    }
+
+    for (item = list; item != NULL; item = item->_next) {
+        serialized = NULL;
+
+        if (serializeFunc(conn, item, element, &serialized,
+                          esxVI_Boolean_True) < 0) {
+            goto failure;
+        }
+
+        virBufferAdd(&buffer, serialized, strlen(serialized));
+
+        VIR_FREE(serialized);
+    }
+
+    *output = virBufferContentAndReset(&buffer);
+
+    return 0;
+
+  failure:
+    *output = virBufferContentAndReset(&buffer);
+
+    VIR_FREE(*output);
+
+    return -1;
+}
+
+int
+esxVI_List_Deserialize(virConnectPtr conn, xmlDocPtr doc, 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, doc, node, &item) < 0) {
+            goto failure;
+        }
+
+        if (esxVI_List_Append(conn, list, item) < 0) {
+            goto failure;
+        }
+    }
+
+    return 0;
+
+  failure:
+    freeFunc(list);
+
+    return -1;
+}
+
+/*
+ * XSD: String
+ */
+
+ESX_VI__TEMPLATE__ALLOC(String, string);
+
+void
+esxVI_String_Free(esxVI_String **string)
+{
+    if (string == NULL || *string == NULL) {
+        return;
+    }
+
+    esxVI_String_Free(&(*string)->_next);
+
+    VIR_FREE((*string)->value);
+
+    VIR_FREE(*string);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(String, string);
+
+int
+esxVI_String_AppendValueToList(virConnectPtr conn,
+                               esxVI_String **stringList, const char *value)
+{
+    int result;
+    esxVI_String *string = NULL;
+
+    if (esxVI_String_Alloc(conn, &string) < 0) {
+        return -1;
+    }
+
+    string->value = esxUtil_Strdup(value);
+
+    if (string->value == NULL) {
+        esxVI_String_Free(&string);
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    result = esxVI_String_AppendToList(conn, stringList, string);
+
+    if (result < 0) {
+        esxVI_String_Free(&string);
+    }
+
+    return result;
+}
+
+int
+esxVI_String_AppendValueListToList(virConnectPtr conn,
+                                   esxVI_String **stringList,
+                                   const char *valueList)
+{
+    const char *value = valueList;
+
+    /* FIXME: if appending fails after successfully adding one or more items
+     *        the list is left in an unclean state
+     */
+    while (value != NULL && *value != '\0') {
+        if (esxVI_String_AppendValueToList(conn, stringList, value) < 0) {
+            return -1;
+        }
+
+        value += strlen(value) + 1;
+    }
+
+    return 0;
+}
+
+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");
+        goto failure;
+    }
+
+    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;
+}
+
+ESX_VI__TEMPLATE__DEEP_COPY_LIST(String);
+
+int
+esxVI_String_DeepCopyValue(virConnectPtr conn, const 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 = esxUtil_Strdup(src);
+
+    if (*dest == NULL) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+esxVI_String_Serialize(virConnectPtr conn, esxVI_String *string,
+                       const char *element, char **output,
+                       esxVI_Boolean required)
+{
+    return esxVI_String_SerializeValue(conn,
+                                       string != NULL ? string->value : NULL,
+                                       element, output, required);
+}
+
+ESX_VI__TEMPLATE__SERIALIZE_LIST(String, string);
+
+int
+esxVI_String_SerializeValue(virConnectPtr conn, const char *value,
+                            const char *element, char **output,
+                            esxVI_Boolean required)
+{
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (value == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"xsd:string\">%s</%s>",
+                    element, value, element) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+esxVI_String_Deserialize(virConnectPtr conn, xmlDocPtr doc, 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 = esxUtil_MigrateStringFromLibXML
+                       (xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
+
+    if ((*string)->value == NULL) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_String_Free(string);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(String, string);
+
+int
+esxVI_String_DeserializeValue(virConnectPtr conn, xmlDocPtr doc,
+                              xmlNodePtr node, const char **value)
+{
+    if (value == NULL || *value != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    *value = esxUtil_MigrateStringFromLibXML
+             (xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
+
+    if (*value == NULL) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    VIR_FREE(value);
+
+    return -1;
+}
+
+/*
+ * VI Type: Fault
+ */
+
+ESX_VI__TEMPLATE__ALLOC(Fault, fault);
+
+void
+esxVI_Fault_Free(esxVI_Fault **fault)
+{
+    if (fault == NULL || *fault == NULL) {
+        return;
+    }
+
+    VIR_FREE((*fault)->code);
+    VIR_FREE((*fault)->string);
+
+    VIR_FREE(*fault);
+}
+
+int
+esxVI_Fault_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                        esxVI_Fault **fault)
+{
+    xmlNodePtr childNode = NULL;
+
+    if (fault == NULL || *fault != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_Fault_Alloc(conn, fault) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "faultcode")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*fault)->code)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "faultstring")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*fault)->string)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "detail")) {
+            /* FIXME: currently ignoring given details */
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*fault)->code == NULL ||
+        (*fault)->string == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_Fault_Free(fault);
+
+    return -1;
+}
+
+/*
+ * XSD: AnyType
+ */
+
+ESX_VI__TEMPLATE__ALLOC(AnyType, anyType);
+
+void
+esxVI_AnyType_Free(esxVI_AnyType **anyType)
+{
+    if (anyType == NULL || *anyType == NULL) {
+        return;
+    }
+
+    xmlFreeNode((*anyType)->_node);
+    VIR_FREE((*anyType)->type);
+    VIR_FREE((*anyType)->value);
+
+    VIR_FREE(*anyType);
+}
+
+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");
+        goto failure;
+    }
+
+    if (src == NULL) {
+        return 0;
+    }
+
+    if (esxVI_AnyType_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_AnyType_Free(dest);
+
+    return -1;
+}
+
+int
+esxVI_AnyType_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                          esxVI_AnyType **anyType)
+{
+    xmlChar *string;
+
+    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);
+
+    string = xmlGetNsProp(node, BAD_CAST "type",
+                          BAD_CAST "http://www.w3.org/2001/XMLSchema-instance";);
+    (*anyType)->type = esxUtil_MigrateStringFromLibXML(string);
+
+    if ((*anyType)->type == NULL) {
+        /* FIXME: may also indicate an out-of-memory condition */
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing 'type' property");
+        goto failure;
+    }
+
+    if (esxVI_String_DeserializeValue(conn, doc, node,
+                                      &(*anyType)->value) < 0) {
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_AnyType_Free(anyType);
+
+    return -1;
+}
+
+/*
+ * XSD: Int
+ */
+
+ESX_VI__TEMPLATE__ALLOC(Int, integer);
+
+void
+esxVI_Int_Free(esxVI_Int **integer)
+{
+    if (integer == NULL || *integer == NULL) {
+        return;
+    }
+
+    VIR_FREE(*integer);
+}
+
+int
+esxVI_Int_Serialize(virConnectPtr conn, esxVI_Int *integer,
+                    const char *element, char **output, esxVI_Boolean required)
+{
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (integer == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"xsd:int\">%d</%s>",
+                    element, integer->value, element) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+esxVI_Int_CastValueFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
+                               int *integer)
+{
+    if (anyType == NULL || integer == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (STRNEQ(anyType->type, "xsd:int")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type 'xsd:int' but found '%s'", anyType->type);
+        return -1;
+    }
+
+    if (virStrToLong_i(anyType->value, NULL, 10, integer) < 0) {
+        *integer = 0;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for xsd:int", anyType->value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * XSD: Long
+ */
+
+int
+esxVI_Long_CastValueFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
+                                long long *integer)
+{
+    if (anyType == NULL || integer == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (STRNEQ(anyType->type, "xsd:long")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type 'xsd:long' but found '%s'",
+                     anyType->type);
+        return -1;
+    }
+
+    if (virStrToLong_ll(anyType->value, NULL, 10, integer) < 0) {
+        *integer = 0;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for xsd:long", anyType->value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * VI Enum: ObjectUpdateKind
+ */
+
+int
+esxVI_ObjectUpdateKind_Deserialize(virConnectPtr conn,
+                                   xmlDocPtr doc, xmlNodePtr node,
+                                   esxVI_ObjectUpdateKind *objectUpdateKind)
+{
+    const char *value = NULL;
+
+    if (objectUpdateKind == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_String_DeserializeValue(conn, doc, node, &value) < 0) {
+        goto failure;
+    }
+
+    if (STREQ(value, "enter")) {
+        *objectUpdateKind = esxVI_ObjectUpdateKind_Enter;
+    } else if (STREQ(value, "leave")) {
+        *objectUpdateKind = esxVI_ObjectUpdateKind_Leave;
+    } else if (STREQ(value, "modify")) {
+        *objectUpdateKind = esxVI_ObjectUpdateKind_Modify;
+    } else {
+        *objectUpdateKind = esxVI_ObjectUpdateKind_Undefined;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for ObjectUpdateKind", value);
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    VIR_FREE(value);
+
+    return -1;
+}
+
+/*
+ * VI Enum: PropertyChangeOp
+ */
+
+int
+esxVI_PropertyChangeOp_Deserialize(virConnectPtr conn,
+                                   xmlDocPtr doc, xmlNodePtr node,
+                                   esxVI_PropertyChangeOp *propertyChangeOp)
+{
+    const char *value = NULL;
+
+    if (propertyChangeOp == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_String_DeserializeValue(conn, doc, node, &value) < 0) {
+        goto failure;
+    }
+
+    if (STREQ(value, "add")) {
+        *propertyChangeOp = esxVI_PropertyChangeOp_Add;
+    } else if (STREQ(value, "remove")) {
+        *propertyChangeOp = esxVI_PropertyChangeOp_Remove;
+    } else if (STREQ(value, "assign")) {
+        *propertyChangeOp = esxVI_PropertyChangeOp_Assign;
+    } else if (STREQ(value, "indirectRemove")) {
+        *propertyChangeOp = esxVI_PropertyChangeOp_IndirectRemove;
+    } else {
+        *propertyChangeOp = esxVI_PropertyChangeOp_Undefined;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for PropertyChangeOp", value);
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    VIR_FREE(value);
+
+    return -1;
+}
+
+/*
+ * VI Enum: TaskInfoState
+ */
+
+int
+esxVI_TaskInfoState_CastFromAnyType(virConnectPtr conn,
+                                    esxVI_AnyType *anyType,
+                                    esxVI_TaskInfoState *taskInfoState)
+{
+    if (anyType == NULL || taskInfoState == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (STRNEQ(anyType->type, "TaskInfoState")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type 'TaskInfoState' but found '%s'",
+                     anyType->type);
+        return -1;
+    }
+
+    if (STREQ(anyType->value, "error")) {
+        *taskInfoState = esxVI_TaskInfoState_Error;
+    } else if (STREQ(anyType->value, "queued")) {
+        *taskInfoState = esxVI_TaskInfoState_Queued;
+    } else if (STREQ(anyType->value, "running")) {
+        *taskInfoState = esxVI_TaskInfoState_Running;
+    } else if (STREQ(anyType->value, "success")) {
+        *taskInfoState = esxVI_TaskInfoState_Success;
+    } else {
+        *taskInfoState = esxVI_TaskInfoState_Undefined;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for TaskInfoState", anyType->value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * VI Enum: VirtualMachineMovePriority
+ */
+
+int
+esxVI_VirtualMachineMovePriority_Serialize(virConnectPtr conn,
+                                           esxVI_VirtualMachineMovePriority virtualMachineMovePriority,
+                                           const char *element, char **output,
+                                           esxVI_Boolean required)
+{
+    const char *string = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    switch (virtualMachineMovePriority) {
+    case esxVI_VirtualMachineMovePriority_Undefined:
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+
+    case esxVI_VirtualMachineMovePriority_LowPriority:
+        string = "lowPriority";
+        break;
+
+    case esxVI_VirtualMachineMovePriority_HighPriority:
+        string = "highPriority";
+        break;
+
+    case esxVI_VirtualMachineMovePriority_DefaultPriority:
+        string = "defaultPriority";
+        break;
+
+    default:
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"VirtualMachineMovePriority\">%s</%s>",
+                    element, string, element) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * VI Enum: VirtualMachinePowerState
+ */
+
+int
+esxVI_VirtualMachinePowerState_CastFromAnyType(virConnectPtr conn,
+                                               esxVI_AnyType *anyType,
+                                               esxVI_VirtualMachinePowerState *virtualMachinePowerState)
+{
+    if (anyType == NULL || virtualMachinePowerState == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (STRNEQ(anyType->type, "VirtualMachinePowerState")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type 'VirtualMachinePowerState' but found '%s'",
+                     anyType->type);
+        return -1;
+    }
+
+    if (STREQ(anyType->value, "poweredOff")) {
+        *virtualMachinePowerState = esxVI_VirtualMachinePowerState_PoweredOff;
+    } else if (STREQ(anyType->value, "poweredOn")) {
+        *virtualMachinePowerState = esxVI_VirtualMachinePowerState_PoweredOn;
+    } else if (STREQ(anyType->value, "suspended")) {
+        *virtualMachinePowerState = esxVI_VirtualMachinePowerState_Suspended;
+    } else {
+        *virtualMachinePowerState = esxVI_VirtualMachinePowerState_Undefined;
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Unknown value '%s' for VirtualMachinePowerState",
+                     anyType->value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * VI Type: ManagedObjectReference
+ */
+
+ESX_VI__TEMPLATE__ALLOC(ManagedObjectReference, managedObjectReference);
+
+void
+
+esxVI_ManagedObjectReference_Free(esxVI_ManagedObjectReference **managedObjectReference)
+{
+    if (managedObjectReference == NULL || *managedObjectReference == NULL) {
+        return;
+    }
+
+    VIR_FREE((*managedObjectReference)->type);
+    VIR_FREE((*managedObjectReference)->value);
+
+    VIR_FREE(*managedObjectReference);
+}
+
+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");
+        goto failure;
+    }
+
+    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->type, "ManagedObjectReference")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type 'ManagedObjectReference' but found '%s'",
+                     anyType->type);
+        goto failure;
+    }
+
+    if (esxVI_ManagedObjectReference_Alloc(conn, managedObjectReference) < 0) {
+        goto failure;
+    }
+
+    (*managedObjectReference)->type = esxUtil_MigrateStringFromLibXML
+                                      (xmlGetNoNsProp(anyType->_node,
+                                                      BAD_CAST "type"));
+
+    if ((*managedObjectReference)->type == NULL) {
+        /* FIXME: may also indicate an out-of-memory condition */
+        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_DeepCopyValue(conn, &(*managedObjectReference)->value,
+                                   anyType->value) < 0) {
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_ManagedObjectReference_Free(managedObjectReference);
+
+    return -1;
+}
+
+int
+esxVI_ManagedObjectReference_Serialize(virConnectPtr conn,
+                                       esxVI_ManagedObjectReference *managedObjectReference,
+                                       const char *element, char **output,
+                                       esxVI_Boolean required)
+{
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (managedObjectReference == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"ManagedObjectReference\" type=\"%s\">%s</%s>",
+                    element, managedObjectReference->type,
+                    managedObjectReference->value, element) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+esxVI_ManagedObjectReference_Deserialize(virConnectPtr conn,
+                                         xmlDocPtr doc, 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 = esxUtil_MigrateStringFromLibXML
+                                      (xmlGetNoNsProp(node, BAD_CAST "type"));
+
+    if ((*managedObjectReference)->type == NULL) {
+        /* FIXME: may also indicate an out-of-memory condition */
+        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, doc, node,
+                                      &(*managedObjectReference)->value) < 0) {
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_ManagedObjectReference_Free(managedObjectReference);
+
+    return -1;
+}
+
+/*
+ * VI Type: DynamicProperty
+ */
+
+ESX_VI__TEMPLATE__ALLOC(DynamicProperty, dynamicProperty);
+
+void
+esxVI_DynamicProperty_Free(esxVI_DynamicProperty **dynamicProperty)
+{
+    if (dynamicProperty == NULL || *dynamicProperty == NULL) {
+        return;
+    }
+
+    esxVI_DynamicProperty_Free(&(*dynamicProperty)->_next);
+
+    VIR_FREE((*dynamicProperty)->name);
+    esxVI_AnyType_Free(&(*dynamicProperty)->value);
+
+    VIR_FREE(*dynamicProperty);
+}
+
+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");
+        goto failure;
+    }
+
+    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)->value, src->value) < 0) {
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_DynamicProperty_Free(dest);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DEEP_COPY_LIST(DynamicProperty);
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(DynamicProperty, dynamicProperty);
+
+int
+esxVI_DynamicProperty_Deserialize(virConnectPtr conn,
+                                  xmlDocPtr doc, xmlNodePtr node,
+                                  esxVI_DynamicProperty **dynamicProperty)
+{
+    xmlNodePtr childNode = NULL;
+
+    if (dynamicProperty == NULL || *dynamicProperty != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_DynamicProperty_Alloc(conn, dynamicProperty) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "name")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*dynamicProperty)->name) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "val")) {
+            if (esxVI_AnyType_Deserialize(conn, doc, childNode,
+                                          &(*dynamicProperty)->value) < 0) {
+                goto failure;
+            }
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*dynamicProperty)->name == NULL || (*dynamicProperty)->value == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_DynamicProperty_Free(dynamicProperty);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(DynamicProperty, dynamicProperty);
+
+/*
+ * VI Type: SelectionSpec
+ */
+
+ESX_VI__TEMPLATE__ALLOC(SelectionSpec, 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);
+    }
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(SelectionSpec, selectionSpec);
+
+int
+esxVI_SelectionSpec_Serialize(virConnectPtr conn,
+                              esxVI_SelectionSpec *selectionSpec,
+                              const char *element, char **output,
+                              esxVI_Boolean required)
+{
+    int result = 0;
+    char *name = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (selectionSpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (selectionSpec->_super != NULL) {
+        return esxVI_TraversalSpec_Serialize(conn, selectionSpec->_super,
+                                             element, output, required);
+    }
+
+    if (esxVI_String_SerializeValue(conn, selectionSpec->name, "name", &name,
+                                    esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"SelectionSpec\">%s</%s>",
+                    element, name, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(name);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+ESX_VI__TEMPLATE__SERIALIZE_LIST(SelectionSpec, 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);
+}
+
+int
+esxVI_TraversalSpec_Serialize(virConnectPtr conn,
+                              esxVI_TraversalSpec *traversalSpec,
+                              const char *element, char **output,
+                              esxVI_Boolean required)
+{
+    int result = 0;
+    char *name = NULL;
+    char *type = NULL;
+    char *path = NULL;
+    char *skip = NULL;
+    char *selectSet = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (traversalSpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (esxVI_String_SerializeValue(conn, traversalSpec->_base->name, "name",
+                                    &name, esxVI_Boolean_False) < 0 ||
+        esxVI_String_SerializeValue(conn, traversalSpec->type, "type", &type,
+                                    esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, traversalSpec->path, "path", &path,
+                                    esxVI_Boolean_True) < 0 ||
+        esxVI_Boolean_Serialize(conn, traversalSpec->skip, "skip", &skip,
+                                esxVI_Boolean_False) < 0 ||
+        esxVI_SelectionSpec_SerializeList(conn, traversalSpec->selectSet,
+                                          "selectSet", &selectSet,
+                                          esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"TraversalSpec\">%s%s%s%s%s</%s>",
+                    element, name, type, path, skip, selectSet, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(name);
+    VIR_FREE(type);
+    VIR_FREE(path);
+    VIR_FREE(skip);
+    VIR_FREE(selectSet);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+/*
+ * VI Type: ObjectSpec
+ */
+
+ESX_VI__TEMPLATE__ALLOC(ObjectSpec, objectSpec);
+
+void
+esxVI_ObjectSpec_Free(esxVI_ObjectSpec **objectSpec)
+{
+    if (objectSpec == NULL || *objectSpec == NULL) {
+        return;
+    }
+
+    esxVI_ObjectSpec_Free(&(*objectSpec)->_next);
+
+    esxVI_ManagedObjectReference_Free(&(*objectSpec)->obj);
+    esxVI_SelectionSpec_Free(&(*objectSpec)->selectSet);
+
+    VIR_FREE(*objectSpec);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(ObjectSpec, objectSpec);
+
+int
+esxVI_ObjectSpec_Serialize(virConnectPtr conn,
+                           esxVI_ObjectSpec *objectSpec,
+                           const char *element, char **output,
+                           esxVI_Boolean required)
+{
+    int result = 0;
+    char *obj = NULL;
+    char *skip = NULL;
+    char *selectSet = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (objectSpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, objectSpec->obj, "obj",
+                                               &obj, esxVI_Boolean_True) < 0 ||
+        esxVI_Boolean_Serialize(conn, objectSpec->skip, "skip", &skip,
+                                esxVI_Boolean_False) < 0 ||
+        esxVI_SelectionSpec_SerializeList(conn, objectSpec->selectSet,
+                                          "selectSet", &selectSet,
+                                          esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"ObjectSpec\">%s%s%s</%s>",
+                    element, obj, skip, selectSet, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(obj);
+    VIR_FREE(skip);
+    VIR_FREE(selectSet);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+ESX_VI__TEMPLATE__SERIALIZE_LIST(ObjectSpec, objectSpec);
+
+/*
+ * VI Type: PropertyChange
+ */
+
+ESX_VI__TEMPLATE__ALLOC(PropertyChange, propertyChange);
+
+void
+esxVI_PropertyChange_Free(esxVI_PropertyChange **propertyChange)
+{
+    if (propertyChange == NULL || *propertyChange == NULL) {
+        return;
+    }
+
+    esxVI_PropertyChange_Free(&(*propertyChange)->_next);
+
+    VIR_FREE((*propertyChange)->name);
+    esxVI_AnyType_Free(&(*propertyChange)->val);
+
+    VIR_FREE(*propertyChange);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(PropertyChange, propertyChange);
+
+int
+esxVI_PropertyChange_Deserialize(virConnectPtr conn,
+                                 xmlDocPtr doc, xmlNodePtr node,
+                                 esxVI_PropertyChange **propertyChange)
+{
+    xmlNodePtr childNode = NULL;
+
+    if (propertyChange == NULL || *propertyChange != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_PropertyChange_Alloc(conn, propertyChange) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "name")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*propertyChange)->name) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "op")) {
+            if (esxVI_PropertyChangeOp_Deserialize(conn, doc, childNode,
+                                                   &(*propertyChange)->op) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "val")) {
+            if (esxVI_AnyType_Deserialize(conn, doc, childNode,
+                                          &(*propertyChange)->val) < 0) {
+                goto failure;
+            }
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*propertyChange)->name == NULL ||
+        (*propertyChange)->op == esxVI_PropertyChangeOp_Undefined) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_PropertyChange_Free(propertyChange);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(PropertyChange, propertyChange);
+
+/*
+ * VI Type: PropertySpec
+ */
+
+ESX_VI__TEMPLATE__ALLOC(PropertySpec, propertySpec);
+
+void
+esxVI_PropertySpec_Free(esxVI_PropertySpec **propertySpec)
+{
+    if (propertySpec == NULL || *propertySpec == NULL) {
+        return;
+    }
+
+    esxVI_PropertySpec_Free(&(*propertySpec)->_next);
+
+    VIR_FREE((*propertySpec)->type);
+    esxVI_String_Free(&(*propertySpec)->pathSet);
+
+    VIR_FREE(*propertySpec);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(PropertySpec, propertySpec);
+
+int
+esxVI_PropertySpec_Serialize(virConnectPtr conn,
+                             esxVI_PropertySpec *propertySpec,
+                             const char *element, char **output,
+                             esxVI_Boolean required)
+{
+    int result = 0;
+    char *type = NULL;
+    char *all = NULL;
+    char *pathSet = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (propertySpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (esxVI_String_SerializeValue(conn, propertySpec->type, "type", &type,
+                                    esxVI_Boolean_True) < 0 ||
+        esxVI_Boolean_Serialize(conn, propertySpec->all, "all", &all,
+                                esxVI_Boolean_False) < 0 ||
+        esxVI_String_SerializeList(conn, propertySpec->pathSet, "pathSet",
+                                   &pathSet, esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"PropertySpec\">%s%s%s</%s>",
+                    element, type, all, pathSet, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(type);
+    VIR_FREE(all);
+    VIR_FREE(pathSet);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+ESX_VI__TEMPLATE__SERIALIZE_LIST(PropertySpec, propertySpec);
+
+/*
+ * VI Type: PropertyFilterSpec
+ */
+
+ESX_VI__TEMPLATE__ALLOC(PropertyFilterSpec, propertyFilterSpec);
+
+void
+
+esxVI_PropertyFilterSpec_Free(esxVI_PropertyFilterSpec **propertyFilterSpec)
+{
+    if (propertyFilterSpec == NULL || *propertyFilterSpec == NULL) {
+        return;
+    }
+
+    esxVI_PropertyFilterSpec_Free(&(*propertyFilterSpec)->_next);
+
+    esxVI_PropertySpec_Free(&(*propertyFilterSpec)->propSet);
+    esxVI_ObjectSpec_Free(&(*propertyFilterSpec)->objectSet);
+
+    VIR_FREE(*propertyFilterSpec);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(PropertyFilterSpec, propertyFilterSpec);
+
+int
+esxVI_PropertyFilterSpec_Serialize(virConnectPtr conn,
+                                   esxVI_PropertyFilterSpec *propertyFilterSpec,
+                                   const char *element, char **output,
+                                   esxVI_Boolean required)
+{
+    int result = 0;
+    char *propSet = NULL;
+    char *objectSet = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (propertyFilterSpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (esxVI_PropertySpec_SerializeList(conn, propertyFilterSpec->propSet,
+                                         "propSet", &propSet,
+                                         esxVI_Boolean_True) < 0 ||
+        esxVI_ObjectSpec_SerializeList(conn, propertyFilterSpec->objectSet,
+                                       "objectSet", &objectSet,
+                                       esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"PropertyFilterSpec\">%s%s</%s>",
+                    element, propSet, objectSet, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(propSet);
+    VIR_FREE(objectSet);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+ESX_VI__TEMPLATE__SERIALIZE_LIST(PropertyFilterSpec, propertyFilterSpec);
+
+/*
+ * VI Type: ObjectContent
+ */
+
+ESX_VI__TEMPLATE__ALLOC(ObjectContent, objectContent);
+
+void
+esxVI_ObjectContent_Free(esxVI_ObjectContent **objectContent)
+{
+    if (objectContent == NULL || *objectContent == NULL) {
+        return;
+    }
+
+    esxVI_ObjectContent_Free(&(*objectContent)->_next);
+
+    esxVI_ManagedObjectReference_Free(&(*objectContent)->obj);
+    esxVI_DynamicProperty_Free(&(*objectContent)->propSet);
+    /*esxVI_MissingProperty_Free (&(*objectContent)->missingSet); *//* FIXME */
+
+    VIR_FREE(*objectContent);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(ObjectContent, 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");
+        goto failure;
+    }
+
+    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;
+}
+
+int
+esxVI_ObjectContent_Deserialize(virConnectPtr conn,
+                                xmlDocPtr doc, xmlNodePtr node,
+                                esxVI_ObjectContent **objectContent)
+{
+    xmlNodePtr childNode = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+
+    if (objectContent == NULL || *objectContent != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_ObjectContent_Alloc(conn, objectContent) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "obj")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*objectContent)-> obj,
+                                                         NULL) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "propSet")) {
+            dynamicProperty = NULL;
+
+            if (esxVI_DynamicProperty_Deserialize(conn, doc, childNode,
+                                                  &dynamicProperty) < 0 ||
+                esxVI_DynamicProperty_AppendToList(conn,
+                                                   &(*objectContent)->propSet,
+                                                   dynamicProperty) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "missingSet")) {
+            /* FIXME */
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*objectContent)->obj == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing 'obj' property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_ObjectContent_Free(objectContent);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(ObjectContent, objectContent);
+
+/*
+ * VI Type: ObjectUpdate
+ */
+
+ESX_VI__TEMPLATE__ALLOC(ObjectUpdate, objectUpdate);
+
+void
+esxVI_ObjectUpdate_Free(esxVI_ObjectUpdate **objectUpdate)
+{
+    if (objectUpdate == NULL || *objectUpdate == NULL) {
+        return;
+    }
+
+    esxVI_ObjectUpdate_Free(&(*objectUpdate)->_next);
+
+    esxVI_ManagedObjectReference_Free(&(*objectUpdate)->obj);
+    esxVI_PropertyChange_Free(&(*objectUpdate)->changeSet);
+    /*esxVI_MissingProperty_Free (&(*objectUpdate)->missingSet); *//* FIXME */
+
+    VIR_FREE(*objectUpdate);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(ObjectUpdate, objectUpdate);
+
+int
+esxVI_ObjectUpdate_Deserialize(virConnectPtr conn,
+                               xmlDocPtr doc, xmlNodePtr node,
+                               esxVI_ObjectUpdate **objectUpdate)
+{
+    xmlNodePtr childNode = NULL;
+    esxVI_PropertyChange *propertyChange = NULL;
+
+    if (objectUpdate == NULL || *objectUpdate != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_ObjectUpdate_Alloc(conn, objectUpdate) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "kind")) {
+            if (esxVI_ObjectUpdateKind_Deserialize(conn, doc, childNode,
+                                                   &(*objectUpdate)->kind) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "obj")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*objectUpdate)->obj,
+                                                         NULL) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "changeSet")) {
+            propertyChange = NULL;
+
+            if (esxVI_PropertyChange_Deserialize(conn, doc, childNode,
+                                                 &propertyChange) < 0 ||
+                esxVI_PropertyChange_AppendToList(conn,
+                                                  &(*objectUpdate)->changeSet,
+                                                  propertyChange) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "missingSet")) {
+            /* FIXME */
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*objectUpdate)->obj == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing 'obj' property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_ObjectUpdate_Free(objectUpdate);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(ObjectUpdate, objectUpdate);
+
+/*
+ * VI Type: PropertyFilterUpdate
+ */
+
+ESX_VI__TEMPLATE__ALLOC(PropertyFilterUpdate, propertyFilterUpdate);
+
+void
+esxVI_PropertyFilterUpdate_Free(esxVI_PropertyFilterUpdate **propertyFilterUpdate)
+{
+    if (propertyFilterUpdate == NULL || *propertyFilterUpdate == NULL) {
+        return;
+    }
+
+    esxVI_PropertyFilterUpdate_Free(&(*propertyFilterUpdate)->_next);
+
+    esxVI_ManagedObjectReference_Free(&(*propertyFilterUpdate)->filter);
+    esxVI_ObjectUpdate_Free(&(*propertyFilterUpdate)->objectSet);
+    /*esxVI_MissingProperty_Free (&(*propertyFilterUpdate)->missingSet); *//* FIXME */
+
+    VIR_FREE(*propertyFilterUpdate);
+}
+
+ESX_VI__TEMPLATE__APPEND_TO_LIST(PropertyFilterUpdate, propertyFilterUpdate);
+
+int
+esxVI_PropertyFilterUpdate_Deserialize(virConnectPtr conn,
+                                       xmlDocPtr doc, xmlNodePtr node,
+                                       esxVI_PropertyFilterUpdate **propertyFilterUpdate)
+{
+    xmlNodePtr childNode = NULL;
+    esxVI_ObjectUpdate *objectUpdate = NULL;
+
+    if (propertyFilterUpdate == NULL || *propertyFilterUpdate != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_PropertyFilterUpdate_Alloc(conn, propertyFilterUpdate) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "filter")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*propertyFilterUpdate)->filter,
+                                                         NULL) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "objectSet")) {
+            objectUpdate = NULL;
+
+            if (esxVI_ObjectUpdate_Deserialize(conn, doc, childNode,
+                                               &objectUpdate) < 0 ||
+                esxVI_ObjectUpdate_AppendToList(conn, &(*propertyFilterUpdate)->objectSet,
+                                                objectUpdate) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "missingSet")) {
+            /* FIXME */
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*propertyFilterUpdate)->filter == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Missing 'filter' property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_PropertyFilterUpdate_Free(propertyFilterUpdate);
+
+    return -1;
+}
+
+ESX_VI__TEMPLATE__DESERIALIZE_LIST(PropertyFilterUpdate, propertyFilterUpdate);
+
+/*
+ * VI Type: AboutInfo
+ */
+
+ESX_VI__TEMPLATE__ALLOC(AboutInfo, aboutInfo);
+
+void
+esxVI_AboutInfo_Free(esxVI_AboutInfo **aboutInfo)
+{
+    if (aboutInfo == NULL || *aboutInfo == NULL) {
+        return;
+    }
+
+    VIR_FREE((*aboutInfo)->name);
+    VIR_FREE((*aboutInfo)->fullName);
+    VIR_FREE((*aboutInfo)->vendor);
+    VIR_FREE((*aboutInfo)->version);
+    VIR_FREE((*aboutInfo)->build);
+    VIR_FREE((*aboutInfo)->localeVersion);
+    VIR_FREE((*aboutInfo)->localeBuild);
+    VIR_FREE((*aboutInfo)->osType);
+    VIR_FREE((*aboutInfo)->productLineId);
+    VIR_FREE((*aboutInfo)->apiType);
+    VIR_FREE((*aboutInfo)->apiVersion);
+
+    VIR_FREE(*aboutInfo);
+}
+
+int
+esxVI_AboutInfo_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                            esxVI_AboutInfo **aboutInfo)
+{
+    xmlNodePtr childNode = NULL;
+
+    if (aboutInfo == NULL || *aboutInfo != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_AboutInfo_Alloc(conn, aboutInfo) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "name")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->name)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "fullName")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->fullName)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "vendor")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->vendor)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "version")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->version)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "build")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->build)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "localeVersion")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->localeVersion)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "localeBuild")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->localeBuild)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "osType")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->osType)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "productLineId")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->productLineId)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "apiType")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->apiType)) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "apiVersion")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*aboutInfo)->apiVersion)) {
+                goto failure;
+            }
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*aboutInfo)->name == NULL ||
+        (*aboutInfo)->fullName == NULL ||
+        (*aboutInfo)->vendor == NULL ||
+        (*aboutInfo)->version == NULL ||
+        (*aboutInfo)->build == NULL ||
+        (*aboutInfo)->localeVersion == NULL ||
+        (*aboutInfo)->localeBuild == NULL ||
+        (*aboutInfo)->osType == NULL ||
+        (*aboutInfo)->productLineId == NULL ||
+        (*aboutInfo)->apiType == NULL ||
+        (*aboutInfo)->apiVersion == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_AboutInfo_Free(aboutInfo);
+
+    return -1;
+}
+
+/*
+ * VI Type: ServiceContent
+ */
+
+ESX_VI__TEMPLATE__ALLOC(ServiceContent, serviceContent);
+
+void
+esxVI_ServiceContent_Free(esxVI_ServiceContent **serviceContent)
+{
+    if (serviceContent == NULL || *serviceContent == NULL) {
+        return;
+    }
+
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->rootFolder);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->propertyCollector);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->viewManager);
+    esxVI_AboutInfo_Free(&(*serviceContent)->about);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->setting);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->userDirectory);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->sessionManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->authorizationManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->perfManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->scheduledTaskManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->alarmManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->eventManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->taskManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->extensionManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->customizationSpecManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->customFieldsManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->accountManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->diagnosticManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->licenseManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->searchIndex);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->fileManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->virtualDiskManager);
+    esxVI_ManagedObjectReference_Free(&(*serviceContent)->virtualizationManager);
+
+    VIR_FREE(*serviceContent);
+}
+
+int
+esxVI_ServiceContent_Deserialize(virConnectPtr conn,
+                                 xmlDocPtr doc, xmlNodePtr node,
+                                 esxVI_ServiceContent **serviceContent)
+{
+    xmlNodePtr childNode = NULL;
+
+    if (serviceContent == NULL || *serviceContent != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_ServiceContent_Alloc(conn, serviceContent) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "rootFolder")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->rootFolder,
+                                                         "Folder") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "propertyCollector")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->propertyCollector,
+                                                         "PropertyCollector") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "viewManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->viewManager,
+                                                         "ViewManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "about")) {
+            if (esxVI_AboutInfo_Deserialize(conn, doc, childNode,
+                                            &(*serviceContent)->about) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "setting")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->setting,
+                                                         "OptionManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "userDirectory")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->userDirectory,
+                                                         "UserDirectory") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "sessionManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->sessionManager,
+                                                         "SessionManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "authorizationManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->authorizationManager,
+                                                         "AuthorizationManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "perfManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->perfManager,
+                                                         "PerformanceManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "scheduledTaskManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->scheduledTaskManager,
+                                                         "ScheduledTaskManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "alarmManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->alarmManager,
+                                                         "AlarmManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "eventManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->eventManager,
+                                                         "EventManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "taskManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->taskManager,
+                                                         "TaskManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "extensionManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->extensionManager,
+                                                         "ExtensionManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "customizationSpecManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->customizationSpecManager,
+                                                        "CustomizationSpecManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "customFieldsManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->customFieldsManager,
+                                                         "CustomFieldsManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "accountManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->accountManager,
+                                                         "HostLocalAccountManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "diagnosticManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->diagnosticManager,
+                                                         "DiagnosticManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "licenseManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->licenseManager,
+                                                         "LicenseManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "searchIndex")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->searchIndex,
+                                                         "SearchIndex") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "fileManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->fileManager,
+                                                         "FileManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "virtualDiskManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->virtualDiskManager,
+                                                         "VirtualDiskManager") < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "virtualizationManager")) {
+            if (esxVI_ManagedObjectReference_Deserialize(conn, doc, childNode,
+                                                         &(*serviceContent)->virtualizationManager,
+                                                         "VirtualizationManager") < 0) {
+                goto failure;
+            }
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*serviceContent)->rootFolder == NULL ||
+        (*serviceContent)->propertyCollector == NULL ||
+        (*serviceContent)->about == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Missing property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_ServiceContent_Free(serviceContent);
+
+    return -1;
+}
+
+/*
+ * VI Type: UpdateSet
+ */
+
+ESX_VI__TEMPLATE__ALLOC(UpdateSet, updateSet);
+
+void
+esxVI_UpdateSet_Free(esxVI_UpdateSet **updateSet)
+{
+    if (updateSet == NULL || *updateSet == NULL) {
+        return;
+    }
+
+    VIR_FREE((*updateSet)->version);
+    esxVI_PropertyFilterUpdate_Free(&(*updateSet)->filterSet);
+
+    VIR_FREE(*updateSet);
+}
+
+int
+esxVI_UpdateSet_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                            esxVI_UpdateSet **updateSet)
+{
+    xmlNodePtr childNode = NULL;
+    esxVI_PropertyFilterUpdate *propertyFilterUpdate = NULL;
+
+    if (updateSet == NULL || *updateSet != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_UpdateSet_Alloc(conn, updateSet) < 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;
+        }
+
+        if (xmlStrEqual(childNode->name, BAD_CAST "version")) {
+            if (esxVI_String_DeserializeValue(conn, doc, childNode,
+                                              &(*updateSet)->version) < 0) {
+                goto failure;
+            }
+        } else if (xmlStrEqual(childNode->name, BAD_CAST "filterSet")) {
+            propertyFilterUpdate = NULL;
+
+            if (esxVI_PropertyFilterUpdate_Deserialize(conn, doc, childNode,
+                                                       &propertyFilterUpdate) < 0 ||
+                esxVI_PropertyFilterUpdate_AppendToList(conn, &(*updateSet)->filterSet,
+                                                        propertyFilterUpdate) < 0) {
+                goto failure;
+            }
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Unknown '%s' property", childNode->name);
+            goto failure;
+        }
+    }
+
+    if ((*updateSet)->version == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Missing 'version' property");
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_UpdateSet_Free(updateSet);
+
+    return -1;
+}
+
+/*
+ * VI Type: VirtualMachineConfigSpec
+ */
+
+ESX_VI__TEMPLATE__ALLOC(VirtualMachineConfigSpec, virtualMachineConfigSpec);
+
+void
+
+esxVI_VirtualMachineConfigSpec_Free(esxVI_VirtualMachineConfigSpec **virtualMachineConfigSpec)
+{
+    if (virtualMachineConfigSpec == NULL || *virtualMachineConfigSpec == NULL) {
+        return;
+    }
+
+    /* FIXME: implement the rest */
+    esxVI_Int_Free(&(*virtualMachineConfigSpec)->numCPUs);
+
+    VIR_FREE(*virtualMachineConfigSpec);
+}
+
+int
+esxVI_VirtualMachineConfigSpec_Serialize(virConnectPtr conn,
+                                         esxVI_VirtualMachineConfigSpec *virtualMachineConfigSpec,
+                                         const char *element, char **output,
+                                         esxVI_Boolean required)
+{
+    int result = 0;
+    char *numCPUs = NULL;
+
+    if (element == NULL || output == NULL || *output != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (virtualMachineConfigSpec == NULL) {
+        return _esxVI_CheckSerializationNecessity(conn, element, output,
+                                                  required);
+    }
+
+    if (esxVI_Int_Serialize(conn, virtualMachineConfigSpec->numCPUs,
+                            "numCPUs", &numCPUs, esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(output, "<%s xmlns=\"urn:vim25\" xsi:type=\"VirtualMachineConfigSpec\">%s</%s>",
+                    element, numCPUs, element) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(numCPUs);
+
+    return result;
+
+  failure:
+    VIR_FREE(*output);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+/*
+ * VI Methods
+ */
+
+#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>"
+
+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 (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0) {
+        goto failure;
+    }
+
+    remoteRequest->request = _esxVI_RetrieveServiceContentRequest;
+    remoteRequest->xpathExpression =
+        "/soapenv:Envelope/soapenv:Body/vim:RetrieveServiceContentResponse/vim:returnval";
+
+    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:
+    if (remoteRequest != NULL) {
+        remoteRequest->request = NULL;
+        remoteRequest->xpathExpression = NULL;
+    }
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_LoginRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<Login xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to SessionManager */
+    "%s" /* userName */
+    "%s" /* password */
+  "</Login>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_Login(virConnectPtr conn, esxVI_Context *ctx,
+            const char *userName , const char *password )
+{
+    int result = 0;
+    esxVI_RemoteRequest *remoteRequest = NULL;
+    esxVI_RemoteResponse *remoteResponse = NULL;
+    char *_this = NULL;
+    char *userName_ = NULL;
+    char *password_ = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn,
+                                               ctx->service->sessionManager,
+                                               "_this", &_this,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, userName, "userName", &userName_,
+                                    esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, password, "password", &password_,
+                                    esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request, _esxVI_LoginRequest,
+                    _this, userName_, password_) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(userName_);
+    VIR_FREE(password_);
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_LogoutRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<Logout xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to SessionManager */
+  "</Logout>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_Logout(virConnectPtr conn, esxVI_Context *ctx)
+{
+    int result = 0;
+    esxVI_RemoteRequest *remoteRequest = NULL;
+    esxVI_RemoteResponse *remoteResponse = NULL;
+    char *_this = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn,
+                                               ctx->service->sessionManager,
+                                               "_this", &_this,
+                                               esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request, _esxVI_LogoutRequest,
+                    _this) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_RetrievePropertiesRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<RetrieveProperties xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to PropertyCollector */
+    "%s" /* specSet = PropertyFilterSpec List */
+  "</RetrieveProperties>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+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;
+    char *_this = NULL;
+    char *specSet = NULL;
+    xmlNodePtr node = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn,
+                                               ctx->service->propertyCollector,
+                                               "_this", &_this,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_PropertyFilterSpec_SerializeList(conn, propertyFilterSpecList,
+                                               "specSet", &specSet,
+                                               esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request,
+                    _esxVI_RetrievePropertiesRequest, _this, specSet) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    remoteRequest->xpathExpression =
+        "/soapenv:Envelope/soapenv:Body/vim:RetrievePropertiesResponse/vim:returnval";
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0) {
+        goto failure;
+    }
+
+    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);
+                goto failure;
+            }
+        } else {
+            node = NULL;
+        }
+
+        if (esxVI_ObjectContent_DeserializeList(conn, remoteResponse->document,
+                                                node, objectContentList) < 0) {
+            goto failure;
+        }
+    } else {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "XPath error");
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(specSet);
+
+    if (remoteRequest != NULL) {
+        remoteRequest->xpathExpression = NULL;
+    }
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    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);
+}
+
+static const char *_esxVI_MigrateVMRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<MigrateVM_Task xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference VirtualMachine */
+    "%s" /* pool = ManagedObjectReference ResourcePool */
+    "%s" /* host = ManagedObjectReference HostSystem */
+    "%s" /* priority = VirtualMachineMovePriority */
+  "</MigrateVM_Task>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_MigrateVM_Task(virConnectPtr conn, esxVI_Context *ctx,
+                     esxVI_ManagedObjectReference *virtualMachine,
+                     esxVI_ManagedObjectReference *resourcePool,
+                     esxVI_ManagedObjectReference *hostSystem,
+                     esxVI_ManagedObjectReference **task)
+{
+    int result = 0;
+    char *_this = NULL;
+    char *pool = NULL;
+    char *host = NULL;
+    char *priority = NULL;
+    char *request = NULL;
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this",
+                                               &_this, esxVI_Boolean_True) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn, resourcePool, "pool",
+                                               &pool, esxVI_Boolean_True) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn, hostSystem, "host", &host,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_VirtualMachineMovePriority_Serialize(conn, esxVI_VirtualMachineMovePriority_DefaultPriority,
+                                                   "priority", &priority,
+                                                   esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(&request, _esxVI_MigrateVMRequest, _this, pool, host,
+                    priority) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_StartVirtualMachineTask(conn, ctx, "MigrateVM", request,
+                                      task) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(pool);
+    VIR_FREE(host);
+    VIR_FREE(priority);
+    VIR_FREE(request);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_ReconfigVMRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<ReconfigVM_Task xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to VirtualMachine */
+    "%s" /* spec = VirtualMachineConfigSpec */
+  "</ReconfigVM_Task>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_ReconfigVM_Task(virConnectPtr conn, esxVI_Context *ctx,
+                      esxVI_ManagedObjectReference *virtualMachine,
+                      esxVI_VirtualMachineConfigSpec *spec,
+                      esxVI_ManagedObjectReference **task)
+{
+    int result = 0;
+    char *_this = NULL;
+    char *spec_ = NULL;
+    char *request = NULL;
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this",
+                                               &_this, esxVI_Boolean_True) < 0 ||
+        esxVI_VirtualMachineConfigSpec_Serialize(conn, spec, "spec", &spec_,
+                                                 esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(&request, _esxVI_ReconfigVMRequest, _this, spec_) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_StartVirtualMachineTask(conn, ctx, "ReconfigVM", request,
+                                      task) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(spec_);
+    VIR_FREE(request);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_CreateFilterRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<CreateFilter xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to PropertyCollector */
+    "%s" /* spec = PropertyFilterSpec List */
+    "%s" /* partialUpdates */
+  "</CreateFilter>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+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;
+    char *_this = NULL;
+    char *spec = NULL;
+    char *partialUpdates_ = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn, ctx->service->propertyCollector,
+                                               "_this", &_this,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_PropertyFilterSpec_Serialize(conn, propertyFilterSpec, "spec",
+                                           &spec, esxVI_Boolean_True) < 0 ||
+        esxVI_Boolean_Serialize(conn, partialUpdates, "partialUpdates",
+                                &partialUpdates_, esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request,
+                    _esxVI_CreateFilterRequest, _this, spec,
+                    partialUpdates_) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    remoteRequest->xpathExpression =
+        "/soapenv:Envelope/soapenv:Body/vim:CreateFilterResponse/vim:returnval";
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0 ||
+        esxVI_RemoteResponse_DeserializeXPathObjectAsManagedObjectReference
+        (conn, remoteResponse, propertyFilter, "PropertyFilter") < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(spec);
+    VIR_FREE(partialUpdates_);
+
+    if (remoteRequest != NULL) {
+        remoteRequest->xpathExpression = NULL;
+    }
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_DestroyPropertyFilterRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<DestroyPropertyFilter xmlns=\"urn:vim25\">"
+    "%s"
+  "</DestroyPropertyFilter>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_DestroyPropertyFilter(virConnectPtr conn, esxVI_Context *ctx,
+                            esxVI_ManagedObjectReference *propertyFilter)
+{
+    int result = 0;
+    esxVI_RemoteRequest *remoteRequest = NULL;
+    esxVI_RemoteResponse *remoteResponse = NULL;
+    char *_this = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn, propertyFilter, "_this",
+                                               &_this, esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request,
+                    _esxVI_DestroyPropertyFilterRequest, _this) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_WaitForUpdatesRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<WaitForUpdates xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to PropertyCollector */
+    "%s" /* version */
+  "</WaitForUpdates>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+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;
+    char *_this = NULL;
+    char *version_ = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn,
+                                               ctx->service->propertyCollector,
+                                               "_this", &_this,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, version, "version", &version_,
+                                    esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request,
+                    _esxVI_WaitForUpdatesRequest, _this, version_) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    remoteRequest->xpathExpression =
+        "/soapenv:Envelope/soapenv:Body/vim:WaitForUpdatesResponse/vim:returnval";
+
+    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:
+    VIR_FREE(_this);
+    VIR_FREE(version_);
+
+    if (remoteRequest != NULL) {
+        remoteRequest->xpathExpression = NULL;
+    }
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_RebootGuestRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<RebootGuest xmlns=\"urn:vim25\">"
+    "%s" /* _this = ManagedObjectReference to VirtualMachine */
+  "</RebootGuest>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_RebootGuest(virConnectPtr conn, esxVI_Context *ctx,
+                  esxVI_ManagedObjectReference *virtualMachine)
+{
+    int result = 0;
+    esxVI_RemoteRequest *remoteRequest = NULL;
+    esxVI_RemoteResponse *remoteResponse = NULL;
+    char *_this = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Alloc(conn, &remoteRequest) < 0 ||
+        esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this",
+                                               &_this,
+                                               esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf((char **) &remoteRequest->request,
+                    _esxVI_RebootGuestRequest, _this) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_RemoteRequest_Execute(conn, ctx, remoteRequest,
+                                    &remoteResponse) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+/*
+ * Utility and Convenience Methods
+ */
+
+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");
+        goto failure;
+    }
+
+    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"
+                                        "dcToVmf\0"
+                                        "dcToHf\0"
+                                        "crToH\0"
+                                        "crToRp\0"
+                                        "HToVm\0"
+                                        "rpToVm\0") < 0) {
+        goto failure;
+    }
+
+    /* Traversal through vmFolder branch */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "dcToVmf",
+                                         "Datacenter", "vmFolder",
+                                         "visitFolders\0") < 0) {
+        goto failure;
+    }
+
+    /* Traversal through hostFolder branch  */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "dcToHf",
+                                         "Datacenter", "hostFolder",
+                                         "visitFolders\0") < 0) {
+        goto failure;
+    }
+
+    /* Traversal through host branch  */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "crToH",
+                                         "ComputeResource", "host",
+                                         NULL) < 0) {
+        goto failure;
+    }
+
+    /* Traversal through resourcePool branch */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "crToRp",
+                                         "ComputeResource", "resourcePool",
+                                         "rpToRp\0"
+                                         "rpToVm\0") < 0) {
+        goto failure;
+    }
+
+    /* Recurse through all resource pools */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "rpToRp",
+                                         "ResourcePool", "resourcePool",
+                                         "rpToRp\0"
+                                         "rpToVm\0") < 0) {
+        goto failure;
+    }
+
+    /* Recurse through all hosts */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "HToVm",
+                                         "HostSystem", "vm",
+                                         "visitFolders\0") < 0) {
+        goto failure;
+    }
+
+    /* Recurse through all resource pools */
+    if (esxVI_BuildFullTraversalSpecItem(conn, fullTraversalSpecList, "rpToVm",
+                                         "ResourcePool", "vm", NULL) < 0) {
+        goto failure;
+    }
+
+    return 0;
+
+  failure:
+    esxVI_SelectionSpec_Free(fullTraversalSpecList);
+
+    return -1;
+}
+
+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 argument");
+        goto failure;
+    }
+
+    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 = 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 beeing 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->value, powerState);
+        }
+    }
+
+    ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                 "Missing 'runtime.powerState' property");
+
+    return -1;
+}
+
+int
+esxVI_NumOfDomainsByPowerState(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 numOfDomains = 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->value,
+                                                                   &powerState_) < 0) {
+                    goto failure;
+                }
+
+                if ((inverse != esxVI_Boolean_True
+                     && powerState_ == powerState)
+                    || (inverse == esxVI_Boolean_True
+                        && powerState_ != powerState)) {
+                    numOfDomains++;
+                }
+            }
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&virtualMachineList);
+
+    return numOfDomains;
+
+  failure:
+    numOfDomains = -1;
+
+    goto cleanup;
+}
+
+int
+esxVI_GetVirtualMachineIdentity(virConnectPtr conn,
+                                esxVI_ObjectContent *virtualMachine,
+                                int *id,
+                                const char **name, unsigned char *uuid)
+{
+    esxVI_Boolean foundName = esxVI_Boolean_False;
+    esxVI_Boolean foundUUID = esxVI_Boolean_False;
+    const char *id_string;
+    const char *uuid_string;
+    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) {
+        id_string = virtualMachine->obj->value;
+
+        if (esxUtil_ParseVirtualMachineIDString(id_string, id) < 0 || *id <= 0) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Could not parse positive integer from '%s'",
+                         id_string);
+            return -1;
+        }
+    }
+
+    if (name != NULL) {
+        if (*name != NULL) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+            return -1;
+        }
+
+        for (dynamicProperty = virtualMachine->propSet;
+             dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "name")) {
+                *name = esxUtil_Strdup(dynamicProperty->value->value);
+
+                if (*name == NULL) {
+                    virReportOOMError(conn);
+                    return -1;
+                }
+
+                foundName = esxVI_Boolean_True;
+                break;
+            }
+        }
+
+        if (foundName != esxVI_Boolean_True) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Could not get name of virtual machine");
+            return -1;
+        }
+    }
+
+    if (uuid != NULL) {
+        for (dynamicProperty = virtualMachine->propSet;
+             dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.config.uuid")) {
+                uuid_string = dynamicProperty->value->value;
+                foundUUID = esxVI_Boolean_True;
+                break;
+            }
+        }
+
+        if (foundUUID != esxVI_Boolean_True) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Could not get UUID of virtual machine");
+            return -1;
+        }
+
+        if (virUUIDParse(uuid_string, uuid) < 0) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Could not parse UUID from string '%s'", uuid_string);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int
+esxVI_LookupVirtualMachineByDomain(virConnectPtr conn, esxVI_Context *ctx,
+                                   virDomainPtr domain,
+                                   esxVI_String *propertyNameList,
+                                   esxVI_ObjectContent **virtualMachine)
+{
+    int result = 0;
+    esxVI_ObjectContent *virtualMachineList = NULL;
+    esxVI_ObjectContent *virtualMachine_ = NULL;
+    esxVI_String *completePropertyNameList = NULL;
+    const char *name = NULL;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+
+    if (virtualMachine == NULL || *virtualMachine != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (esxVI_String_DeepCopyList(conn, &completePropertyNameList,
+                                  propertyNameList) < 0 ||
+        esxVI_String_AppendValueListToList(conn, &completePropertyNameList,
+                                           "name\0"
+                                           "summary.config.uuid\0") < 0 ||
+        esxVI_GetObjectContent(conn, ctx, ctx->vmFolder, "VirtualMachine",
+                               completePropertyNameList, esxVI_Boolean_True,
+                               &virtualMachineList) < 0) {
+        goto failure;
+    }
+
+    for (virtualMachine_ = virtualMachineList; virtualMachine_ != NULL;
+         virtualMachine_ = virtualMachine_->_next) {
+        VIR_FREE(name);
+
+        if (esxVI_GetVirtualMachineIdentity(conn, virtualMachine_, NULL,
+                                            &name, uuid) < 0) {
+            goto failure;
+        }
+
+        /* Don't match by ID because the ID for a single virtual machine may be
+         * different between host and Virtual Center. Only match by name and UUID.
+         */
+        if (STRNEQ(name, domain->name)) {
+            continue;
+        }
+
+        if (memcmp(uuid, domain->uuid,
+                   VIR_UUID_BUFLEN * sizeof(unsigned char)) != 0) {
+            continue;
+        }
+
+        if (esxVI_ObjectContent_DeepCopy(conn, virtualMachine,
+                                         virtualMachine_) < 0) {
+            goto failure;
+        }
+
+        break;
+    }
+
+  cleanup:
+    esxVI_String_Free(&completePropertyNameList);
+    esxVI_ObjectContent_Free(&virtualMachineList);
+    VIR_FREE(name);
+
+    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 = request;
+
+    if (virAsprintf((char **) &remoteRequest->xpathExpression,
+                    "/soapenv:Envelope/soapenv:Body/vim:%s_TaskResponse/vim:returnval",
+                    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:
+    if (remoteRequest != NULL) {
+        remoteRequest->request = NULL;
+    }
+
+    esxVI_RemoteRequest_Free(&remoteRequest);
+    esxVI_RemoteResponse_Free(&remoteResponse);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+static const char *_esxVI_SimpleVirtualMachineRequest =
+ESX_VI_SOAP_REQUEST_HEADER
+  "<%s_Task xmlns=\"urn:vim25\">"
+    "%s"
+  "</%s_Task>"
+ESX_VI_SOAP_REQUEST_FOOTER;
+
+int
+esxVI_StartSimpleVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx,
+                                    const char *name,
+                                    esxVI_ManagedObjectReference *virtualMachine,
+                                    esxVI_ManagedObjectReference **task)
+{
+    int result = 0;
+    char *_this = NULL;
+    char *request = NULL;
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this",
+                                               &_this,
+                                               esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    if (virAsprintf(&request, _esxVI_SimpleVirtualMachineRequest, name,
+                    _this, name) < 0) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    if (esxVI_StartVirtualMachineTask(conn, ctx, name, request, task) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(_this);
+    VIR_FREE(request);
+
+    return result;
+
+  failure:
+    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;
+    const 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 = esxUtil_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 = esxUtil_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 beeing 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_vi.h b/src/esx_vi.h
new file mode 100644
index 0000000..52e5112
--- /dev/null
+++ b/src/esx_vi.h
@@ -0,0 +1,863 @@
+
+/*
+ * esx_vi.h: client for the VMware VI API 2.5 to manage ESX hosts
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias bolte googlemail com>
+ *
+ * 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 "threads.h"
+
+typedef struct _esxVI_Context esxVI_Context;
+typedef struct _esxVI_RemoteResponse esxVI_RemoteResponse;
+typedef struct _esxVI_RemoteRequest esxVI_RemoteRequest;
+typedef enum _esxVI_Boolean esxVI_Boolean;
+typedef struct _esxVI_List esxVI_List;
+typedef struct _esxVI_String esxVI_String;
+typedef struct _esxVI_Fault esxVI_Fault;
+typedef struct _esxVI_AnyType esxVI_AnyType;
+typedef enum _esxVI_ObjectUpdateKind esxVI_ObjectUpdateKind;
+typedef enum _esxVI_PropertyChangeOp esxVI_PropertyChangeOp;
+typedef enum _esxVI_TaskInfoState esxVI_TaskInfoState;
+typedef enum _esxVI_VirtualMachineMovePriority
+  esxVI_VirtualMachineMovePriority;
+typedef enum _esxVI_VirtualMachinePowerState esxVI_VirtualMachinePowerState;
+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_VirtualMachineConfigSpec esxVI_VirtualMachineConfigSpec;
+
+/*
+ * Context
+ */
+
+struct _esxVI_Context {
+    char *url;
+    CURL *curl_handle;
+    struct curl_slist *curl_headers;
+    virMutex curl_lock;
+    esxVI_ServiceContent *service;
+    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);
+
+/*
+ * Internal: RemoteRequest
+ */
+
+struct _esxVI_RemoteRequest {
+    const char *request;                              /* required */
+    const 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);
+
+/*
+ * Internal: RemoteResponse
+ */
+
+struct _esxVI_RemoteResponse {
+    long code;                                        /* required */
+    char error[CURL_ERROR_SIZE];                      /* optional */
+    const char *response;                             /* required */
+    xmlDocPtr document;                               /* optional */
+    xmlXPathContextPtr xpathContext;                  /* optional */
+    xmlXPathObjectPtr xpathObject;                    /* optional */
+};
+
+typedef int (*esxVI_RemoteResponse_DeserializeFunc) (virConnectPtr conn,
+                                                     xmlDocPtr doc,
+                                                     xmlNodePtr node,
+                                                     void **item);
+
+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_DeserializeXPathObjectAsManagedObjectReference
+    (virConnectPtr conn, esxVI_RemoteResponse *remoteResponse,
+     esxVI_ManagedObjectReference **managedObjectReference,
+     const char *expectedType);
+
+/*
+ * 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, char **output,
+                            esxVI_Boolean required);
+
+/*
+ * Internal: 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, char **output,
+                                         esxVI_Boolean required);
+typedef int (*esxVI_List_DeserializeFunc) (virConnectPtr conn, xmlDocPtr doc,
+                                           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, char **output,
+                         esxVI_Boolean required,
+                         esxVI_List_SerializeFunc serializeFunc);
+int esxVI_List_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                           esxVI_List **list,
+                           esxVI_List_DeserializeFunc deserializeFunc,
+                           esxVI_List_FreeFunc freeFunc);
+
+/*
+ * XSD: String
+ */
+
+struct _esxVI_String {
+    esxVI_String *_next;                              /* optional */
+
+    const char *value;                                /* required */
+};
+
+int esxVI_String_Alloc(virConnectPtr conn, esxVI_String **string);
+void esxVI_String_Free(esxVI_String **string);
+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, const char **dest,
+                               const char *src);
+int esxVI_String_Serialize(virConnectPtr conn, esxVI_String *string,
+                           const char *element, char **output,
+                           esxVI_Boolean required);
+int esxVI_String_SerializeList(virConnectPtr conn, esxVI_String *stringList,
+                               const char *element, char **output,
+                               esxVI_Boolean required);
+int esxVI_String_SerializeValue(virConnectPtr conn, const char *value,
+                                const char *element, char **output,
+                                esxVI_Boolean required);
+int esxVI_String_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                             xmlNodePtr node, esxVI_String **string);
+int esxVI_String_DeserializeList(virConnectPtr conn, xmlDocPtr doc,
+                                 xmlNodePtr node, esxVI_String **stringList);
+int esxVI_String_DeserializeValue(virConnectPtr conn, xmlDocPtr doc,
+                                  xmlNodePtr node, const char **value);
+
+/*
+ * VI Type: Fault
+ */
+
+struct _esxVI_Fault {
+    const char *code;                                 /* required */
+    const char *string;                               /* required */
+};
+
+int esxVI_Fault_Alloc(virConnectPtr conn, esxVI_Fault **fault);
+void esxVI_Fault_Free(esxVI_Fault **fault);
+int esxVI_Fault_Deserialize(virConnectPtr conn, xmlDocPtr doc, xmlNodePtr node,
+                            esxVI_Fault **fault);
+
+/*
+ * XSD: AnyType
+ */
+
+struct _esxVI_AnyType {
+    xmlNodePtr _node;                                 /* required */
+
+    const char *type;                                 /* required */
+    const char *value;                                /* required */
+};
+
+int esxVI_AnyType_Alloc(virConnectPtr conn, esxVI_AnyType **anyType);
+void esxVI_AnyType_Free(esxVI_AnyType **anyType);
+int esxVI_AnyType_DeepCopy(virConnectPtr conn, esxVI_AnyType **dest,
+                           esxVI_AnyType *src);
+int esxVI_AnyType_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                              xmlNodePtr node, esxVI_AnyType **anyType);
+
+/*
+ * XSD: Int
+ */
+
+typedef struct _esxVI_Int {
+    int value;                                        /* required */
+} esxVI_Int;
+
+int esxVI_Int_Alloc(virConnectPtr conn, esxVI_Int ** integer);
+void esxVI_Int_Free(esxVI_Int ** integer);
+int esxVI_Int_Serialize(virConnectPtr conn, esxVI_Int * integer,
+                        const char *element, char **output,
+                        esxVI_Boolean required);
+int esxVI_Int_CastValueFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
+                                   int *integer);
+
+/*
+ * XSD: Long
+ */
+
+int esxVI_Long_CastValueFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
+                                    long long *integer);
+
+/*
+ * 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, xmlDocPtr doc,
+                                       xmlNodePtr node,
+                                       esxVI_ObjectUpdateKind *objectUpdateKind);
+
+/*
+ * 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, xmlDocPtr doc,
+                                       xmlNodePtr node,
+                                       esxVI_PropertyChangeOp *propertyChangeOp);
+
+/*
+ * 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,
+                                               char **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);
+
+/*
+ * VI Type: ManagedObjectReference
+ */
+
+struct _esxVI_ManagedObjectReference {
+    const char *type;                                 /* required */
+    const char *value;                                /* required */
+};
+
+int esxVI_ManagedObjectReference_Alloc(virConnectPtr conn,
+                                       esxVI_ManagedObjectReference **managedObjectReference);
+void esxVI_ManagedObjectReference_Free(esxVI_ManagedObjectReference **managedObjectReference);
+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, char **output,
+                                           esxVI_Boolean required);
+int esxVI_ManagedObjectReference_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                                             xmlNodePtr node,
+                                             esxVI_ManagedObjectReference **managedObjectReference,
+                                             const char *expectedType);
+
+/*
+ * VI Type: DynamicProperty
+ */
+
+struct _esxVI_DynamicProperty {
+    esxVI_DynamicProperty *_next;                     /* optional */
+
+    const char *name;                                 /* required */
+    esxVI_AnyType *value;                             /* required */
+};
+
+int esxVI_DynamicProperty_Alloc(virConnectPtr conn,
+                                esxVI_DynamicProperty **dynamicProperty);
+void esxVI_DynamicProperty_Free(esxVI_DynamicProperty **dynamicProperty);
+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, xmlDocPtr doc,
+                                      xmlNodePtr node,
+                                      esxVI_DynamicProperty **dynamicProperty);
+int esxVI_DynamicProperty_DeserializeList(virConnectPtr conn, xmlDocPtr doc,
+                                          xmlNodePtr node,
+                                          esxVI_DynamicProperty **dynamicProperty);
+
+/*
+ * VI Type: SelectionSpec
+ */
+
+struct _esxVI_SelectionSpec {
+    esxVI_SelectionSpec *_next;                       /* optional */
+    esxVI_TraversalSpec *_super;                      /* optional */
+
+    const char *name;                                 /* optional */
+};
+
+int esxVI_SelectionSpec_Alloc(virConnectPtr conn,
+                              esxVI_SelectionSpec **selectionSpec);
+void esxVI_SelectionSpec_Free(esxVI_SelectionSpec **selectionSpec);
+int esxVI_SelectionSpec_AppendToList(virConnectPtr conn,
+                                     esxVI_SelectionSpec **selectionSpecList,
+                                     esxVI_SelectionSpec *selectionSpec);
+int esxVI_SelectionSpec_Serialize(virConnectPtr conn,
+                                  esxVI_SelectionSpec *selectionSpec,
+                                  const char *element, char **output,
+                                  esxVI_Boolean required);
+int esxVI_SelectionSpec_SerializeList(virConnectPtr conn,
+                                      esxVI_SelectionSpec *selectionSpecList,
+                                      const char *element, char **output,
+                                      esxVI_Boolean required);
+
+/*
+ * VI Type: TraversalSpec extends SelectionSpec
+ */
+
+struct _esxVI_TraversalSpec {
+    esxVI_SelectionSpec *_base;                       /* required */
+
+    const char *type;                                 /* required */
+    const 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, char **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 **objectSpec);
+int esxVI_ObjectSpec_AppendToList(virConnectPtr conn,
+                                  esxVI_ObjectSpec **objectSpecList,
+                                  esxVI_ObjectSpec *objectSpec);
+int esxVI_ObjectSpec_Serialize(virConnectPtr conn,
+                               esxVI_ObjectSpec *objectSpec,
+                               const char *element, char **output,
+                               esxVI_Boolean required);
+int esxVI_ObjectSpec_SerializeList(virConnectPtr conn,
+                                   esxVI_ObjectSpec *objectSpecList,
+                                   const char *element, char **output,
+                                   esxVI_Boolean required);
+
+/*
+ * VI Type: PropertyChange
+ */
+
+struct _esxVI_PropertyChange {
+    esxVI_PropertyChange *_next;                      /* optional */
+
+    const 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 **propertyChange);
+int esxVI_PropertyChange_AppendToList(virConnectPtr conn,
+                                      esxVI_PropertyChange **propertyChangeList,
+                                      esxVI_PropertyChange *propertyChange);
+int esxVI_PropertyChange_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                                     xmlNodePtr node,
+                                     esxVI_PropertyChange **propertyChange);
+int esxVI_PropertyChange_DeserializeList(virConnectPtr conn, xmlDocPtr doc,
+                                         xmlNodePtr node,
+                                         esxVI_PropertyChange **propertyChange);
+
+/*
+ * VI Type: PropertySpec
+ */
+
+struct _esxVI_PropertySpec {
+    esxVI_PropertySpec *_next;                        /* optional */
+
+    const 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 **propertySpec);
+int esxVI_PropertySpec_AppendToList(virConnectPtr conn,
+                                    esxVI_PropertySpec **propertySpecList,
+                                    esxVI_PropertySpec *propertySpec);
+int esxVI_PropertySpec_Serialize(virConnectPtr conn,
+                                 esxVI_PropertySpec *propertySpec,
+                                 const char *element, char **output,
+                                 esxVI_Boolean required);
+int esxVI_PropertySpec_SerializeList(virConnectPtr conn,
+                                     esxVI_PropertySpec *propertySpecList,
+                                     const char *element, char **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 **propertyFilterSpec);
+int esxVI_PropertyFilterSpec_AppendToList(virConnectPtr conn,
+                                          esxVI_PropertyFilterSpec **propertyFilterSpecList,
+                                          esxVI_PropertyFilterSpec *propertyFilterSpec);
+int esxVI_PropertyFilterSpec_Serialize(virConnectPtr conn,
+                                       esxVI_PropertyFilterSpec *propertyFilterSpec,
+                                       const char *element, char **output,
+                                       esxVI_Boolean required);
+int esxVI_PropertyFilterSpec_SerializeList(virConnectPtr conn,
+                                           esxVI_PropertyFilterSpec *propertyFilterSpecList,
+                                           const char *element, char **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 **objectContent);
+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, xmlDocPtr doc,
+                                    xmlNodePtr node,
+                                    esxVI_ObjectContent **objectContent);
+int esxVI_ObjectContent_DeserializeList(virConnectPtr conn, xmlDocPtr doc,
+                                        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 **objectUpdate);
+int esxVI_ObjectUpdate_AppendToList(virConnectPtr conn,
+                                    esxVI_ObjectUpdate **objectUpdateList,
+                                    esxVI_ObjectUpdate *objectUpdate);
+int esxVI_ObjectUpdate_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                                   xmlNodePtr node,
+                                   esxVI_ObjectUpdate **objectUpdate);
+int esxVI_ObjectUpdate_DeserializeList(virConnectPtr conn, xmlDocPtr doc,
+                                       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 **propertyFilterUpdate);
+int esxVI_PropertyFilterUpdate_AppendToList(virConnectPtr conn,
+                                            esxVI_PropertyFilterUpdate **propertyFilterUpdateList,
+                                            esxVI_PropertyFilterUpdate *propertyFilterUpdate);
+int esxVI_PropertyFilterUpdate_Deserialize(virConnectPtr conn, xmlDocPtr doc,
+                                           xmlNodePtr node,
+                                           esxVI_PropertyFilterUpdate **propertyFilterUpdate);
+int esxVI_PropertyFilterUpdate_DeserializeList(virConnectPtr conn,
+                                               xmlDocPtr doc, xmlNodePtr node,
+                                               esxVI_PropertyFilterUpdate **propertyFilterUpdateList);
+
+/*
+ * VI Type: AboutInfo
+ */
+
+struct _esxVI_AboutInfo {
+    const char *name;                                 /* required */
+    const char *fullName;                             /* required */
+    const char *vendor;                               /* required */
+    const char *version;                              /* required */
+    const char *build;                                /* required */
+    const char *localeVersion;                        /* optional */
+    const char *localeBuild;                          /* optional */
+    const char *osType;                               /* required */
+    const char *productLineId;                        /* required */
+    const char *apiType;                              /* required */
+    const 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, xmlDocPtr doc,
+                                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, xmlDocPtr doc,
+                                     xmlNodePtr node,
+                                     esxVI_ServiceContent **serviceContent);
+
+/*
+ * VI Type: UpdateSet
+ */
+
+struct _esxVI_UpdateSet {
+    const 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, xmlDocPtr doc,
+                                xmlNodePtr node, esxVI_UpdateSet **updateSet);
+
+/*
+ * VI Type: VirtualMachineConfigSpec
+ */
+
+/* FIXME: implement the rest */
+struct _esxVI_VirtualMachineConfigSpec {
+    //const char *changeVersion; /* optional */
+    //const char *name; /* optional */
+    //const char *version; /* optional */
+    //const char *uuid; /* optional */
+    //esxVI_Long *npivNodeWorldWideName; /* optional, list */
+    //esxVI_Long *npivPortWorldWideName; /* optional, list */
+    //const char *npivWorldWideNameType; /* optional */
+    //const char *npivWorldWideNameOp; /* optional */
+    //const char *locationId; /* optional */
+    //const char *guestId; /* optional */
+    //const char *alternateGuestName; /* optional */
+    //const 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 */
+    //const 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,
+                                             char **output,
+                                             esxVI_Boolean required);
+
+/*
+ * 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);
+
+int esxVI_Logout(virConnectPtr conn, esxVI_Context *ctx);
+
+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);
+
+/*
+ * Utility and Convenience Methods
+ */
+
+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_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_NumOfDomainsByPowerState(virConnectPtr conn, esxVI_Context *ctx,
+                                   esxVI_VirtualMachinePowerState powerState,
+                                   esxVI_Boolean inverse);
+
+int esxVI_GetVirtualMachineIdentity(virConnectPtr conn,
+                                    esxVI_ObjectContent *virtualMachine,
+                                    int *id, const char **name,
+                                    unsigned char *uuid);
+
+int esxVI_LookupVirtualMachineByDomain(virConnectPtr conn, esxVI_Context *ctx,
+                                       virDomainPtr domain,
+                                       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_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
+                                esxVI_ManagedObjectReference *task,
+                                esxVI_TaskInfoState *finalState);
+
+#endif /* __ESX_VI_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]