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