[libvirt] [PATCH v2] esx: Add read-only storage pool access

Matthias Bolte matthias.bolte at googlemail.com
Tue May 18 16:38:47 UTC 2010


Allows listing existing pools and requesting information about them.

Alter the esxVI_ProductVersion enum in a way that allows to check for
product type by masking.

Changes in v2:
 - split not directly related parts into separate patches
 - simplify goto usage: don't jump backwards
 - rework format of esxVI_ProductVersion values and explain the format
 - expand a FIXME in esxStoragePoolGetXMLDesc
---
 po/POTFILES.in                 |    1 +
 src/esx/esx_storage_driver.c   |  597 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.c               |  126 ++++++++-
 src/esx/esx_vi.h               |   33 ++-
 src/esx/esx_vi_generator.input |   59 ++++
 src/esx/esx_vi_generator.py    |    7 +-
 6 files changed, 794 insertions(+), 29 deletions(-)

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 88218bd..e047b1b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,6 +19,7 @@ src/cpu/cpu_map.c
 src/cpu/cpu_x86.c
 src/datatypes.c
 src/esx/esx_driver.c
+src/esx/esx_storage_driver.c
 src/esx/esx_util.c
 src/esx/esx_vi.c
 src/esx/esx_vi_methods.c
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 97b92a5..0e2e1a3 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -29,6 +29,7 @@
 #include "memory.h"
 #include "logging.h"
 #include "uuid.h"
+#include "storage_conf.h"
 #include "esx_private.h"
 #include "esx_storage_driver.h"
 #include "esx_vi.h"
@@ -65,17 +66,587 @@ esxStorageClose(virConnectPtr conn)
 
 
 
