mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
esx: Add read-only storage pool access
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.
This commit is contained in:
parent
6e6acb776b
commit
ddb4ae0ca9
@ -20,6 +20,7 @@ src/cpu/cpu_x86.c
|
||||
src/datatypes.c
|
||||
src/driver.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
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
126
src/esx/esx_vi.c
126
src/esx/esx_vi.c
@ -1529,6 +1529,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,
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user