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

Matthias Bolte matthias.bolte at googlemail.com
Fri May 7 20:02:53 UTC 2010


Add VIR_STORAGE_POOL_INACCESSIBLE to denote a running but inaccessible
storage pool. For example an NFS pool is inaccessible when the NFS
server is currently unreachable.

Add CIFS to the list of network file systems because ESX distinguishes
between NFS and CIFS.

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

Make esxVI_*_CastFromAnyType dynamically dispatched in order to handle
the DatastoreInfo type and inheriting types properly.

Allow esxVI_X_DynamicCast to be called successfully on objects with
type X. This is necessary for handling DatastoreInfo and inheriting
types properly.
---
 include/libvirt/libvirt.h.in   |    1 +
 po/POTFILES.in                 |    1 +
 src/conf/storage_conf.c        |    2 +-
 src/conf/storage_conf.h        |    1 +
 src/esx/esx_storage_driver.c   |  606 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.c               |  126 ++++++++-
 src/esx/esx_vi.h               |   26 ++-
 src/esx/esx_vi_generator.input |   59 ++++
 src/esx/esx_vi_generator.py    |   20 ++-
 src/esx/esx_vi_types.c         |   44 ++-
 tools/virsh.c                  |    4 +
 11 files changed, 845 insertions(+), 45 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index db107cc..838028d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1118,6 +1118,7 @@ typedef enum {
   VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */
   VIR_STORAGE_POOL_RUNNING = 2,  /* Running normally */
   VIR_STORAGE_POOL_DEGRADED = 3, /* Running degraded */
+  VIR_STORAGE_POOL_INACCESSIBLE = 4, /* Running, but not accessible */
 } virStoragePoolState;
 
 
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/conf/storage_conf.c b/src/conf/storage_conf.c
index 6218e02..c1595aa 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -61,7 +61,7 @@ VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
 
 VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
               VIR_STORAGE_POOL_NETFS_LAST,