+static int
+esxNumberOfStoragePools(virConnectPtr conn)
+{
+    int count = 0;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return -1;
+    }
+
+    if (esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+                                        "Datastore", NULL, esxVI_Boolean_True,
+                                        &datastoreList) < 0) {
+        return -1;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        ++count;
+    }
+
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return count;
+}
+
+
+
+static int
+esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
+{
+    bool success = false;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    int count = 0;
+    int i;
+
+    if (names == NULL || maxnames < 0) {
+        ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return -1;
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "summary.name") < 0 ||
+        esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+                                        "Datastore", propertyNameList,
+                                        esxVI_Boolean_True,
+                                        &datastoreList) < 0) {
+        goto cleanup;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.name")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_String) < 0) {
+                    goto cleanup;
+                }
+
+                names[count] = strdup(dynamicProperty->val->string);
+
+                if (names[count] == NULL) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                ++count;
+                break;
+            } else {
+                VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+            }
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (! success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+
+        count = -1;
+    }
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return count;
+}
+
+
+
+static int
+esxNumberOfDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    /* ESX storage pools are always active */
+    return 0;
+}
+
+
+
+static int
+esxListDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
+                           char **const names ATTRIBUTE_UNUSED,
+                           int maxnames ATTRIBUTE_UNUSED)
+{
+    /* ESX storage pools are always active */
+    return 0;
+}
+
+
+
+static virStoragePoolPtr
+esxStoragePoolLookupByName(virConnectPtr conn, const char *name)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+    char *summaryUrl = NULL;
+    char *suffix = NULL;
+    int suffixLength;
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "00000000-00000000-0000-000000000000";
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    char *realName = NULL;
+    virStoragePoolPtr pool = NULL;
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return NULL;
+    }
+
+    if (esxVI_String_AppendValueListToList(&propertyNameList,
+                                           "summary.accessible\0"
+                                           "summary.name\0"
+                                           "summary.url\0") < 0 ||
+        esxVI_LookupDatastoreByName(priv->host, name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_GetBoolean(datastore, "summary.accessible",
+                         &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    /*
+     * Datastores don't have a UUID. We can use the 'summary.url' property as
+     * source for a "UUID" on ESX, because the property value has this format:
+     *
+     *   summary.url = /vmfs/volumes/4b0beca7-7fd401f3-1d7f-000ae484a6a3
+     *   summary.url = /vmfs/volumes/b24b7a78-9d82b4f5    (short format)
+     *
+     * The 'summary.url' property comes in two forms, with a complete "UUID"
+     * and a short "UUID".
+     *
+     * But this trailing "UUID" is not guaranteed to be there. On the other
+     * hand we already rely on another implementation detail of the ESX server:
+     * The object name of virtual machine contains an integer, we use that as
+     * domain ID.
+     *
+     * The 'summary.url' property of an inaccessible datastore is invalid.
+     */
+    if (accessible == esxVI_Boolean_True &&
+        priv->host->productVersion & esxVI_ProductVersion_ESX) {
+        if (esxVI_GetStringValue(datastore, "summary.url", &summaryUrl,
+                                 esxVI_Occurrence_RequiredItem) < 0) {
+            goto cleanup;
+        }
+
+        if ((suffix = STRSKIP(summaryUrl, "/vmfs/volumes/")) == NULL) {
+            ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                         _("Datastore URL '%s' has unexpected prefix, "
+                           "expecting '/vmfs/volumes/' prefix"), summaryUrl);
+            goto cleanup;
+        }
+
+        suffixLength = strlen(suffix);
+
+        if ((suffixLength == 35 && /* = strlen("4b0beca7-7fd401f3-1d7f-000ae484a6a3") */
+             suffix[8] == '-' && suffix[17] == '-' && suffix[22] == '-') ||
+            (suffixLength == 17 && /* = strlen("b24b7a78-9d82b4f5") */
+             suffix[8] == '-')) {
+            /*
+             * Intentionally use memcpy here, because we want to be able to
+             * replace a prefix of the initial Zero-UUID. virStrncpy would
+             * null-terminate the string in an unwanted place.
+             */
+            memcpy(uuid_string, suffix, suffixLength);
+        } else {
+            VIR_WARN("Datastore URL suffix '%s' has unexpected format, "
+                     "cannot deduce a UUID from it", suffix);
+        }
+    }
+
+    if (virUUIDParse(uuid_string, uuid) < 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                  _("Could not parse UUID from string '%s'"),
+                  uuid_string);
+        goto cleanup;
+    }
+
+    if (esxVI_GetStringValue(datastore, "summary.name", &realName,
+                             esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    pool = virGetStoragePool(conn, realName, uuid);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+
+    return pool;
+}
+
+
+
+static virStoragePoolPtr
+esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+    char *name = NULL;
+    virStoragePoolPtr pool = NULL;
+
+    if (! (priv->host->productVersion & esxVI_ProductVersion_ESX)) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Lookup by UUID is supported on ESX only"));
+        return NULL;
+    }
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return NULL;
+    }
+
+    /*
+     * Convert from UUID to datastore URL form by stripping the second '-':
+     *
+     * <---- 14 ----><-------- 22 -------->    <---- 13 ---><-------- 22 -------->
+     * 4b0beca7-7fd4-01f3-1d7f-000ae484a6a3 -> 4b0beca7-7fd401f3-1d7f-000ae484a6a3
+     */
+    virUUIDFormat(uuid, uuid_string);
+    memmove(uuid_string + 13, uuid_string + 14, 22 + 1);
+
+    /*
+     * Use esxVI_LookupDatastoreByName because it also does try to match "UUID"
+     * part of the 'summary.url' property if there is no name match.
+     */
+    if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+        esxVI_LookupDatastoreByName(priv->host, uuid_string,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_OptionalItem) < 0) {
+        goto cleanup;
+    }
+
+    /*
+     * If the first try didn't succeed and the trailing 16 digits are zero then
+     * the "UUID" could be a short one. Strip the 16 zeros and try again:
+     *
+     * <------ 17 ----->                      <------ 17 ----->
+     * b24b7a78-9d82b4f5-0000-000000000000 -> b24b7a78-9d82b4f5
+     */
+    if (datastore == NULL && STREQ(uuid_string + 17, "-0000-000000000000")) {
+        uuid_string[17] = '\0';
+
+        if (esxVI_LookupDatastoreByName(priv->host, uuid_string,
+                                        propertyNameList, &datastore,
+                                        esxVI_Occurrence_RequiredItem) < 0) {
+            goto cleanup;
+        }
+    }
+
+    if (datastore == NULL) {
+        virUUIDFormat(uuid, uuid_string);
+
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not find datastore with UUID '%s'"),
+                     uuid_string);
+
+        goto cleanup;
+    }
+
+    if (esxVI_GetStringValue(datastore, "summary.name", &name,
+                             esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    pool = virGetStoragePool(conn, name, uuid);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+
+    return pool;
+}
+
+
+
+static int
+esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
+{
+    int result = -1;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_ObjectContent *datastore = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return -1;
+    }
+
+    if (esxVI_LookupDatastoreByName(priv->host, pool->name, NULL, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_RefreshDatastore(priv->host, datastore->obj) < 0) {
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+}
+
+
+
+static int
+esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
+{
+    int result = -1;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+
+    memset(info, 0, sizeof (*info));
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return -1;
+    }
+
+    if (esxVI_String_AppendValueListToList(&propertyNameList,
+                                           "summary.accessible\0"
+                                           "summary.capacity\0"
+                                           "summary.freeSpace\0") < 0 ||
+        esxVI_LookupDatastoreByName(priv->host, pool->name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_GetBoolean(datastore, "summary.accessible",
+                         &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    if (accessible == esxVI_Boolean_True) {
+        info->state = VIR_STORAGE_POOL_RUNNING;
+
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.capacity")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                info->capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                info->available = dynamicProperty->val->int64;
+            }
+        }
+
+        info->allocation = info->capacity - info->available;
+    } else {
+        info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        memset(info, 0, sizeof (*info));
+    }
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+}
+
+
+
+static char *
+esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+    virStoragePoolDef def;
+    esxVI_DatastoreInfo *info = NULL;
+    esxVI_LocalDatastoreInfo *localInfo = NULL;
+    esxVI_NasDatastoreInfo *nasInfo = NULL;
+    esxVI_VmfsDatastoreInfo *vmfsInfo = NULL;
+    char *xml = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&def, 0, sizeof (def));
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        return NULL;
+    }
+
+    if (esxVI_String_AppendValueListToList(&propertyNameList,
+                                           "summary.accessible\0"
+                                           "summary.capacity\0"
+                                           "summary.freeSpace\0"
+                                           "info\0") < 0 ||
+        esxVI_LookupDatastoreByName(priv->host, pool->name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_GetBoolean(datastore, "summary.accessible",
+                         &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    def.name = pool->name;
+    memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+    if (accessible == esxVI_Boolean_True) {
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.capacity")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                def.capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                def.available = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "info")) {
+                if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+                                                        &info) < 0) {
+                    goto cleanup;
+                }
+            }
+        }
+
+        def.allocation = def.capacity - def.available;
+
+        /* See vSphere API documentation about HostDatastoreSystem for details */
+        if ((localInfo = esxVI_LocalDatastoreInfo_DynamicCast(info)) != NULL) {
+            def.type = VIR_STORAGE_POOL_DIR;
+            def.target.path = localInfo->path;
+        } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
+            def.type = VIR_STORAGE_POOL_NETFS;
+            def.source.host.name = nasInfo->nas->remoteHost;
+            def.source.dir = nasInfo->nas->remotePath;
+
+            if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
+                def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
+            } else  if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
+                def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
+            } else {
+                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+                          _("Datastore has unexpected type '%s'"),
+                          nasInfo->nas->type);
+                goto cleanup;
+            }
+        } else if ((vmfsInfo = esxVI_VmfsDatastoreInfo_DynamicCast(info)) != NULL) {
+            def.type = VIR_STORAGE_POOL_FS;
+            /*
+             * FIXME: I'm not sure how to represent the source and target of a
+             * VMFS based datastore in libvirt terms
+             */
+        } else {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                      _("DatastoreInfo has unexpected type"));
+            goto cleanup;
+        }
+    }
+
+    xml = virStoragePoolDefFormat(&def);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreInfo_Free(&info);
+
+    return xml;
+}
+
+
+
+static int
+esxStoragePoolGetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+                           int *autostart)
+{
+    /* ESX storage pools are always active */
+    *autostart = 1;
+
+    return 0;
+}
+
+
+
+static int
+esxStoragePoolSetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+                           int autostart)
+{
+    /* Just accept autostart activation, but fail on autostart deactivation */
+    autostart = (autostart != 0);
+
+    if (! autostart) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Cannot deactivate storage pool autostart"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+esxStoragePoolIsActive(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
+{
+    /* ESX storage pools are always active */
+    return 1;
+}
+
+
+
+static int
+esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
+{
+    /* ESX has no concept of transient pools, so all of them are persistent */
+    return 1;
+}
+
+
 static virStorageDriver esxStorageDriver = {
     "ESX",                                 /* name */
     esxStorageOpen,                        /* open */
     esxStorageClose,                       /* close */
-    NULL,                                  /* numOfPools */
-    NULL,                                  /* listPools */
-    NULL,                                  /* numOfDefinedPools */
-    NULL,                                  /* listDefinedPools */
+    esxNumberOfStoragePools,               /* numOfPools */
+    esxListStoragePools,                   /* listPools */
+    esxNumberOfDefinedStoragePools,        /* numOfDefinedPools */
+    esxListDefinedStoragePools,            /* listDefinedPools */
     NULL,                                  /* findPoolSources */
-    NULL,                                  /* poolLookupByName */
-    NULL,                                  /* poolLookupByUUID */
+    esxStoragePoolLookupByName,            /* poolLookupByName */
+    esxStoragePoolLookupByUUID,            /* poolLookupByUUID */
     NULL,                                  /* poolLookupByVolume */
     NULL,                                  /* poolCreateXML */
     NULL,                                  /* poolDefineXML */
@@ -84,11 +655,11 @@ static virStorageDriver esxStorageDriver = {
     NULL,                                  /* poolCreate */
     NULL,                                  /* poolDestroy */
     NULL,                                  /* poolDelete */
-    NULL,                                  /* poolRefresh */
-    NULL,                                  /* poolGetInfo */
-    NULL,                                  /* poolGetXMLDesc */
-    NULL,                                  /* poolGetAutostart */
-    NULL,                                  /* poolSetAutostart */
+    esxStoragePoolRefresh,                 /* poolRefresh */
+    esxStoragePoolGetInfo,                 /* poolGetInfo */
+    esxStoragePoolGetXMLDesc,              /* poolGetXMLDesc */
+    esxStoragePoolGetAutostart,            /* poolGetAutostart */
+    esxStoragePoolSetAutostart,            /* poolSetAutostart */
     NULL,                                  /* poolNumOfVolumes */
     NULL,                                  /* poolListVolumes */
     NULL,                                  /* volLookupByName */
@@ -101,8 +672,8 @@ static virStorageDriver esxStorageDriver = {
     NULL,                                  /* volGetInfo */
     NULL,                                  /* volGetXMLDesc */
     NULL,                                  /* volGetPath */
-    NULL,                                  /* poolIsActive */
-    NULL,                                  /* poolIsPersistent */
+    esxStoragePoolIsActive,                /* poolIsActive */
+    esxStoragePoolIsPersistent,            /* poolIsPersistent */
 };
 
 
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 966ef85..100b9d2 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -1530,6 +1530,114 @@ esxVI_GetVirtualMachineQuestionInfo
 
 
 int
+esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName,
+                 esxVI_Boolean *value, esxVI_Occurrence occurence)
+{
+    esxVI_DynamicProperty *dynamicProperty;
+
+    if (value == NULL || *value != esxVI_Boolean_Undefined) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, propertyName)) {
+            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                         esxVI_Type_Boolean) < 0) {
+                return -1;
+            }
+
+            *value = dynamicProperty->val->boolean;
+            break;
+        }
+    }
+
+    if (*value == esxVI_Boolean_Undefined &&
+        occurence == esxVI_Occurrence_RequiredItem) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Missing '%s' property"), propertyName);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+int
+esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
+                     const char *propertyName,
+                     char **value, esxVI_Occurrence occurence)
+{
+    esxVI_DynamicProperty *dynamicProperty;
+
+    if (value == NULL || *value != NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, propertyName)) {
+            if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                         esxVI_Type_String) < 0) {
+                return -1;
+            }
+
+            *value = dynamicProperty->val->string;
+            break;
+        }
+    }
+
+    if (*value == NULL && occurence == esxVI_Occurrence_RequiredItem) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Missing '%s' property"), propertyName);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+int
+esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
+                                const char *propertyName,
+                                esxVI_ManagedObjectReference **value,
+                                esxVI_Occurrence occurence)
+{
+    esxVI_DynamicProperty *dynamicProperty;
+
+    if (value == NULL || *value != NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, propertyName)) {
+            if (esxVI_ManagedObjectReference_CastFromAnyType
+                  (dynamicProperty->val, value) < 0) {
+                return -1;
+            }
+
+            break;
+        }
+    }
+
+    if (*value == NULL && occurence == esxVI_Occurrence_RequiredItem) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Missing '%s' property"), propertyName);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+int
 esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context *ctx,
                                         esxVI_VirtualMachinePowerState powerState,
                                         esxVI_Boolean inverse)
