The patch adds the backend driver to support iSCSI format storage pools and volumes for ESX host. The mapping of ESX iSCSI specifics to Libvirt is as follows: 1. ESX static iSCSI target <------> Libvirt Storage Pools 2. ESX iSCSI LUNs <------> Libvirt Storage Volumes. The above understanding is based on http://libvirt.org/storage.html. The operation supported on iSCSI pools includes: 1. List storage pools & volumes. 2. Get xml descriptor operaion on pools & volumes. 3. Lookup operation on pools & volumes by name, uuid and path (if applicable). iSCSI pools does not support operations such as: Create / remove pools and volumes. --- src/Makefile.am | 1 + src/esx/esx_storage_backend_iscsi.c | 807 +++++++++++++++++++++++++++++++++++ src/esx/esx_storage_backend_iscsi.h | 29 ++ src/esx/esx_storage_driver.c | 8 +- src/esx/esx_vi.c | 332 ++++++++++++++ src/esx/esx_vi.h | 18 + src/esx/esx_vi_generator.input | 302 +++++++++++++ src/esx/esx_vi_generator.py | 19 + 8 files changed, 1515 insertions(+), 1 deletion(-) create mode 100644 src/esx/esx_storage_backend_iscsi.c create mode 100644 src/esx/esx_storage_backend_iscsi.h diff --git a/src/Makefile.am b/src/Makefile.am index 4026a15..1668b84 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -494,6 +494,7 @@ ESX_DRIVER_SOURCES = \ esx/esx_network_driver.c esx/esx_network_driver.h \ esx/esx_storage_driver.c esx/esx_storage_driver.h \ esx/esx_storage_backend_vmfs.c esx/esx_storage_backend_vmfs.h \ + esx/esx_storage_backend_iscsi.c esx/esx_storage_backend_iscsi.h \ esx/esx_device_monitor.c esx/esx_device_monitor.h \ esx/esx_secret_driver.c esx/esx_secret_driver.h \ esx/esx_nwfilter_driver.c esx/esx_nwfilter_driver.h \ diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c new file mode 100644 index 0000000..fa4bf45 --- /dev/null +++ b/src/esx/esx_storage_backend_iscsi.c @@ -0,0 +1,807 @@ +/* + * esx_storage_backend_iscsi.c: ESX storage backend for iSCSI handling + * + * Copyright (C) 2012 Ata E Husain Bohra <ata.husain@xxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include <string.h> +#include <stdio.h> +#include <unistd.h> + +#include "internal.h" +#include "md5.h" +#include "util.h" +#include "memory.h" +#include "logging.h" +#include "uuid.h" + +#include "storage_conf.h" +#include "storage_file.h" +#include "esx_storage_backend_iscsi.h" +#include "esx_private.h" +#include "esx_vi.h" +#include "esx_vi_methods.h" +#include "esx_util.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +/* + * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore, + * verify that UUID and MD5 sum match in size, because we rely on that. + */ +verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN); + + + +static int +esxStorageBackendISCSINumberOfStoragePools(virConnectPtr conn) +{ + int count = 0; + esxPrivate *priv = conn->storagePrivateData; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + const esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + bool success = false; + + if (esxVI_LookupHostInternetScsiHba( + priv->primary, &hostInternetScsiHba) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to obtain iSCSI adapter")); + goto cleanup; + } + + /* FIXME: code looks for software iSCSI adapter only */ + if (hostInternetScsiHba == NULL) { + /* iSCSI adapter may not be enabled for this host */ + return 0; + } + + /** + * ESX has two kind of targets: + * 1. staticIscsiTargets + * 2. dynamicIscsiTargets + * For each dynamic target if its reachable a static target is added. + * return iSCSI names for all static targets to avoid duplicate names. + */ + for (target = hostInternetScsiHba->configuredStaticTarget; + target != NULL; + target = target->_next) { + ++count; + } + + success = true; + +cleanup: + + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return success ? count : -1; + +} + + + +static int +esxStorageBackendISCSIListStoragePools(virConnectPtr conn, + char **const names, + const int maxnames) +{ + int count = 0; + esxPrivate *priv = conn->storagePrivateData; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + const esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + bool success = false; + int i = 0; + + if (maxnames ==0) { + return 0; + } + + if (esxVI_LookupHostInternetScsiHba( + priv->primary, &hostInternetScsiHba) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to obtain iSCSI adapter")); + goto cleanup; + } + + /* FIXME: code looks for software iSCSI adapter only */ + if (hostInternetScsiHba == NULL) { + /* iSCSI adapter may not be enabled for this host */ + return 0; + } + + /** + * ESX has two kind of targets: + * 1. staticIscsiTargets + * 2. dynamicIscsiTargets + * For each dynamic target if its reachable a static target is added. + * return iSCSI names for all static targets to avoid duplicate names. + */ + for (target = hostInternetScsiHba->configuredStaticTarget; + target != NULL && count < maxnames; + target = target->_next, ++count) { + names[count] = strdup(target->iScsiName); + + if (names[count] == NULL) { + virReportOOMError(); + goto cleanup; + } + } + + success = true; + +cleanup: + if (! success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + count = -1; + } + + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return success ? count : -1; +} + + + +static virStoragePoolPtr +esxStorageBackendISCSIPoolLookupByName(virConnectPtr conn, + const char *name) +{ + esxPrivate *priv = conn->storagePrivateData; + esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + virStoragePoolPtr pool = NULL; + + /* lookup routine are used by the base driver to determine + * appropriate backend driver, lookup targetName as optional + * parameter + */ + if (esxVI_LookupHostInternetScsiHbaStaticTargetByName( + priv->primary, name, &target, esxVI_Occurrence_OptionalItem) < 0 || + target == NULL) { + goto cleanup; + } + + /** + * HostInternetScsiHbaStaticTarget does not provide a uuid field, + * but iScsiName (or widely known as IQN) is unique across the multiple + * hosts, using it to compute key + */ + + md5_buffer(target->iScsiName, strlen(target->iScsiName), md5); + + pool = virGetStoragePool(conn, name, md5, &esxStorageBackendISCSIDrv, NULL); + + cleanup: + + esxVI_HostInternetScsiHbaStaticTarget_Free(&target); + + return pool; + +} + + + +static virStoragePoolPtr +esxStorageBackendISCSIPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + virStoragePoolPtr pool = NULL; + esxPrivate *priv = conn->storagePrivateData; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + const esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + + if (esxVI_LookupHostInternetScsiHba( + priv->primary, &hostInternetScsiHba) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to obtain iSCSI adapter")); + goto cleanup; + } + + /* FIXME: code just looks for software iSCSI adapter */ + if (hostInternetScsiHba == NULL) { + /* iSCSI adapter may not be enabled for this host */ + return NULL; + } + + for (target = hostInternetScsiHba->configuredStaticTarget; + target != NULL; + target = target->_next) { + md5_buffer(target->iScsiName, strlen(target->iScsiName), md5); + + if (memcmp(uuid, md5, VIR_UUID_STRING_BUFLEN) == 0) { + break; + } + } + + if (target == NULL) { + /* pool not found, error handling done by the base driver */ + goto cleanup; + } + + pool = virGetStoragePool(conn, + target->iScsiName, + md5, + &esxStorageBackendISCSIDrv, + NULL); + + cleanup: + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return pool; + +} + + + +static int +esxStorageBackendISCSIPoolRefresh(virStoragePoolPtr pool, + unsigned int flags) +{ + int result = -1; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_ManagedObjectReference *hostStorageSystem = NULL; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_String *propertyNameList = NULL; + + virCheckFlags(0, -1); + + if (esxVI_String_AppendValueToList(&propertyNameList, + "configManager.storageSystem\0") < 0 || + esxVI_LookupHostSystemProperties(priv->primary, + propertyNameList, &hostSystem) < 0 || + esxVI_GetManagedObjectReference(hostSystem, + "configManager.storageSystem", &hostStorageSystem, + esxVI_Occurrence_RequiredItem) < 0 || + esxVI_LookupHostInternetScsiHba( + priv->primary, &hostInternetScsiHba) < 0) { + goto cleanup; + } + + /** + * ESX does not allow rescan on a particular target, + * rescan all the static targets + */ + if (esxVI_RescanHba(priv->primary, hostStorageSystem, + hostInternetScsiHba->device) < 0) { + goto cleanup; + } + + result = 0; + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ManagedObjectReference_Free(&hostStorageSystem); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return result; + +} + + + +static int +esxStorageBackendISCSIPoolGetInfo(virStoragePoolPtr pool ATTRIBUTE_UNUSED, + virStoragePoolInfoPtr info) +{ + /* these fields are not valid for iSCSI pool */ + info->allocation = info->capacity = info->available = 0; + info->state = VIR_STORAGE_POOL_RUNNING; + + return 0; +} + + + +static char * +esxStorageBackendISCSIPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) +{ + char *xml = NULL; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + const esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + virStoragePoolDef def; + + virCheckFlags(0, NULL); + + memset(&def, 0, sizeof(def)); + + if (esxVI_LookupHostInternetScsiHba(priv->primary, &hostInternetScsiHba)) { + goto cleanup; + } + + for (target = hostInternetScsiHba->configuredStaticTarget; + target != NULL; + target = target->_next) { + if (STREQ(target->iScsiName, pool->name)) { + break; + } + } + + if (target == NULL) { + /* pool not found */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find storage pool with name '%s'"), pool->name); + goto cleanup; + } + + def.name = pool->name; + memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN); + + def.type = VIR_STORAGE_POOL_ISCSI; + + def.source.initiator.iqn = target->iScsiName; + + def.source.nhost = 1; + if (VIR_ALLOC_N(def.source.hosts, def.source.nhost) < 0) { + virReportOOMError(); + goto cleanup; + } + + def.source.hosts[0].name = target->address; + if (target->port) { + def.source.hosts[0].port = target->port->value; + } + + /* TODO: add CHAP authentication params */ + + xml = virStoragePoolDefFormat(&def); + + cleanup: + + VIR_FREE(def.source.hosts); + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return xml; + +} + + + +static int +esxStorageBackendISCSIPoolNumberOfStorageVolumes(virStoragePoolPtr pool) +{ + int count = 0; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL; + const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL; + bool success = false; + + if (esxVI_LookupHostScsiTopologyLunListByTargetName( + priv->primary, pool->name, &hostScsiTopologyLunList) < 0) { + goto cleanup; + } + + for (hostScsiTopologyLun = hostScsiTopologyLunList ; + hostScsiTopologyLun != NULL; + hostScsiTopologyLun = hostScsiTopologyLun->_next) { + ++count; + } + + success = true; + + cleanup: + + esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList); + + return success ? count : -1; + +} + + +static int +esxStorageBackendISCSIPoolListStorageVolumes(virStoragePoolPtr pool, + char **const names, + int maxnames) +{ + int count = 0; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL; + const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL; + esxVI_ScsiLun *scsiLunList = NULL; + const esxVI_ScsiLun *scsiLun = NULL; + bool success = false; + int i = 0; + + if (esxVI_LookupHostScsiTopologyLunListByTargetName( + priv->primary, pool->name, &hostScsiTopologyLunList) < 0) { + goto cleanup; + } + + if (hostScsiTopologyLunList == NULL) { + /* iSCSI adapter may not be enabled on ESX host */ + return 0; + } + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) { + goto cleanup; + } + + /* O^2 but still faster than hash given N is not that large */ + for (scsiLun = scsiLunList; scsiLun != NULL && count < maxnames; + scsiLun = scsiLun->_next) { + for (hostScsiTopologyLun = hostScsiTopologyLunList; + hostScsiTopologyLun != NULL && count < maxnames; + hostScsiTopologyLun = hostScsiTopologyLun->_next) { + if (STREQ(hostScsiTopologyLun->scsiLun, scsiLun->key)) { + names[count] = strdup(scsiLun->deviceName); + + if (names[count] == NULL) { + virReportOOMError(); + goto cleanup; + } + ++count; + } + } + } + + success = true; + + cleanup: + if (! success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + count = -1; + } + + esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList); + esxVI_ScsiLun_Free(&scsiLunList); + + return count; +} + + +static virStorageVolPtr +esxStorageBackendISCSIVolumeLookupByName(virStoragePoolPtr pool, + const char *name) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = pool->conn->storagePrivateData; + esxVI_ScsiLun *scsiLunList = NULL; + const esxVI_ScsiLun *scsiLun = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) { + goto cleanup; + } + + for (scsiLun = scsiLunList; scsiLun != NULL; + scsiLun = scsiLun->_next) { + if (STREQ(scsiLun->deviceName, name)) { + /** + * ScsiLun provides an UUID field that is unique accross + * multiple servers. But this field length is ~55 characters + * compute MD5 hash to transform it to an acceptable + * libvirt format + */ + md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5); + + virUUIDFormat(md5, uuid_string); + + /** + * ScsiLun provides displayName and canonicalName but both are + * optional and its observed that they can be NULL, using + * deviceName to create volume. + */ + volume = virGetStorageVol(pool->conn, pool->name, name, uuid_string, + &esxStorageBackendISCSIDrv, NULL); + break; + } + } + + cleanup: + + esxVI_ScsiLun_Free(&scsiLunList); + + return volume; + +} + + +static virStorageVolPtr +esxStorageBackendISCSIVolumeLookupByPath(virConnectPtr conn, const char *path) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = conn->storagePrivateData; + char *poolName = NULL; + esxVI_ScsiLun *scsiLunList = NULL; + esxVI_ScsiLun *scsiLun = NULL; + const esxVI_HostScsiDisk *hostScsiDisk = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) { + goto cleanup; + } + + for (scsiLun = scsiLunList ; scsiLun != NULL; + scsiLun = scsiLun->_next) { + hostScsiDisk = esxVI_HostScsiDisk_DynamicCast(scsiLun); + + if (hostScsiDisk != NULL && + STREQ(hostScsiDisk->devicePath, path)) { + /* Found matching device */ + if (esxVI_LookupStoragePoolNameByScsiLunKey( + priv->primary, hostScsiDisk->key, &poolName) < 0) { + goto cleanup; + } + + md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5); + + virUUIDFormat(md5, uuid_string); + + volume = virGetStorageVol(conn, poolName, path, uuid_string, + &esxStorageBackendISCSIDrv, NULL); + break; + } + } + + cleanup: + + esxVI_ScsiLun_Free(&scsiLunList); + VIR_FREE(poolName); + + return volume; + +} + + +static virStorageVolPtr +esxStorageBackendISCSIVolumeLookupByKey(virConnectPtr conn, const char *key) +{ + virStorageVolPtr volume = NULL; + esxPrivate *priv = conn->storagePrivateData; + char *poolName = NULL; + esxVI_ScsiLun *scsiLunList = NULL; + const esxVI_ScsiLun *scsiLun = NULL; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + + + /* key may be LUN device path */ + if (STRPREFIX(key, "/")) { + return esxStorageBackendISCSIVolumeLookupByPath(conn, key); + } + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) { + goto cleanup; + } + + for (scsiLun = scsiLunList; scsiLun != NULL; + scsiLun = scsiLun->_next) { + + memset(uuid_string, '\0', sizeof(uuid_string)); + memset(md5, '\0', sizeof(md5)); + + md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5); + + virUUIDFormat(md5, uuid_string); + + if (STREQ(key, uuid_string)) { + /* Found matching UUID */ + if (esxVI_LookupStoragePoolNameByScsiLunKey( + priv->primary, scsiLun->key, &poolName) < 0) { + goto cleanup; + } + + volume = virGetStorageVol(conn, + poolName, + scsiLun->deviceName, + uuid_string, + &esxStorageBackendISCSIDrv, + NULL); + break; + } + } + + cleanup: + + esxVI_ScsiLun_Free(&scsiLunList); + VIR_FREE(poolName); + + return volume; + +} + + + +static virStorageVolPtr +esxStorageBackendISCSIVolumeCreateXML(virStoragePoolPtr pool ATTRIBUTE_UNUSED, + const char *xmldesc ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + + /* not supported operation for iSCSI pools */ + return NULL; +} + + + +static virStorageVolPtr +esxStorageBackendISCSIVolumeCreateXMLFrom( + virStoragePoolPtr pool ATTRIBUTE_UNUSED, + const char *xmldesc ATTRIBUTE_UNUSED, + virStorageVolPtr sourceVolume ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + + /* not supported operation for iSCSI pools */ + return NULL; +} + + + +static char* +esxStorageBackendISCSIVolumeGetXMLDesc(virStorageVolPtr volume, + unsigned int flags) +{ + char *xml = NULL; + esxPrivate *priv = volume->conn->storagePrivateData; + virStoragePoolDef pool; + esxVI_ScsiLun *scsiLunList = NULL; + const esxVI_ScsiLun *scsiLun = NULL; + const esxVI_HostScsiDisk *hostScsiDisk = NULL; + virStorageVolDef def; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + + virCheckFlags(0, NULL); + + memset(&pool, 0, sizeof(pool)); + memset(&def, 0, sizeof(def)); + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) { + goto cleanup; + } + + for (scsiLun = scsiLunList; scsiLun != NULL; + scsiLun = scsiLun->_next) { + hostScsiDisk = + esxVI_HostScsiDisk_DynamicCast((esxVI_ScsiLun *)scsiLun); + + if (hostScsiDisk != NULL && + STREQ(hostScsiDisk->deviceName, volume->name)) { + break; + } + } + + if (hostScsiDisk == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could find volume with name: %s"), volume->name); + goto cleanup; + } + + pool.type = VIR_STORAGE_POOL_ISCSI; + + def.name = volume->name; + + md5_buffer(scsiLun->uuid, strlen(hostScsiDisk->uuid), md5); + + virUUIDFormat(md5, uuid_string); + + if (esxVI_String_DeepCopyValue(&def.key, uuid_string) < 0) { + goto cleanup; + } + + /* iSCSI LUN exposes a block device */ + def.type = VIR_STORAGE_VOL_BLOCK; + + def.target.path = hostScsiDisk->devicePath; + + def.capacity = hostScsiDisk->capacity->block->value * + hostScsiDisk->capacity->blockSize->value; + + def.allocation = def.capacity; + + /* iSCSI LUN(s) hosting a datastore will be auto-mounted by + * ESX host + */ + def.target.format = VIR_STORAGE_FILE_RAW; + + xml = virStorageVolDefFormat(&pool, &def); + + cleanup: + + esxVI_ScsiLun_Free(&scsiLunList); + VIR_FREE(def.key); + + return xml; + +} + +static int +esxStorageBackendISCSIVolumeDelete(virStorageVolPtr volume ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + + /* unsupported operation for iSCSI volume */ + return 1; + +} + + + +static int +esxStorageBackendISCSIVolumeWipe(virStorageVolPtr volume ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + + /* unsupported operation for iSCSI volume */ + return 1; + +} + + + +static char* +esxStorageBackendISCSIVolumeGetPath(virStorageVolPtr volume) +{ + char *path; + + if (virAsprintf(&path, "%s", volume->name) < 0) { + virReportOOMError(); + return NULL; + } + + return path; + +} + + + +virStorageDriver esxStorageBackendISCSIDrv = { + .name = "ESX ISCSI backend", + .open = NULL, /* 1.0.0 */ + .close = NULL, /* 1.0.0 */ + .numOfPools = esxStorageBackendISCSINumberOfStoragePools, /* 1.0.0 */ + .listPools = esxStorageBackendISCSIListStoragePools, /* 1.0.0 */ + .poolLookupByName = esxStorageBackendISCSIPoolLookupByName, /* 1.0.0 */ + .poolLookupByUUID = esxStorageBackendISCSIPoolLookupByUUID, /* 1.0.0 */ + .poolRefresh = esxStorageBackendISCSIPoolRefresh, /* 1.0.0 */ + .poolGetInfo = esxStorageBackendISCSIPoolGetInfo, /* 1.0.0 */ + .poolGetXMLDesc = esxStorageBackendISCSIPoolGetXMLDesc, /* 1.0.0 */ + .poolNumOfVolumes = esxStorageBackendISCSIPoolNumberOfStorageVolumes, /* 1.0.0 */ + .poolListVolumes = esxStorageBackendISCSIPoolListStorageVolumes, /* 1.0.0 */ + .volLookupByName = esxStorageBackendISCSIVolumeLookupByName, /* 1.0.0 */ + .volLookupByKey = esxStorageBackendISCSIVolumeLookupByKey, /* 1.0.0 */ + .volLookupByPath = esxStorageBackendISCSIVolumeLookupByPath, /* 1.0.0 */ + .volCreateXML = esxStorageBackendISCSIVolumeCreateXML, /* 1.0.0 */ + .volCreateXMLFrom = esxStorageBackendISCSIVolumeCreateXMLFrom, /* 1.0.0 */ + .volGetXMLDesc = esxStorageBackendISCSIVolumeGetXMLDesc, /* 1.0.0 */ + .volDelete = esxStorageBackendISCSIVolumeDelete, /* 1.0.0 */ + .volWipe = esxStorageBackendISCSIVolumeWipe, /* 1.0.0 */ + .volGetPath = esxStorageBackendISCSIVolumeGetPath, /* 1.0.0 */ +}; diff --git a/src/esx/esx_storage_backend_iscsi.h b/src/esx/esx_storage_backend_iscsi.h new file mode 100644 index 0000000..f78da46 --- /dev/null +++ b/src/esx/esx_storage_backend_iscsi.h @@ -0,0 +1,29 @@ +/* + * esx_storage_backend_iscsi.h: ESX storage backend for iSCSI handling + * + * Copyright (C) 2012 Ata E Husain Bohra <ata.husain@xxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __ESX_STORAGE_BACKEND_ISCSI_H__ +# define __ESX_STORAGE_BACKEND_ISCSI_H__ + +# include "driver.h" + +extern virStorageDriver esxStorageBackendISCSIDrv; + +#endif /* __ESX_STORAGE_BACKEND_ISCSI_H__ */ diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 5530ea7..6952c69 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -31,6 +31,7 @@ #include "esx_private.h" #include "esx_storage_driver.h" #include "esx_storage_backend_vmfs.h" +#include "esx_storage_backend_iscsi.h" #define VIR_FROM_THIS VIR_FROM_ESX @@ -42,11 +43,13 @@ */ enum { VMFS = 0, + ISCSI, LAST_DRIVER }; static virStorageDriverPtr backendDrv[] = { - &esxStorageBackendVMFSDrv + &esxStorageBackendVMFSDrv, + &esxStorageBackendISCSIDrv }; static virDrvOpenStatus @@ -465,9 +468,12 @@ esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path) * VMFS Datastore path follows cannonical format i.e.: * [<datastore_name>] <file_path> * WHEREAS + * iSCSI LUNs device path follows normal linux path convention */ if (STRPREFIX(path, "[")) { volume = backendDrv[VMFS]->volLookupByPath(conn, path); + } else if (STRPREFIX(path, "/")) { + volume = backendDrv[ISCSI]->volLookupByPath(conn, path); } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected volume path format: %s"), path); diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 9fb2c11..12100d7 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -4875,5 +4875,337 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx, } +int +esxVI_LookupHostInternetScsiHbaStaticTargetByName( + esxVI_Context *ctx, + const char *name, + esxVI_HostInternetScsiHbaStaticTarget **ret, + esxVI_Occurrence occurrence) +{ + int result = -1; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + const esxVI_HostInternetScsiHbaStaticTarget *target = NULL; + + if (esxVI_LookupHostInternetScsiHba(ctx, &hostInternetScsiHba) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to obtain hostInternetScsiHba")); + goto cleanup; + } + + if (hostInternetScsiHba == NULL) { + /* iSCSI adapter may not be enabled for this host */ + return 0; + } + + for (target = hostInternetScsiHba->configuredStaticTarget; + target != NULL; + target = target->_next) { + if (STREQ(target->iScsiName, name)) { + break; + } + } + + if (target == NULL) { + if (occurrence == esxVI_Occurrence_RequiredItem) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find storage pool with name: %s"), name); + } + goto cleanup; + } + + if (esxVI_HostInternetScsiHbaStaticTarget_DeepCopy( + ret, (esxVI_HostInternetScsiHbaStaticTarget *)target) < 0) { + goto cleanup; + } + + result = 0; + + cleanup: + + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return result; +} + + +int +esxVI_LookupHostInternetScsiHba( + esxVI_Context *ctx, + esxVI_HostInternetScsiHba **hostInternetScsiHba) +{ + int result = -1; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_HostHostBusAdapter *hostHostBusAdapterList = NULL; + esxVI_HostHostBusAdapter *hostHostBusAdapter = NULL; + + if (esxVI_String_AppendValueToList(&propertyNameList, + "config.storageDevice.hostBusAdapter\0") < 0 || + esxVI_LookupHostSystemProperties(ctx, propertyNameList, + &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, + "config.storageDevice.hostBusAdapter")) { + if (esxVI_HostHostBusAdapter_CastListFromAnyType( + dynamicProperty->val, &hostHostBusAdapterList) < 0 || + hostHostBusAdapterList == NULL) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + /* See vSphere API documentation about HostInternetScsiHba for details */ + for (hostHostBusAdapter = hostHostBusAdapterList; + hostHostBusAdapter != NULL; + hostHostBusAdapter = hostHostBusAdapter->_next) { + esxVI_HostInternetScsiHba *candidate= + esxVI_HostInternetScsiHba_DynamicCast(hostHostBusAdapter); + + if (candidate) { + if (esxVI_HostInternetScsiHba_DeepCopy(hostInternetScsiHba, + candidate) < 0) { + goto cleanup; + } + break; + } + } + + result = 0; + +cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_HostHostBusAdapter_Free(&hostHostBusAdapterList); + + return result; +} + + +int +esxVI_LookupScsiLunList(esxVI_Context *ctx, + esxVI_ScsiLun **ret) +{ + int result = -1; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_ScsiLun *scsiLunList = NULL; + + if (esxVI_String_AppendValueToList(&propertyNameList, + "config.storageDevice.scsiLun\0") < 0 || + esxVI_LookupHostSystemProperties( + ctx, propertyNameList, &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, + "config.storageDevice.scsiLun")) { + if (esxVI_ScsiLun_CastListFromAnyType(dynamicProperty->val, + &scsiLunList) < 0) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (scsiLunList == NULL || + esxVI_ScsiLun_DeepCopyList(ret, scsiLunList) < 0) { + goto cleanup; + } + + result = 0; + +cleanup: + + esxVI_ScsiLun_Free(&scsiLunList); + + return result; + +} + + +int +esxVI_LookupHostScsiTopologyLunListByTargetName( + esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret) +{ + int result = -1; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL; + const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL; + const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL; + bool found = false; + + if (esxVI_String_AppendValueToList(&propertyNameList, + "config.storageDevice.scsiTopology.adapter\0") < 0 || + esxVI_LookupHostSystemProperties( + ctx, propertyNameList, &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, + "config.storageDevice.scsiTopology.adapter")) { + esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList); + + if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType + (dynamicProperty->val, &hostScsiInterfaceList) < 0)) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (hostScsiInterfaceList == NULL) { + /* iSCSI adapter may not be enabled */ + return 0; + } + + /* See vSphere API documentation about HostScsiTopologyInterface */ + for (hostScsiInterface = hostScsiInterfaceList; + hostScsiInterface != NULL && !found; + hostScsiInterface = hostScsiInterface->_next) { + for (hostScsiTopologyTarget = hostScsiInterface->target; + hostScsiTopologyTarget != NULL; + hostScsiTopologyTarget = hostScsiTopologyTarget->_next) { + const esxVI_HostInternetScsiTargetTransport *candidate = + esxVI_HostInternetScsiTargetTransport_DynamicCast( + hostScsiTopologyTarget->transport); + + if (candidate && STREQ(candidate->iScsiName, name)) { + found = true; + break; + } + } + } + + if (!found || hostScsiTopologyTarget == NULL) { + goto cleanup; + } + + if (esxVI_HostScsiTopologyLun_DeepCopyList( + ret, hostScsiTopologyTarget->lun) < 0) { + goto cleanup; + } + + if (*ret == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Target not found")); + goto cleanup; + } + + result = 0; + + cleanup: + + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList); + + return result; +} + + +int +esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx, + const char *key, + char **poolName) +{ + int result = -1; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_String *propertyNameList = NULL; + esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL; + const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL; + const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL; + bool found = false; + + if (esxVI_String_AppendValueToList(&propertyNameList, + "config.storageDevice.scsiTopology.adapter\0") < 0 || + esxVI_LookupHostSystemProperties( + ctx, propertyNameList, &hostSystem) < 0) { + goto cleanup; + } + + for (dynamicProperty = hostSystem->propSet; + dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, + "config.storageDevice.scsiTopology.adapter")) { + esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList); + + if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType + (dynamicProperty->val, &hostScsiInterfaceList) < 0)) { + goto cleanup; + } + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + if (hostScsiInterfaceList == NULL) { + /* iSCSI adapter may not be enabled */ + return 0; + } + + /* See vSphere API documentation about HostScsiTopologyInterface */ + for (hostScsiInterface = hostScsiInterfaceList; + hostScsiInterface != NULL && !found; + hostScsiInterface = hostScsiInterface->_next) { + for (hostScsiTopologyTarget = hostScsiInterface->target; + hostScsiTopologyTarget != NULL; + hostScsiTopologyTarget = hostScsiTopologyTarget->_next) { + const esxVI_HostInternetScsiTargetTransport *candidate = + esxVI_HostInternetScsiTargetTransport_DynamicCast( + hostScsiTopologyTarget->transport); + + if (candidate) { + /* iterate hostScsiTopologyLun list to find matching key */ + const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = + hostScsiTopologyTarget->lun; + for (; hostScsiTopologyLun != NULL; + hostScsiTopologyLun = hostScsiTopologyLun->_next) { + if (STREQ(hostScsiTopologyLun->scsiLun, key)) { + *poolName = strdup(candidate->iScsiName); + + if (*poolName == NULL) { + virReportOOMError(); + goto cleanup; + } + } + } + /* hostScsiTopologyLun iteration done, terminate loop */ + break; + } + } + } + + result = 0; + + cleanup: + esxVI_ObjectContent_Free(&hostSystem); + esxVI_String_Free(&propertyNameList); + esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList); + + return result; +} + + #include "esx_vi.generated.c" diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index d7895a0..8e56044 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -528,6 +528,24 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo, int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion); +int esxVI_LookupHostInternetScsiHbaStaticTargetByName(esxVI_Context *ctx, + const char *name, esxVI_HostInternetScsiHbaStaticTarget **ret, + esxVI_Occurrence occurrence); + +int esxVI_LookupHostInternetScsiHba( + esxVI_Context *ctx, + esxVI_HostInternetScsiHba **hostInternetScsiHba); + +int esxVI_LookupScsiLunList(esxVI_Context *ctx, esxVI_ScsiLun **ret); + +int esxVI_LookupHostScsiTopologyLunListByTargetName( + esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret); + +int +esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx, + const char *key, + char **poolName); + # include "esx_vi.generated.h" #endif /* __ESX_VI_H__ */ diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index c4a3e56..21f5b10 100644 --- a/src/esx/esx_vi_generator.input +++ b/src/esx/esx_vi_generator.input @@ -58,6 +58,14 @@ enum AutoStartWaitHeartbeatSetting end +enum FibreChannelPortType + fabric + loop + pointToPoint + unknown +end + + enum ManagedEntityStatus gray green @@ -128,6 +136,12 @@ enum VirtualMachinePowerState end +enum vStorageSupport + vStorageUnknown +end + + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Objects # @@ -262,6 +276,13 @@ object HostAutoStartManagerConfig AutoStartPowerInfo powerInfo ol end +object HostBlockAdapterTargetTransport extends HostTargetTransport +end + + +object HostBlockHba extends HostHostBusAdapter +end + object HostConfigManager ManagedObjectReference cpuScheduler o @@ -309,6 +330,31 @@ object HostDatastoreBrowserSearchSpec Boolean sortFoldersFirst o end +object HostDevice + String deviceName r + String deviceType r +end + + +object HostDiskDimensionsLba + Int blockSize r + Long block r +end + + +object HostFibreChannelHba extends HostHostBusAdapter + Long nodeWorldWideName r + FibreChannelPortType portType r + Long portWorldWideName r + Long speed r +end + + +object HostFibreChannelTargetTransport extends HostTargetTransport + Long nodeWorldWideName r + Long portWorldWideName r +end + object HostFileSystemVolume String type r @@ -323,6 +369,164 @@ object HostIpConfig String subnetMask o end +object HostHostBusAdapter + Int bus r + String device r + String driver o + String key o + String model r + String pci o + String status r +end + + +object HostInternetScsiTargetTransport extends HostTargetTransport + String iScsiName r + String iScsiAlias r + String address ol + +end + + +object HostInternetScsiHba extends HostHostBusAdapter + HostInternetScsiHbaAuthenticationCapabilities authenticationCapabilities r + HostInternetScsiHbaAuthenticationProperties authenticationProperties r + HostInternetScsiHbaDiscoveryCapabilities discoveryCapabilities r + HostInternetScsiHbaDiscoveryProperties discoveryProperties r + HostInternetScsiHbaIPCapabilities ipCapabilities r + HostInternetScsiHbaIPProperties ipProperties r + String iScsiName r + Boolean isSoftwareBased r + HostInternetScsiHbaParamValue advancedOptions ol + HostInternetScsiHbaSendTarget configuredSendTarget ol + HostInternetScsiHbaStaticTarget configuredStaticTarget ol + Int currentSpeedMb o + HostInternetScsiHbaDigestCapabilities digestCapabilities o + HostInternetScsiHbaDigestProperties digestProperties o + String iScsiAlias o + Int maxSpeedMb o + OptionDef supportedAdvancedOptions ol +end + + + +object HostInternetScsiHbaAuthenticationCapabilities + Boolean chapAuthSettable r + Boolean krb5AuthSettable r + Boolean spkmAuthSettable r + Boolean srpAuthSettable r + Boolean mutualChapSettable o + Boolean targetChapSettable o + Boolean targetMutualChapSettable o +end + + +object HostInternetScsiHbaAuthenticationProperties + Boolean chapAuthEnabled r + String chapAuthenticationType o + Boolean chapInherited o + String chapName o + String chapSecret o + String mutualChapAuthenticationType o + Boolean mutualChapInherited o + String mutualChapName o + String mutualChapSecret o +end + + +object HostInternetScsiHbaDigestCapabilities + Boolean dataDigestSettable o + Boolean headerDigestSettable o + Boolean targetDataDigestSettable o + Boolean targetHeaderDigestSettable o +end + + +object HostInternetScsiHbaDigestProperties + Boolean dataDigestInherited o + String dataDigestType o + Boolean headerDigestInherited o + String headerDigestType o +end + + +object HostInternetScsiHbaDiscoveryCapabilities + Boolean iSnsDiscoverySettable r + Boolean sendTargetsDiscoverySettable r + Boolean slpDiscoverySettable r + Boolean staticTargetDiscoverySettable r +end + + +object HostInternetScsiHbaDiscoveryProperties + Boolean iSnsDiscoveryEnabled r + Boolean sendTargetsDiscoveryEnabled r + Boolean slpDiscoveryEnabled r + Boolean staticTargetDiscoveryEnabled r + String iSnsDiscoveryMethod o + String iSnsHost o + String slpDiscoveryMethod o + String slpHost o +end + +object HostInternetScsiHbaIPCapabilities + Boolean addressSettable r + Boolean alternateDnsServerAddressSettable r + Boolean defaultGatewaySettable r + Boolean ipConfigurationMethodSettable r + Boolean primaryDnsServerAddressSettable r + Boolean subnetMaskSettable r + Boolean arpRedirectSettable o + Boolean hostNameAsTargetAddress o + Boolean ipv6Supported o + Boolean mtuSettable o + Boolean nameAliasSettable o +end + + +object HostInternetScsiHbaIPProperties + Boolean dhcpConfigurationEnabled r + String address o + String alternateDnsServerAddress o + Boolean arpRedirectEnabled o + String defaultGateway o + String ipv6Address o + String ipv6DefaultGateway o + Boolean jumboFramesEnabled o + String mac o + Int mtu o + String primaryDnsServerAddress o + String subnetMask o +end + + +object HostInternetScsiHbaParamValue extends OptionValue + Boolean isInherited o +end + + +object HostInternetScsiHbaSendTarget + String address r + HostInternetScsiHbaParamValue advancedOptions ol + HostInternetScsiHbaAuthenticationProperties authenticationProperties o + HostInternetScsiHbaDigestProperties digestProperties o + String parent o + Int port o + OptionDef supportedAdvancedOptions ol +end + + +object HostInternetScsiHbaStaticTarget + String address r + String iScsiName r + HostInternetScsiHbaParamValue advancedOptions ol + HostInternetScsiHbaAuthenticationProperties authenticationProperties o + HostInternetScsiHbaDigestProperties digestProperties o + String parent o + Int port o + OptionDef supportedAdvancedOptions ol +end + object HostMountInfo String path o @@ -418,12 +622,55 @@ object HostPortGroupSpec HostNetworkPolicy policy r end +object HostParallelScsiHba extends HostHostBusAdapter +end + + +object HostParallelScsiTargetTransport extends HostTargetTransport +end + + +object HostScsiDisk extends ScsiLun + HostDiskDimensionsLba capacity r + String devicePath r +end + object HostScsiDiskPartition String diskName r Int partition r end +object HostScsiTopology + HostScsiTopologyInterface adapater ol +end + + +object HostScsiTopologyInterface + String adapter r + String key r + HostScsiTopologyTarget target ol +end + + +object HostScsiTopologyLun + String key r + Int lun r + String scsiLun r +end + + +object HostScsiTopologyTarget + String key r + Int target r + HostScsiTopologyLun lun ol + HostTargetTransport transport o +end + + +object HostTargetTransport +end + object HostVirtualSwitch String name r @@ -526,12 +773,22 @@ object ObjectUpdate MissingProperty missingSet i end +object OptionDef extends ElementDescription + OptionType optionType r +end + object OptionType Boolean valueIsReadonly o end +object OptionValue + String key r + AnyType value r +end + + object PerfCounterInfo Int key r ElementDescription nameInfo r @@ -664,6 +921,45 @@ object SelectionSpec end +object ScsiLun extends HostDevice + String lunType r + String operationalState rl + String uuid r + ScsiLunDurableName alternateName ol + String canonicalName o + ScsiLunCapabilities capabilities o + ScsiLunDescriptor descriptor ol + String displayName o + ScsiLunDurableName durableName o + String key o + String model o + Int queueDepth o + String revision o + Int scsiLevel o + String serialNumber o + Byte standardInquiry ol + String vendor o +end + + +object ScsiLunCapabilities + Boolean updateDisplayNameSupported r +end + + +object ScsiLunDescriptor + String id r + String quality r +end + + +object ScsiLunDurableName + String namespace r + Byte namespaceId r + Byte data ol +end + + object ServiceContent ManagedObjectReference rootFolder r ManagedObjectReference propertyCollector r @@ -1138,6 +1434,12 @@ method RemoveVirtualSwitch end +method RescanHba + ManagedObjectReference _this r + String hbaDevice r +end + + method RetrieveProperties returns ObjectContent ol ManagedObjectReference _this:propertyCollector r PropertyFilterSpec specSet rl diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py index 2883ac0..af4e7e8 100755 --- a/src/esx/esx_vi_generator.py +++ b/src/esx/esx_vi_generator.py @@ -1532,6 +1532,21 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN Object.FEATURE__ANY_TYPE, "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, + "HostHostBusAdapter" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE, + "HostInternetScsiHba" : Object.FEATURE__DYNAMIC_CAST | + Object.FEATURE__DEEP_COPY, + "HostInternetScsiTargetTransport" : Object.FEATURE__DYNAMIC_CAST, + "HostScsiDisk" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DYNAMIC_CAST, + "HostScsiTopologyInterface" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE, + "HostScsiTopologyLun" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST | + Object.FEATURE__DEEP_COPY, + "HostScsiTopologyTarget" : Object.FEATURE__ANY_TYPE | + Object.FEATURE__LIST, "HostPortGroup" : Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, "HostVirtualSwitch" : Object.FEATURE__DEEP_COPY | @@ -1543,6 +1558,10 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, "ResourcePoolResourceUsage" : Object.FEATURE__ANY_TYPE, + "ScsiLun" : Object.FEATURE__LIST | + Object.FEATURE__ANY_TYPE | + Object.FEATURE__DEEP_COPY, + "ScsiLunDurableName" : Object.FEATURE__LIST, "ServiceContent" : Object.FEATURE__DESERIALIZE, "SharesInfo" : Object.FEATURE__ANY_TYPE, "TaskInfo" : Object.FEATURE__LIST | -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list