-              "auto", "nfs", "glusterfs")
+              "auto", "nfs", "glusterfs", "cifs")
 
 VIR_ENUM_IMPL(virStoragePoolFormatDisk,
               VIR_STORAGE_POOL_DISK_LAST,
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 1c9ba04..5813489 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -405,6 +405,7 @@ enum virStoragePoolFormatFileSystemNet {
     VIR_STORAGE_POOL_NETFS_AUTO = 0,
     VIR_STORAGE_POOL_NETFS_NFS,
     VIR_STORAGE_POOL_NETFS_GLUSTERFS,
+    VIR_STORAGE_POOL_NETFS_CIFS,
     VIR_STORAGE_POOL_NETFS_LAST,
 };
 VIR_ENUM_DECL(virStoragePoolFormatFileSystemNet)
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 97b92a5..c82667b 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,596 @@ esxStorageClose(virConnectPtr conn)
 
 
 
+static int
+esxNumberOfStoragePools(virConnectPtr conn)
+{
+    int result = 0;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        goto failure;
+    }
+
+    if (esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+                                        "Datastore", NULL, esxVI_Boolean_True,
+                                        &datastoreList) < 0) {
+        goto failure;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        ++result;
+    }
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+static int
+esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
+{
+    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) {
+        goto failure;
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "summary.name") < 0 ||
+        esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+                                        "Datastore", propertyNameList,
+                                        esxVI_Boolean_True,
+                                        &datastoreList) < 0) {
+        goto failure;
+    }
+
+    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 failure;
+                }
+
+                names[count] = strdup(dynamicProperty->val->string);
+
+                if (names[count] == NULL) {
+                    virReportOOMError();
+                    goto failure;
+                }
+
+                ++count;
+                break;
+            } else {
+                VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+            }
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return count;
+
+  failure:
+    for (i = 0; i < count; ++i) {
+        VIR_FREE(names[i]);
+    }
+
+    count = -1;
+
+    goto cleanup;
+}
+
+
+
+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) {
+        goto cleanup;
+    }
+
+    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) {
+        goto cleanup;
+    }
+
+    /*
+     * 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 ATTRIBUTE_UNUSED)
+{
+    int result = 0;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_ObjectContent *datastore = NULL;
+
+    if (esxVI_EnsureSession(priv->host) < 0) {
+        goto failure;
+    }
+
+    if (esxVI_LookupDatastoreByName(priv->host, pool->name, NULL, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_RefreshDatastore(priv->host, datastore->obj) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+static int
+esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
+{
+    int result = 0;
+    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) {
+        goto failure;
+    }
+
+    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 failure;
+    }
+
+    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 failure;
+                }
+
+                info->capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto failure;
+                }
+
+                info->available = dynamicProperty->val->int64;
+            }
+        }
+
+        info->allocation = info->capacity - info->available;
+    } else {
+        info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+
+  failure:
+    memset(info, 0, sizeof (*info));
+
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+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) {
+        goto failure;
+    }
+
+    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 failure;
+    }
+
+    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 failure;
+                }
+
+                def.capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto failure;
+                }
+
+                def.available = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "info")) {
+                if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+                                                        &info) < 0) {
+                    goto failure;
+                }
+            }
+        }
+
+        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 failure;
+            }
+        } else if ((vmfsInfo = esxVI_VmfsDatastoreInfo_DynamicCast(info)) != NULL) {
+            def.type = VIR_STORAGE_POOL_FS;
+            /* FIXME */
+        } else {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                      _("DatastoreInfo has unexpected type"));
+            goto failure;
+        }
+    }
+
+    xml = virStoragePoolDefFormat(&def);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreInfo_Free(&info);
+
+    return xml;
+
+  failure:
+    VIR_FREE(xml);
+
+    goto cleanup;
+}
+
+
+
+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 +664,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 +681,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..7a39fc2 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/");
+    int 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..e84f62b 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -98,11 +98,14 @@ enum _esxVI_APIVersion {
 
 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   = 0x1000,
+    esxVI_ProductVersion_GSX20 = 0x1001,
+    esxVI_ProductVersion_ESX   = 0x2000,
+    esxVI_ProductVersion_ESX35 = 0x2001,
+    esxVI_ProductVersion_ESX40 = 0x2002,
+    esxVI_ProductVersion_VPX   = 0x4000,
+    esxVI_ProductVersion_VPX25 = 0x4001,
+    esxVI_ProductVersion_VPX40 = 0x4002
 };
 
 enum _esxVI_Occurrence {
@@ -272,6 +275,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 d249e2d..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
@@ -765,7 +768,18 @@ class Object:
         # cast from any type
         if self.features & Object.FEATURE__ANY_TYPE:
             source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
-            source += "ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(%s)\n" % self.name
+            source += "ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(%s,\n" % self.name
+
+            if self.extended_by is None:
+                source += "{\n"
+                source += "})\n\n"
+            else:
+                source += "{\n"
+
+                for extended_by in self.extended_by:
+                    source += "    ESX_VI__TEMPLATE__DISPATCH__CAST_FROM_ANY_TYPE(%s)\n" % extended_by
+
+                source += "})\n\n"
 
             if self.features & Object.FEATURE__LIST:
                 source += "/* esxVI_%s_CastListFromAnyType */\n" % self.name
@@ -1084,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,
@@ -1224,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()
 
 
 
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index 7d2c02c..8334efd 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -183,7 +183,7 @@
 
 
 
-#define ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(_type)                           \
+#define ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(_type, _dispatch)                \
     int                                                                       \
     esxVI_##_type##_CastFromAnyType(esxVI_AnyType *anyType,                   \
                                     esxVI_##_type **ptrptr)                   \
@@ -194,11 +194,16 @@
             return -1;                                                        \
         }                                                                     \
                                                                               \