@@ -2161,7 +2269,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
     esxVI_ObjectContent *candidate = NULL;
     esxVI_DynamicProperty *dynamicProperty = NULL;
     esxVI_Boolean accessible = esxVI_Boolean_Undefined;
-    size_t offset = strlen("/vmfs/volumes/");
+    size_t offset = 14; /* = strlen("/vmfs/volumes/") */
     int numInaccessibleDatastores = 0;
 
     if (datastore == NULL || *datastore != NULL) {
@@ -2227,9 +2335,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
 
         for (dynamicProperty = candidate->propSet; dynamicProperty != NULL;
              dynamicProperty = dynamicProperty->_next) {
-            if (STREQ(dynamicProperty->name, "summary.accessible")) {
-                /* Ignore it */
-            } else if (STREQ(dynamicProperty->name, "summary.name")) {
+            if (STREQ(dynamicProperty->name, "summary.name")) {
                 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
                                              esxVI_Type_String) < 0) {
                     goto failure;
@@ -2244,7 +2350,8 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
                     /* Found datastore with matching name */
                     goto cleanup;
                 }
-            } else if (STREQ(dynamicProperty->name, "summary.url")) {
+            } else if (STREQ(dynamicProperty->name, "summary.url") &&
+                       ctx->productVersion & esxVI_ProductVersion_ESX) {
                 if (accessible == esxVI_Boolean_False) {
                     /*
                      * The 'summary.url' property of an inaccessible datastore
@@ -2276,8 +2383,6 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
                     /* Found datastore with matching URL suffix */
                     goto cleanup;
                 }
-            } else {
-                VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
             }
         }
     }
