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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list