-        if (anyType->type != esxVI_Type_##_type) {                            \
+        switch (anyType->type) {                                              \
+          _dispatch                                                           \
+                                                                              \
+          case esxVI_Type_##_type:                                            \
+            break;                                                            \
+                                                                              \
+          default:                                                            \
             ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,                              \
-                         "Expecting type '%s' but found '%s'",                \
-                         esxVI_Type_ToString(esxVI_Type_##_type),             \
-                         anyType->other);                                     \
+                         _("Call to %s for unexpected type '%s'"),            \
+                         __FUNCTION__, anyType->other);                       \
             return -1;                                                        \
         }                                                                     \
                                                                               \
@@ -505,7 +510,7 @@
                                                                               \
       default:                                                                \
         ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,                                  \
-                     "Call to %s for unexpected type '%s'", __FUNCTION__,     \
+                     _("Call to %s for unexpected type '%s'"), __FUNCTION__,  \
                      esxVI_Type_ToString(item->_type));                       \
         return _error_return;                                                 \
     }
@@ -526,6 +531,13 @@
 
 
 
+#define ESX_VI__TEMPLATE__DISPATCH__CAST_FROM_ANY_TYPE(_type)                 \
+    case esxVI_Type_##_type:                                                  \
+      return esxVI_##_type##_Deserialize(anyType->node,                       \
+                                         (esxVI_##_type **)ptrptr);
+
+
+
 #define ESX_VI__TEMPLATE__DISPATCH__SERIALIZE(_type)                          \
     case esxVI_Type_##_type:                                                  \
       return esxVI_##_type##_Serialize((esxVI_##_type *)item, element,        \
@@ -540,6 +552,13 @@
 
 
 
+#define ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(__type)                        \
+    if (((esxVI_Object *)item)->_type == esxVI_Type_##__type) {               \
+        return item;                                                          \
+    }
+
+
+
 #define ESX_VI__TEMPLATE__DYNAMIC_CAST(__type, _accept)                       \
     esxVI_##__type *                                                          \
     esxVI_##__type##_DynamicCast(void *item)                                  \
@@ -550,6 +569,8 @@
             return NULL;                                                      \
         }                                                                     \
                                                                               \
+        ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(__type)                        \
+                                                                              \
         _accept                                                               \
                                                                               \
         return NULL;                                                          \
@@ -557,13 +578,6 @@
 
 
 
-#define ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(__type)                        \
-    if (((esxVI_Object *)item)->_type == esxVI_Type_##__type) {               \
-        return item;                                                          \
-    }
-
-
-
 #define ESX_VI__TEMPLATE__DYNAMIC_SERIALIZE(__type, _dispatch, _serialize)    \
     ESX_VI__TEMPLATE__SERIALIZE_EXTRA(__type,                                 \
       ESX_VI__TEMPLATE__DISPATCH(__type, _dispatch, -1),                      \
@@ -1357,7 +1371,9 @@ ESX_VI__TEMPLATE__DEEP_COPY(ManagedObjectReference,
 ESX_VI__TEMPLATE__LIST__APPEND(ManagedObjectReference)
 
 /* esxVI_ManagedObjectReference_CastFromAnyType */
-ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(ManagedObjectReference)
+ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(ManagedObjectReference,
+{
+})
 
 /* esxVI_ManagedObjectReference_CastListFromAnyType */
 ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(ManagedObjectReference)
diff --git a/tools/virsh.c b/tools/virsh.c
index 0a63f1b..4108e1e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -5151,6 +5151,10 @@ cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
             vshPrint(ctl, "%-15s %s\n", _("State:"),
                      _("degraded"));
             break;
+        case VIR_STORAGE_POOL_INACCESSIBLE:
+            vshPrint(ctl, "%-15s %s\n", _("State:"),
+                     _("inaccessible"));
+            break;
         }
 
         if (info.state == VIR_STORAGE_POOL_RUNNING ||
-- 
1.7.0.4




More information about the libvir-list mailing list