@@ -2309,9 +2414,10 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
 
 
 
-int esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
-                               esxVI_ManagedObjectReference *task,
-                               esxVI_TaskInfo **taskInfo)
+int
+esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
+                           esxVI_ManagedObjectReference *task,
+                           esxVI_TaskInfo **taskInfo)
 {
     int result = 0;
     esxVI_String *propertyNameList = NULL;
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index d581a59..e2687c4 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -96,13 +96,23 @@ enum _esxVI_APIVersion {
     esxVI_APIVersion_40
 };
 
+/*
+ * AAAABBBB: where AAAA0000 is the product and BBBB the version. this format
+ * allows simple bitmask testing for a product independent of the version
+ */
 enum _esxVI_ProductVersion {
     esxVI_ProductVersion_Undefined = 0,
-    esxVI_ProductVersion_GSX20,
-    esxVI_ProductVersion_ESX35,
-    esxVI_ProductVersion_ESX40,
-    esxVI_ProductVersion_VPX25,
-    esxVI_ProductVersion_VPX40
+
+    esxVI_ProductVersion_GSX   = (1 << 0) << 16,
+    esxVI_ProductVersion_GSX20 = esxVI_ProductVersion_GSX | 1,
+
+    esxVI_ProductVersion_ESX   = (1 << 1) << 16,
+    esxVI_ProductVersion_ESX35 = esxVI_ProductVersion_ESX | 1,
+    esxVI_ProductVersion_ESX40 = esxVI_ProductVersion_ESX | 2,
+
+    esxVI_ProductVersion_VPX   = (1 << 2) << 16,
+    esxVI_ProductVersion_VPX25 = esxVI_ProductVersion_VPX | 1,
+    esxVI_ProductVersion_VPX40 = esxVI_ProductVersion_VPX | 2
 };
 
 enum _esxVI_Occurrence {
@@ -272,6 +282,19 @@ int esxVI_GetVirtualMachineQuestionInfo
       (esxVI_ObjectContent *virtualMachine,
        esxVI_VirtualMachineQuestionInfo **questionInfo);
 
+int esxVI_GetBoolean(esxVI_ObjectContent *objectContent,
+                     const char *propertyName,
+                     esxVI_Boolean *value, esxVI_Occurrence occurence);
+
+int esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
+                         const char *propertyName,
+                         char **value, esxVI_Occurrence occurence);
+
+int esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
+                                    const char *propertyName,
+                                    esxVI_ManagedObjectReference **value,
+                                    esxVI_Occurrence occurence);
+
 int esxVI_LookupNumberOfDomainsByPowerState
       (esxVI_Context *ctx, esxVI_VirtualMachinePowerState powerState,
        esxVI_Boolean inverse);
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 5e5e6ba..ff65178 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -146,6 +146,14 @@ object ChoiceOption extends OptionType
 end
 
 
+object DatastoreInfo
+    String                                   name                           r
+    String                                   url                            r
+    Long                                     freeSpace                      r
+    Long                                     maxFileSize                    r
+end
+
+
 object Description
     String                                   label                          r
     String                                   summary                        r
@@ -186,6 +194,47 @@ object HostCpuIdInfo
 end
 
 
+object HostFileSystemVolume
+    String                                   type                           r
+    String                                   name                           r
+    Long                                     capacity                       r
+end
+
+
+object HostNasVolume extends HostFileSystemVolume
+    String                                   remoteHost                     r
+    String                                   remotePath                     r
+    String                                   userName                       o
+end
+
+
+object HostScsiDiskPartition
+    String                                   diskName                       r
+    Int                                      partition                      r
+end
+
+
+object HostVmfsVolume extends HostFileSystemVolume
+    Int                                      blockSizeMb                    r
+    Int                                      maxBlocks                      r
+    Int                                      majorVersion                   r
+    String                                   version                        r
+    String                                   uuid                           r
+    HostScsiDiskPartition                    extent                         rl
+    Boolean                                  vmfsUpgradable                 r
+end
+
+
+object LocalDatastoreInfo extends DatastoreInfo
+    String                                   path                           o
+end
+
+
+object NasDatastoreInfo extends DatastoreInfo
+    HostNasVolume                            nas                            o
+end
+
+
 object ObjectContent
     ManagedObjectReference                   obj                            r
     DynamicProperty                          propSet                        ol
@@ -453,6 +502,11 @@ object VirtualMachineSnapshotTree
 end
 
 
+object VmfsDatastoreInfo extends DatastoreInfo
+    HostVmfsVolume                           vmfs                           o
+end
+
+
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 # Methods
 #
@@ -571,6 +625,11 @@ method ReconfigVM_Task returns ManagedObjectReference r
 end
 
 
+method RefreshDatastore
+    ManagedObjectReference                   _this                          r
+end
+
+
 method RegisterVM_Task returns ManagedObjectReference r
     ManagedObjectReference                   _this                          r
     String                                   path                           r
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 6ae13c0..8df0e80 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -382,6 +382,9 @@ class Object:
         self.properties = properties
         self.extended_by = extended_by
 
+        if self.extended_by is not None:
+            self.extended_by.sort();
+
 
     def generate_struct_members(self, add_banner = False, struct_gap = False):
         global objects_by_name
@@ -1095,7 +1098,8 @@ additional_enum_features = { "ManagedEntityStatus"      : Enum.FEATURE__ANY_TYPE
                              "VirtualMachinePowerState" : Enum.FEATURE__ANY_TYPE }
 
 
-additional_object_features = { "Event"                      : Object.FEATURE__LIST,
+additional_object_features = { "DatastoreInfo"              : Object.FEATURE__ANY_TYPE | Object.FEATURE__DYNAMIC_CAST,
+                               "Event"                      : Object.FEATURE__LIST,
                                "HostCpuIdInfo"              : Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
                                "ManagedObjectReference"     : Object.FEATURE__ANY_TYPE,
                                "ObjectContent"              : Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST,
@@ -1235,6 +1239,7 @@ for obj in objects_by_name.values():
             extended_obj.extended_by = [obj.name]
         else:
             extended_obj.extended_by.append(obj.name)
+            extended_obj.extended_by.sort()
 
 
 
-- 
1.7.0.4




More information about the libvir-list mailing list