[libvirt] [PATCH v3 00/11] esx: various improvements

- fix a bug in the esx VI generator - implement connectListAllStoragePools, so virConnectListAllStoragePools() works - implement connectListAllNetworks, so virConnectListAllNetworks() works - implement storagePoolListAllVolumes, so virStoragePoolListAllVolumes() works - implement domainGetHostname, so virDomainGetHostname() works - implement domainInterfaceAddresses only for VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT, so virDomainInterfaceAddresses() partially works - improve virErrorNumber for some virReportError() calls TODO: - handle the comments in v2 about esxStoragePoolListAllVolumes() Changes from v2: - pushed patches reviewed with no changes required - integrated the Reviewed-By in patches that required very minor changes, will push them on request - fixed bool/size_t error/count handling - bumped API version numbers to 6.0.0 - fixed a bug in the esx VI generator - implemented domainGetHostname - implemented domainInterfaceAddresses Pino Toscano (11): esx: implement connectListAllStoragePools esx: implement connectListAllNetworks esx: split datastorePathToStorageVol helper esx: split scsilunToStorageVol helper esx: implement storagePoolListAllVolumes esx: improve some of the virErrorNumber used esx: implement domainGetHostname esx: generator: fix free of elements in lists esx: generator: add GuestNicInfo object esx: implement domainInterfaceAddresses docs: document implemented APIs in esx docs/drvesx.html.in | 7 + docs/news.xml | 14 ++ scripts/esx_vi_generator.py | 27 +++- src/esx/esx_driver.c | 220 ++++++++++++++++++++++++++++ src/esx/esx_network_driver.c | 68 ++++++++- src/esx/esx_storage_backend_iscsi.c | 202 +++++++++++++++++++++---- src/esx/esx_storage_backend_vmfs.c | 220 ++++++++++++++++++++++++++-- src/esx/esx_storage_driver.c | 84 +++++++++++ src/esx/esx_util.c | 4 +- src/esx/esx_vi.c | 36 ++--- src/esx/esx_vi_generator.input | 54 +++++++ 11 files changed, 862 insertions(+), 74 deletions(-) -- 2.24.1

Implement the .connectListAllStoragePools storage API in the esx storage driver, and in all its subdrivers. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- src/esx/esx_storage_backend_iscsi.c | 70 +++++++++++++++++++++ src/esx/esx_storage_backend_vmfs.c | 96 +++++++++++++++++++++++++++++ src/esx/esx_storage_driver.c | 65 +++++++++++++++++++ 3 files changed, 231 insertions(+) diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 72ab0d3cb0..b6e0841dda 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -779,6 +779,75 @@ esxStorageVolGetPath(virStorageVolPtr volume) +#define MATCH(FLAG) (flags & (FLAG)) +static int +esxConnectListAllStoragePools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + int ret = -1; + size_t count = 0; + esxPrivate *priv = conn->privateData; + esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL; + esxVI_HostInternetScsiHbaStaticTarget *target; + size_t i; + + /* this driver provides only iSCSI pools */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE) && + !(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI))) + return 0; + + if (esxVI_LookupHostInternetScsiHba(priv->primary, + &hostInternetScsiHba) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to obtain iSCSI adapter")); + goto cleanup; + } + + /* FIXME: code looks for software iSCSI adapter only */ + if (!hostInternetScsiHba) { + /* 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 it's reachable a static target is added. + * return iSCSI names for all static targets to avoid duplicate names. + */ + for (target = hostInternetScsiHba->configuredStaticTarget; + target; target = target->_next) { + virStoragePoolPtr pool; + + pool = targetToStoragePool(conn, target->iScsiName, target); + if (!pool) + goto cleanup; + + if (VIR_APPEND_ELEMENT(*pools, count, pool) < 0) + goto cleanup; + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*pools) { + for (i = 0; i < count; ++i) + VIR_FREE((*pools)[i]); + VIR_FREE(*pools); + } + } + + esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba); + + return ret; +} +#undef MATCH + + + virStorageDriver esxStorageBackendISCSI = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 1.0.1 */ .connectListStoragePools = esxConnectListStoragePools, /* 1.0.1 */ @@ -799,4 +868,5 @@ virStorageDriver esxStorageBackendISCSI = { .storageVolDelete = esxStorageVolDelete, /* 1.0.1 */ .storageVolWipe = esxStorageVolWipe, /* 1.0.1 */ .storageVolGetPath = esxStorageVolGetPath, /* 1.0.1 */ + .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ }; diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 61b30c3c1d..41f0d4577b 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -1461,6 +1461,101 @@ esxStorageVolGetPath(virStorageVolPtr volume) +#define MATCH(FLAG) (flags & (FLAG)) +static int +esxConnectListAllStoragePools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + int ret = -1; + esxPrivate *priv = conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_ObjectContent *datastoreList = NULL; + esxVI_ObjectContent *datastore = NULL; + size_t count = 0; + size_t i; + virStoragePoolPtr pool; + const bool checkPoolType = MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE); + + if (esxVI_String_AppendValueToList(&propertyNameList, + "summary.name") < 0) { + goto cleanup; + } + + if (checkPoolType && + esxVI_String_AppendValueToList(&propertyNameList, + "info") < 0) { + goto cleanup; + } + + if (esxVI_LookupDatastoreList(priv->primary, propertyNameList, + &datastoreList) < 0) { + goto cleanup; + } + + for (datastore = datastoreList; datastore; + datastore = datastore->_next) { + const char *name = NULL; + + for (dynamicProperty = datastore->propSet; dynamicProperty; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "summary.name")) { + if (esxVI_AnyType_ExpectType(dynamicProperty->val, + esxVI_Type_String) < 0) { + goto cleanup; + } + + name = dynamicProperty->val->string; + } + } + + if (!name) + goto cleanup; + + if (checkPoolType) { + int poolType; + + if (datastorePoolType(datastore, &poolType) < 0) + goto cleanup; + + if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) && + (poolType == VIR_STORAGE_POOL_DIR)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) && + (poolType == VIR_STORAGE_POOL_FS)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) && + (poolType == VIR_STORAGE_POOL_NETFS)))) + continue; + } + + pool = datastoreToStoragePoolPtr(conn, name, datastore); + if (!pool) + goto cleanup; + + if (VIR_APPEND_ELEMENT(*pools, count, pool) < 0) + goto cleanup; + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*pools) { + for (i = 0; i < count; ++i) + VIR_FREE((*pools)[i]); + VIR_FREE(*pools); + } + } + + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&datastoreList); + + return ret; +} +#undef MATCH + + + virStorageDriver esxStorageBackendVMFS = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */ .connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */ @@ -1481,4 +1576,5 @@ virStorageDriver esxStorageBackendVMFS = { .storageVolGetInfo = esxStorageVolGetInfo, /* 0.8.4 */ .storageVolGetXMLDesc = esxStorageVolGetXMLDesc, /* 0.8.4 */ .storageVolGetPath = esxStorageVolGetPath, /* 0.8.4 */ + .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ }; diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 8a34732b45..9e14b8b0ac 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -517,6 +517,70 @@ esxStoragePoolIsPersistent(virStoragePoolPtr pool G_GNUC_UNUSED) +#define MATCH(FLAG) (flags & (FLAG)) +static int +esxConnectListAllStoragePools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + int ret = -1; + esxPrivate *priv = conn->privateData; + size_t count = 0; + size_t i, j; + + virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1); + + /* + * ESX storage pools are always active, persistent, and + * autostarted, so return zero elements in case we are asked + * for pools different than that. + * + * Filtering by type will be done by each backend. + */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) && + !(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE))) + return 0; + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT) && + !(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT))) + return 0; + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART) && + !(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART))) + return 0; + + if (esxVI_EnsureSession(priv->primary) < 0) + return -1; + + for (i = 0; i < LAST_BACKEND; ++i) { + virStoragePoolPtr *new_pools = 0; + int tmp = backends[i]->connectListAllStoragePools(conn, &new_pools, flags); + + if (tmp < 0) + goto cleanup; + + for (j = 0; j < tmp; ++j) { + if (VIR_APPEND_ELEMENT(*pools, count, new_pools[j]) < 0) + goto cleanup; + } + VIR_FREE(new_pools); + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*pools) { + for (i = 0; i < count; ++i) + VIR_FREE((*pools)[i]); + VIR_FREE(*pools); + } + } + + return ret; +} +#undef MATCH + + + virStorageDriver esxStorageDriver = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */ .connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */ @@ -544,4 +608,5 @@ virStorageDriver esxStorageDriver = { .storageVolGetPath = esxStorageVolGetPath, /* 0.8.4 */ .storagePoolIsActive = esxStoragePoolIsActive, /* 0.8.2 */ .storagePoolIsPersistent = esxStoragePoolIsPersistent, /* 0.8.2 */ + .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ }; -- 2.24.1

Implement the .connectListAllNetworks networks API in the esx network driver. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- src/esx/esx_network_driver.c | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 4f359c61e2..f14d309293 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -863,6 +863,69 @@ esxNetworkIsPersistent(virNetworkPtr network G_GNUC_UNUSED) +#define MATCH(FLAG) (flags & (FLAG)) +static int +esxConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + int ret = -1; + esxPrivate *priv = conn->privateData; + esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL; + esxVI_HostVirtualSwitch *hostVirtualSwitch = NULL; + size_t count = 0; + size_t i; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + /* + * ESX networks are always active, persistent, and + * autostarted, so return zero elements in case we are asked + * for networks different than that. + */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) && + !(MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE))) + return 0; + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) && + !(MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT))) + return 0; + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) && + !(MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART))) + return 0; + + if (esxVI_EnsureSession(priv->primary) < 0 || + esxVI_LookupHostVirtualSwitchList(priv->primary, + &hostVirtualSwitchList) < 0) { + return -1; + } + + for (hostVirtualSwitch = hostVirtualSwitchList; hostVirtualSwitch; + hostVirtualSwitch = hostVirtualSwitch->_next) { + virNetworkPtr net = virtualswitchToNetwork(conn, hostVirtualSwitch); + + if (VIR_APPEND_ELEMENT(*nets, count, net) < 0) + goto cleanup; + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*nets) { + for (i = 0; i < count; ++i) + VIR_FREE((*nets)[i]); + VIR_FREE(*nets); + } + } + + esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList); + + return ret; +} +#undef MATCH + + + virNetworkDriver esxNetworkDriver = { .connectNumOfNetworks = esxConnectNumOfNetworks, /* 0.10.0 */ .connectListNetworks = esxConnectListNetworks, /* 0.10.0 */ @@ -877,4 +940,5 @@ virNetworkDriver esxNetworkDriver = { .networkSetAutostart = esxNetworkSetAutostart, /* 0.10.0 */ .networkIsActive = esxNetworkIsActive, /* 0.10.0 */ .networkIsPersistent = esxNetworkIsPersistent, /* 0.10.0 */ + .connectListAllNetworks = esxConnectListAllNetworks, /* 6.0.0 */ }; -- 2.24.1

Move the creation of a virStorageVolPtr object by lookup out of esxStorageVolLookupByPath in an own helper. This way it can be used also in other functions. Signed-off-by: Pino Toscano <ptoscano@redhat.com> Reviewed-by: Cole Robinson <crobinso@redhat.com> --- src/esx/esx_storage_backend_vmfs.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 41f0d4577b..1d7f9afda1 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -695,32 +695,41 @@ esxStorageVolLookupByName(virStoragePoolPtr pool, +static virStorageVolPtr +datastorePathToStorageVol(virConnectPtr conn, const char *pool, + const char *path) +{ + esxPrivate *priv = conn->privateData; + g_autofree char *key = NULL; + + if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path, + &key) < 0) { + return NULL; + } + + return virGetStorageVol(conn, pool, path, key, + &esxStorageBackendVMFS, NULL); +} + + + static virStorageVolPtr esxStorageVolLookupByPath(virConnectPtr conn, const char *path) { virStorageVolPtr volume = NULL; - esxPrivate *priv = conn->privateData; char *datastoreName = NULL; char *directoryAndFileName = NULL; - char *key = NULL; if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL, &directoryAndFileName) < 0) { goto cleanup; } - if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path, - &key) < 0) { - goto cleanup; - } - - volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key, - &esxStorageBackendVMFS, NULL); + volume = datastorePathToStorageVol(conn, datastoreName, directoryAndFileName); cleanup: VIR_FREE(datastoreName); VIR_FREE(directoryAndFileName); - VIR_FREE(key); return volume; } -- 2.24.1

Move the creation of a virStorageVolPtr object from the esxVI_ScsiLun object of a SCSI lun out of esxStorageVolLookupByName and esxStorageVolLookupByPath in an own helper. This way it can be used also in other functions. Signed-off-by: Pino Toscano <ptoscano@redhat.com> Reviewed-by: Cole Robinson <crobinso@redhat.com> --- src/esx/esx_storage_backend_iscsi.c | 60 +++++++++++++++-------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index b6e0841dda..50de7d88ac 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -440,6 +440,35 @@ esxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, +static virStorageVolPtr +scsiLunToStorageVol(virConnectPtr conn, esxVI_ScsiLun *scsiLun, + const char *pool) +{ + /* VIR_CRYPTO_HASH_SIZE_MD5 = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[VIR_CRYPTO_HASH_SIZE_MD5]; + char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; + + /* + * ScsiLun provides a UUID field that is unique across + * multiple servers. But this field length is ~55 characters + * compute MD5 hash to transform it to an acceptable + * libvirt format + */ + if (virCryptoHashBuf(VIR_CRYPTO_HASH_MD5, scsiLun->uuid, md5) < 0) + return NULL; + 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. + */ + return virGetStorageVol(conn, pool, scsiLun->deviceName, uuid_string, + &esxStorageBackendISCSI, NULL); +} + + + static virStorageVolPtr esxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) @@ -448,9 +477,6 @@ esxStorageVolLookupByName(virStoragePoolPtr pool, esxPrivate *priv = pool->conn->privateData; esxVI_ScsiLun *scsiLunList = NULL; esxVI_ScsiLun *scsiLun; - /* VIR_CRYPTO_HASH_SIZE_MD5 = VIR_UUID_BUFLEN = 16 */ - unsigned char md5[VIR_CRYPTO_HASH_SIZE_MD5]; - char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) goto cleanup; @@ -458,23 +484,7 @@ esxStorageVolLookupByName(virStoragePoolPtr pool, for (scsiLun = scsiLunList; scsiLun; scsiLun = scsiLun->_next) { if (STREQ(scsiLun->deviceName, name)) { - /* - * ScsiLun provides a UUID field that is unique across - * multiple servers. But this field length is ~55 characters - * compute MD5 hash to transform it to an acceptable - * libvirt format - */ - if (virCryptoHashBuf(VIR_CRYPTO_HASH_MD5, scsiLun->uuid, md5) < 0) - goto cleanup; - 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, - &esxStorageBackendISCSI, NULL); + volume = scsiLunToStorageVol(pool->conn, scsiLun, pool->name); break; } } @@ -496,9 +506,6 @@ esxStorageVolLookupByPath(virConnectPtr conn, const char *path) esxVI_ScsiLun *scsiLun; esxVI_HostScsiDisk *hostScsiDisk = NULL; char *poolName = NULL; - /* VIR_CRYPTO_HASH_SIZE_MD5 = VIR_UUID_BUFLEN = 16 */ - unsigned char md5[VIR_CRYPTO_HASH_SIZE_MD5]; - char uuid_string[VIR_UUID_STRING_BUFLEN] = ""; if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) goto cleanup; @@ -516,12 +523,7 @@ esxStorageVolLookupByPath(virConnectPtr conn, const char *path) goto cleanup; } - if (virCryptoHashBuf(VIR_CRYPTO_HASH_MD5, scsiLun->uuid, md5) < 0) - goto cleanup; - virUUIDFormat(md5, uuid_string); - - volume = virGetStorageVol(conn, poolName, path, uuid_string, - &esxStorageBackendISCSI, NULL); + volume = scsiLunToStorageVol(conn, scsiLun, poolName); break; } } -- 2.24.1

Implement the .storagePoolListAllVolumes storage API in the esx storage driver, and in all its subdrivers. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- src/esx/esx_storage_backend_iscsi.c | 68 +++++++++++++++++++++++ src/esx/esx_storage_backend_vmfs.c | 83 +++++++++++++++++++++++++++++ src/esx/esx_storage_driver.c | 19 +++++++ 3 files changed, 170 insertions(+) diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 50de7d88ac..cd83a0fbfd 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -850,6 +850,73 @@ esxConnectListAllStoragePools(virConnectPtr conn, +static int +esxStoragePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) +{ + int ret = -1; + size_t count = 0; + esxPrivate *priv = pool->conn->privateData; + esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL; + esxVI_HostScsiTopologyLun *hostScsiTopologyLun; + esxVI_ScsiLun *scsiLunList = NULL; + esxVI_ScsiLun *scsiLun = NULL; + size_t i; + + virCheckFlags(0, -1); + + if (esxVI_LookupHostScsiTopologyLunListByTargetName + (priv->primary, pool->name, &hostScsiTopologyLunList) < 0) { + goto cleanup; + } + + if (!hostScsiTopologyLunList) { + /* iSCSI adapter may not be enabled on ESX host */ + return 0; + } + + if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) + goto cleanup; + + for (scsiLun = scsiLunList; scsiLun; + scsiLun = scsiLun->_next) { + for (hostScsiTopologyLun = hostScsiTopologyLunList; + hostScsiTopologyLun; + hostScsiTopologyLun = hostScsiTopologyLun->_next) { + if (STREQ(hostScsiTopologyLun->scsiLun, scsiLun->key)) { + virStorageVolPtr volume; + + volume = scsiLunToStorageVol(pool->conn, scsiLun, pool->name); + if (!volume) + goto cleanup; + + if (VIR_APPEND_ELEMENT(*vols, count, volume) < 0) + goto cleanup; + } + + } + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*vols) { + for (i = 0; i < count; ++i) + VIR_FREE((*vols)[i]); + VIR_FREE(*vols); + } + } + + esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList); + esxVI_ScsiLun_Free(&scsiLunList); + + return ret; +} + + + virStorageDriver esxStorageBackendISCSI = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 1.0.1 */ .connectListStoragePools = esxConnectListStoragePools, /* 1.0.1 */ @@ -871,4 +938,5 @@ virStorageDriver esxStorageBackendISCSI = { .storageVolWipe = esxStorageVolWipe, /* 1.0.1 */ .storageVolGetPath = esxStorageVolGetPath, /* 1.0.1 */ .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ + .storagePoolListAllVolumes = esxStoragePoolListAllVolumes, /* 6.0.0 */ }; diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 1d7f9afda1..70005717cb 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -1565,6 +1565,88 @@ esxConnectListAllStoragePools(virConnectPtr conn, +static int +esxStoragePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) +{ + int ret = -1; + esxPrivate *priv = pool->conn->privateData; + esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL; + esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL; + esxVI_FileInfo *fileInfo = NULL; + char *directoryAndFileName = NULL; + size_t length; + size_t count = 0; + size_t i; + + virCheckFlags(0, -1); + + if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name, + &searchResultsList) < 0) { + goto cleanup; + } + + /* Interpret search result */ + for (searchResults = searchResultsList; searchResults; + searchResults = searchResults->_next) { + VIR_FREE(directoryAndFileName); + + if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL, + &directoryAndFileName) < 0) { + goto cleanup; + } + + /* Strip trailing separators */ + length = strlen(directoryAndFileName); + + while (length > 0 && directoryAndFileName[length - 1] == '/') { + directoryAndFileName[length - 1] = '\0'; + --length; + } + + /* Build volume names */ + for (fileInfo = searchResults->file; fileInfo; + fileInfo = fileInfo->_next) { + g_autofree char *datastorePath = NULL; + virStorageVolPtr volume; + + if (length < 1) { + datastorePath = g_strdup(fileInfo->path); + } else { + datastorePath = g_strdup_printf("%s/%s", + directoryAndFileName, + fileInfo->path); + } + + volume = datastorePathToStorageVol(pool->conn, pool->name, datastorePath); + if (!volume) + goto cleanup; + + if (VIR_APPEND_ELEMENT(*vols, count, volume) < 0) + goto cleanup; + } + } + + ret = count; + + cleanup: + if (ret < 0) { + if (*vols) { + for (i = 0; i < count; ++i) + VIR_FREE((*vols)[i]); + VIR_FREE(*vols); + } + } + + esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList); + VIR_FREE(directoryAndFileName); + + return ret; +} + + + virStorageDriver esxStorageBackendVMFS = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */ .connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */ @@ -1586,4 +1668,5 @@ virStorageDriver esxStorageBackendVMFS = { .storageVolGetXMLDesc = esxStorageVolGetXMLDesc, /* 0.8.4 */ .storageVolGetPath = esxStorageVolGetPath, /* 0.8.4 */ .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ + .storagePoolListAllVolumes = esxStoragePoolListAllVolumes, /* 6.0.0 */ }; diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 9e14b8b0ac..8470a31c68 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -581,6 +581,24 @@ esxConnectListAllStoragePools(virConnectPtr conn, +static int +esxStoragePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) +{ + esxPrivate *priv = pool->conn->privateData; + virStorageDriverPtr backend = pool->privateData; + + virCheckNonNullArgReturn(pool->privateData, -1); + + if (esxVI_EnsureSession(priv->primary) < 0) + return -1; + + return backend->storagePoolListAllVolumes(pool, vols, flags); +} + + + virStorageDriver esxStorageDriver = { .connectNumOfStoragePools = esxConnectNumOfStoragePools, /* 0.8.2 */ .connectListStoragePools = esxConnectListStoragePools, /* 0.8.2 */ @@ -609,4 +627,5 @@ virStorageDriver esxStorageDriver = { .storagePoolIsActive = esxStoragePoolIsActive, /* 0.8.2 */ .storagePoolIsPersistent = esxStoragePoolIsPersistent, /* 0.8.2 */ .connectListAllStoragePools = esxConnectListAllStoragePools, /* 6.0.0 */ + .storagePoolListAllVolumes = esxStoragePoolListAllVolumes, /* 6.0.0 */ }; -- 2.24.1

A lot of virReportError() calls use VIR_ERR_INTERNAL_ERROR to represent the number of the error, even in cases where there is one fitting more. Hence, replace some of them with better virErrorNumber values. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- src/esx/esx_network_driver.c | 4 ++-- src/esx/esx_storage_backend_iscsi.c | 4 ++-- src/esx/esx_storage_backend_vmfs.c | 12 +++++----- src/esx/esx_util.c | 4 ++-- src/esx/esx_vi.c | 36 ++++++++++++++--------------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index f14d309293..2a76831606 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -355,7 +355,7 @@ esxNetworkDefineXML(virConnectPtr conn, const char *xml) for (hostPortGroup = hostPortGroupList; hostPortGroup; hostPortGroup = hostPortGroup->_next) { if (STREQ(def->portGroups[i].name, hostPortGroup->spec->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NETWORK_EXIST, _("HostPortGroup with name '%s' exists already"), def->portGroups[i].name); goto cleanup; @@ -388,7 +388,7 @@ esxNetworkDefineXML(virConnectPtr conn, const char *xml) if (def->forward.ifs[i].type != VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_SUPPORT, _("unsupported device type in network %s " "interface pool"), def->name); diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index cd83a0fbfd..1e54cef948 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -321,7 +321,7 @@ esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) if (!target) { /* pool not found */ - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_STORAGE_POOL, _("Could not find storage pool with name '%s'"), pool->name); goto cleanup; @@ -701,7 +701,7 @@ esxStorageVolGetXMLDesc(virStorageVolPtr volume, } if (!scsiLun) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_STORAGE_VOL, _("Could find volume with name: %s"), volume->name); goto cleanup; } diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 70005717cb..d4b23c6d51 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -906,7 +906,7 @@ esxStorageVolCreateXML(virStoragePoolPtr pool, goto cleanup; if (def->type != VIR_STORAGE_VOL_FILE) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_NO_SUPPORT, "%s", _("Creating non-file volumes is not supported")); goto cleanup; } @@ -922,7 +922,7 @@ esxStorageVolCreateXML(virStoragePoolPtr pool, } if (!virStringHasCaseSuffix(def->name, ".vmdk")) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_SUPPORT, _("Volume name '%s' has unsupported suffix, " "expecting '.vmdk'"), def->name); goto cleanup; @@ -1041,7 +1041,7 @@ esxStorageVolCreateXML(virStoragePoolPtr pool, key = g_strdup(datastorePath); } } else { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_SUPPORT, _("Creation of %s volumes is not supported"), virStorageFileFormatTypeToString(def->target.format)); goto cleanup; @@ -1120,7 +1120,7 @@ esxStorageVolCreateXMLFrom(virStoragePoolPtr pool, goto cleanup; if (def->type != VIR_STORAGE_VOL_FILE) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_NO_SUPPORT, "%s", _("Creating non-file volumes is not supported")); goto cleanup; } @@ -1136,7 +1136,7 @@ esxStorageVolCreateXMLFrom(virStoragePoolPtr pool, } if (!virStringHasCaseSuffix(def->name, ".vmdk")) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_SUPPORT, _("Volume name '%s' has unsupported suffix, " "expecting '.vmdk'"), def->name); goto cleanup; @@ -1221,7 +1221,7 @@ esxStorageVolCreateXMLFrom(virStoragePoolPtr pool, key = g_strdup(datastorePath); } } else { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_NO_SUPPORT, _("Creation of %s volumes is not supported"), virStorageFileFormatTypeToString(def->target.format)); goto cleanup; diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index c265528056..dc0983a47d 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -218,7 +218,7 @@ esxUtil_ParseDatastorePath(const char *datastorePath, char **datastoreName, if ((datastoreName && *datastoreName) || (directoryName && *directoryName) || (directoryAndFileName && *directoryAndFileName)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } @@ -227,7 +227,7 @@ esxUtil_ParseDatastorePath(const char *datastorePath, char **datastoreName, /* Expected format: '[<datastore>] <path>' where <path> is optional */ if (!(tmp = STRSKIP(copyOfDatastorePath, "[")) || *tmp == ']' || !(preliminaryDatastoreName = strtok_r(tmp, "]", &saveptr))) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_INVALID_ARG, _("Datastore path '%s' doesn't have expected format " "'[<datastore>] <path>'"), datastorePath); goto cleanup; diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 4e67d76bfe..3c5a994848 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -435,7 +435,7 @@ esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content) int responseCode = 0; if (!content) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } @@ -552,13 +552,13 @@ esxVI_SharedCURL_Add(esxVI_SharedCURL *shared, esxVI_CURL *curl) size_t i; if (!curl->handle) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot share uninitialized CURL handle")); return -1; } if (curl->shared) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot share CURL handle that is already shared")); return -1; } @@ -607,19 +607,19 @@ int esxVI_SharedCURL_Remove(esxVI_SharedCURL *shared, esxVI_CURL *curl) { if (!curl->handle) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot unshare uninitialized CURL handle")); return -1; } if (!curl->shared) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot unshare CURL handle that is not shared")); return -1; } if (curl->shared != shared) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (share) mismatch")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("CURL (share) mismatch")); return -1; } @@ -727,13 +727,13 @@ int esxVI_MultiCURL_Add(esxVI_MultiCURL *multi, esxVI_CURL *curl) { if (!curl->handle) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot add uninitialized CURL handle to a multi handle")); return -1; } if (curl->multi) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot add CURL handle to a multi handle twice")); return -1; } @@ -773,21 +773,21 @@ int esxVI_MultiCURL_Remove(esxVI_MultiCURL *multi, esxVI_CURL *curl) { if (!curl->handle) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot remove uninitialized CURL handle from a " "multi handle")); return -1; } if (!curl->multi) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Cannot remove CURL handle from a multi handle when it " "wasn't added before")); return -1; } if (curl->multi != multi) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (multi) mismatch")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("CURL (multi) mismatch")); return -1; } @@ -994,7 +994,7 @@ esxVI_Context_Connect(esxVI_Context *ctx, const char *url, if (!ctx || !url || !ipAddress || !username || !password || ctx->url || ctx->service || ctx->curl) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } @@ -1405,7 +1405,7 @@ esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName, xmlNodePtr responseNode = NULL; if (!request || !response || *response) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } @@ -1548,7 +1548,7 @@ esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName, } } } else { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_HTTP_ERROR, _("HTTP response code %d for call to '%s'"), (*response)->responseCode, methodName); goto cleanup; @@ -1599,14 +1599,14 @@ esxVI_Enumeration_CastFromAnyType(const esxVI_Enumeration *enumeration, size_t i; if (!anyType || !value) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } *value = 0; /* undefined */ if (anyType->type != enumeration->type) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_INVALID_ARG, _("Expecting type '%s' but found '%s'"), esxVI_Type_ToString(enumeration->type), esxVI_AnyType_TypeToString(anyType)); @@ -1635,7 +1635,7 @@ esxVI_Enumeration_Serialize(const esxVI_Enumeration *enumeration, const char *name = NULL; if (!element || !output) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } @@ -1674,7 +1674,7 @@ esxVI_Enumeration_Deserialize(const esxVI_Enumeration *enumeration, char *name = NULL; if (!value) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument")); return -1; } -- 2.24.1

Implement the .domainGetHostname hypervisor driver API to get the hostname of a running guest (needs VMware Tools). Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- docs/drvesx.html.in | 3 +++ src/esx/esx_driver.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in index ac7bc645d1..465daafc2e 100644 --- a/docs/drvesx.html.in +++ b/docs/drvesx.html.in @@ -789,6 +789,9 @@ Enter administrator password for example-vcenter.com: performed the ESX server raises an error and the driver reports it. </p> <ul> + <li> + <code>virDomainGetHostname</code> + </li> <li> <code>virDomainReboot</code> </li> diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 0ede65279a..39e3faeb8f 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -5069,6 +5069,59 @@ esxDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags) } +static char * +esxDomainGetHostname(virDomainPtr domain, + unsigned int flags) +{ + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + char *hostname = NULL; + char *new_hostname = NULL; + + virCheckFlags(0, NULL); + + if (esxVI_EnsureSession(priv->primary) < 0) + return NULL; + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "runtime.powerState\0" + "guest.hostName") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_OptionalItem) || + esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) { + goto cleanup; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Domain is not powered on")); + goto cleanup; + } + + if (esxVI_GetStringValue(virtualMachine, "guest.hostName", + &hostname, esxVI_Occurrence_OptionalItem) < 0) { + goto cleanup; + } + + if (!hostname) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("hostName field not available (missing VMware Tools?)")); + goto cleanup; + } + + new_hostname = g_strdup(hostname); + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + + return new_hostname; +} + + static virHypervisorDriver esxHypervisorDriver = { .name = "ESX", .connectOpen = esxConnectOpen, /* 0.7.0 */ @@ -5149,6 +5202,7 @@ static virHypervisorDriver esxHypervisorDriver = { .domainSnapshotDelete = esxDomainSnapshotDelete, /* 0.8.0 */ .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */ .domainHasManagedSaveImage = esxDomainHasManagedSaveImage, /* 1.2.13 */ + .domainGetHostname = esxDomainGetHostname, /* 6.0.0 */ }; -- 2.24.1

When a list is freed, we iterate through all the items, invoking the free function for each; the actual free function called for each element is the function of the actual type of each element, and thus the @_next pointer in the element struct has the same type as the element itself. Currently, the free function gets the parent of the current element type, and invoke its free function to continue freeing the list. However, in case the hierarchy of the classes has more than 1 level (i.e. Class <- SubClass <- SubSubClass), the invoked free function is only the parent class' one, and not the actual base class of the hierarchy. To fix that, change the generator to get the ancestor of a class, and invoking that instead. Also, avoid to set the @_next back, as it is not needed. Fixes commits 5cff36e39ae691fbd7c40597df1732eecf294150 and f76c6dde2e33233566e886d96e76b5fe0c102d9a. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- scripts/esx_vi_generator.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/scripts/esx_vi_generator.py b/scripts/esx_vi_generator.py index 048f5dde9e..9e3151943b 100755 --- a/scripts/esx_vi_generator.py +++ b/scripts/esx_vi_generator.py @@ -751,13 +751,13 @@ class Object(GenericObject): source += "{\n" if self.features & Object.FEATURE__LIST: - if self.extends is not None: + ancestor = get_ancestor(self) + if ancestor: # avoid "dereferencing type-punned pointer will break # strict-aliasing rules" warnings - source += " esxVI_%s *next = (esxVI_%s *)item->_next;\n\n" \ - % (self.extends, self.extends) - source += " esxVI_%s_Free(&next);\n" % self.extends - source += " item->_next = (esxVI_%s *)next;\n\n" % self.name + source += " esxVI_%s *baseNext = (esxVI_%s *)item->_next;\n" \ + % (ancestor, ancestor) + source += " esxVI_%s_Free(&baseNext);\n\n" % ancestor else: source += " esxVI_%s_Free(&item->_next);\n\n" % self.name @@ -1250,6 +1250,21 @@ def is_known_type(type): type in enums_by_name) +def get_ancestor(obj): + if not obj.extends: + return None + ancestor = None + try: + ancestor = ancestor_by_name[obj.extends] + except KeyError: + parent = objects_by_name[obj.extends] + ancestor = get_ancestor(parent) + if not ancestor: + ancestor = parent.name + ancestor_by_name[name] = ancestor + return ancestor + + def open_and_print(filename): if filename.startswith("./"): print(" GEN " + filename[2:]) @@ -1346,6 +1361,7 @@ managed_objects_by_name = {} enums_by_name = {} methods_by_name = {} block = None +ancestor_by_name = {} # parse input file -- 2.24.1

Add the definition of the GuestNicInfo object, with all the required objects for it. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- scripts/esx_vi_generator.py | 1 + src/esx/esx_vi_generator.input | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/scripts/esx_vi_generator.py b/scripts/esx_vi_generator.py index 9e3151943b..761bb2d8de 100755 --- a/scripts/esx_vi_generator.py +++ b/scripts/esx_vi_generator.py @@ -1297,6 +1297,7 @@ additional_object_features = { "DatastoreHostMount": (Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE), "DatastoreInfo": Object.FEATURE__ANY_TYPE | Object.FEATURE__DYNAMIC_CAST, + "GuestNicInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, "HostConfigManager": Object.FEATURE__ANY_TYPE, "HostCpuIdInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE, "HostDatastoreBrowserSearchResults": (Object.FEATURE__LIST | diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input index 22c114e0aa..bd6ac72a18 100644 --- a/src/esx/esx_vi_generator.input +++ b/src/esx/esx_vi_generator.input @@ -277,6 +277,18 @@ object FolderFileQuery extends FileQuery end +object GuestNicInfo + Boolean connected r + Int deviceConfigId r + NetDnsConfigInfo dnsConfig o + String ipAddress ol + NetIpConfigInfo ipConfig o + String macAddress o + NetBIOSConfigInfo netBIOSConfig o + String network o +end + + object HostAutoStartManagerConfig AutoStartDefaults defaults o AutoStartPowerInfo powerInfo ol @@ -770,6 +782,48 @@ object NasDatastoreInfo extends DatastoreInfo end +object NetBIOSConfigInfo + String mode r +end + + +object NetDhcpConfigInfo + NetDhcpConfigInfoDhcpOptions ipv4 o + NetDhcpConfigInfoDhcpOptions ipv6 o +end + + +object NetDhcpConfigInfoDhcpOptions + KeyAnyValue config ol + Boolean enable r +end + + +object NetDnsConfigInfo + Boolean dhcp r + String domainName r + String hostName r + String ipAddress ol + String searchDomain ol +end + + +object NetIpConfigInfo + Boolean autoConfigurationEnabled o + NetDhcpConfigInfo dhcp o + NetIpConfigInfoIpAddress ipAddress ol +end + + +object NetIpConfigInfoIpAddress + String ipAddress r + DateTime lifetime o + String origin o + Int prefixLength r + String state o +end + + object ObjectContent ManagedObjectReference obj r DynamicProperty propSet ol -- 2.24.1

Implement the .domainInterfaceAddresses hypervisor API, although only functional for the VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT source. Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- docs/drvesx.html.in | 4 ++ src/esx/esx_driver.c | 166 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in index 465daafc2e..c4a2ae78a8 100644 --- a/docs/drvesx.html.in +++ b/docs/drvesx.html.in @@ -792,6 +792,10 @@ Enter administrator password for example-vcenter.com: <li> <code>virDomainGetHostname</code> </li> + <li> + <code>virDomainInterfaceAddresses</code> (only for the + <code>VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT</code> source) + </li> <li> <code>virDomainReboot</code> </li> diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 39e3faeb8f..73b8f32f1b 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -5122,6 +5122,171 @@ esxDomainGetHostname(virDomainPtr domain, } +static int +esxParseIPAddress(const char *ipAddress, int prefixLength, + virDomainIPAddress *addr) +{ + virSocketAddr tmp_addr; + virIPAddrType addr_type; + + if (virSocketAddrParseAny(&tmp_addr, ipAddress, AF_UNSPEC, false) <= 0) + return 0; + + switch (VIR_SOCKET_ADDR_FAMILY(&tmp_addr)) { + case AF_INET: + addr_type = VIR_IP_ADDR_TYPE_IPV4; + break; + case AF_INET6: + addr_type = VIR_IP_ADDR_TYPE_IPV6; + break; + default: + return 0; + } + + addr->type = addr_type; + addr->addr = g_strdup(ipAddress); + addr->prefix = prefixLength; + + return 1; +} + + +static int +esxDomainInterfaceAddresses(virDomainPtr domain, + virDomainInterfacePtr **ifaces, + unsigned int source, + unsigned int flags) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_DynamicProperty *dynamicProperty; + esxVI_GuestNicInfo *guestNicInfoList = NULL; + esxVI_GuestNicInfo *guestNicInfo = NULL; + virDomainInterfacePtr *ifaces_ret = NULL; + size_t ifaces_count = 0; + size_t i; + int ret; + + virCheckFlags(0, -1); + if (source != VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Unknown IP address data source %d"), + source); + return -1; + } + + if (esxVI_EnsureSession(priv->primary) < 0) + return -1; + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "runtime.powerState\0" + "guest.net") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_RequiredItem) || + esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) { + goto cleanup; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Domain is not powered on")); + goto cleanup; + } + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "guest.net")) { + if (esxVI_GuestNicInfo_CastListFromAnyType + (dynamicProperty->val, &guestNicInfoList) < 0) { + goto cleanup; + } + } + } + + if (!guestNicInfoList) + goto cleanup; + + for (guestNicInfo = guestNicInfoList; guestNicInfo; + guestNicInfo = guestNicInfo->_next) { + virDomainInterfacePtr iface = NULL; + size_t addrs_count = 0; + + if (guestNicInfo->connected != esxVI_Boolean_True || + !guestNicInfo->network) { + continue; + } + + if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) < 0) + goto cleanup; + + if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) < 0) + goto cleanup; + + iface = ifaces_ret[ifaces_count - 1]; + iface->naddrs = 0; + iface->name = g_strdup(guestNicInfo->network); + iface->hwaddr = g_strdup(guestNicInfo->macAddress); + + if (guestNicInfo->ipConfig) { + esxVI_NetIpConfigInfoIpAddress *ipAddress; + for (ipAddress = guestNicInfo->ipConfig->ipAddress; ipAddress; + ipAddress = ipAddress->_next) { + virDomainIPAddress ip_addr; + + ret = esxParseIPAddress(ipAddress->ipAddress, + ipAddress->prefixLength->value, &ip_addr); + if (ret < 0) + goto cleanup; + else if (ret == 0) + continue; + + if (VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr) < 0) + goto cleanup; + } + } else { + esxVI_String *str; + for (str = guestNicInfo->ipAddress; str; + str = str->_next) { + virDomainIPAddress ip_addr; + + /* Not even the netmask seems available... */ + ret = esxParseIPAddress(str->value, 0, &ip_addr); + if (ret < 0) + goto cleanup; + else if (ret == 0) + continue; + + if (VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr) < 0) + goto cleanup; + + } + } + + iface->naddrs = addrs_count; + } + + *ifaces = ifaces_ret; + result = ifaces_count; + + cleanup: + if (result < 0) { + if (ifaces_ret) { + for (i = 0; i < ifaces_count; i++) + virDomainInterfaceFree(ifaces_ret[i]); + } + } + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&virtualMachine); + esxVI_GuestNicInfo_Free(&guestNicInfoList); + + return result; +} + + static virHypervisorDriver esxHypervisorDriver = { .name = "ESX", .connectOpen = esxConnectOpen, /* 0.7.0 */ @@ -5203,6 +5368,7 @@ static virHypervisorDriver esxHypervisorDriver = { .connectIsAlive = esxConnectIsAlive, /* 0.9.8 */ .domainHasManagedSaveImage = esxDomainHasManagedSaveImage, /* 1.2.13 */ .domainGetHostname = esxDomainGetHostname, /* 6.0.0 */ + .domainInterfaceAddresses = esxDomainInterfaceAddresses, /* 6.0.0 */ }; -- 2.24.1

On 12/20/19 3:58 PM, Pino Toscano wrote:
Implement the .domainInterfaceAddresses hypervisor API, although only functional for the VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT source.
Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- docs/drvesx.html.in | 4 ++ src/esx/esx_driver.c | 166 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+)
diff --git a/docs/drvesx.html.in b/docs/drvesx.html.in index 465daafc2e..c4a2ae78a8 100644 --- a/docs/drvesx.html.in +++ b/docs/drvesx.html.in @@ -792,6 +792,10 @@ Enter administrator password for example-vcenter.com: <li> <code>virDomainGetHostname</code> </li> + <li> + <code>virDomainInterfaceAddresses</code> (only for the + <code>VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT</code> source) + </li> <li> <code>virDomainReboot</code> </li> diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 39e3faeb8f..73b8f32f1b 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -5122,6 +5122,171 @@ esxDomainGetHostname(virDomainPtr domain, }
+static int +esxParseIPAddress(const char *ipAddress, int prefixLength, + virDomainIPAddress *addr) +{ + virSocketAddr tmp_addr; + virIPAddrType addr_type; + + if (virSocketAddrParseAny(&tmp_addr, ipAddress, AF_UNSPEC, false) <= 0) + return 0; + + switch (VIR_SOCKET_ADDR_FAMILY(&tmp_addr)) { + case AF_INET: + addr_type = VIR_IP_ADDR_TYPE_IPV4; + break; + case AF_INET6: + addr_type = VIR_IP_ADDR_TYPE_IPV6; + break; + default: + return 0; + } + + addr->type = addr_type; + addr->addr = g_strdup(ipAddress); + addr->prefix = prefixLength; + + return 1; +} + + +static int +esxDomainInterfaceAddresses(virDomainPtr domain, + virDomainInterfacePtr **ifaces, + unsigned int source, + unsigned int flags) +{ + int result = -1; + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *virtualMachine = NULL; + esxVI_VirtualMachinePowerState powerState; + esxVI_DynamicProperty *dynamicProperty; + esxVI_GuestNicInfo *guestNicInfoList = NULL; + esxVI_GuestNicInfo *guestNicInfo = NULL; + virDomainInterfacePtr *ifaces_ret = NULL; + size_t ifaces_count = 0; + size_t i; + int ret; + + virCheckFlags(0, -1); + if (source != VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Unknown IP address data source %d"), + source); + return -1; + } + + if (esxVI_EnsureSession(priv->primary) < 0) + return -1; + + if (esxVI_String_AppendValueListToList(&propertyNameList, + "runtime.powerState\0" + "guest.net") < 0 || + esxVI_LookupVirtualMachineByUuid(priv->primary, domain->uuid, + propertyNameList, &virtualMachine, + esxVI_Occurrence_RequiredItem) || + esxVI_GetVirtualMachinePowerState(virtualMachine, &powerState) < 0) { + goto cleanup; + } + + if (powerState != esxVI_VirtualMachinePowerState_PoweredOn) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Domain is not powered on")); + goto cleanup; + } + + for (dynamicProperty = virtualMachine->propSet; dynamicProperty; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "guest.net")) { + if (esxVI_GuestNicInfo_CastListFromAnyType + (dynamicProperty->val, &guestNicInfoList) < 0) { + goto cleanup; + } + } + } + + if (!guestNicInfoList) + goto cleanup; + + for (guestNicInfo = guestNicInfoList; guestNicInfo; + guestNicInfo = guestNicInfo->_next) { + virDomainInterfacePtr iface = NULL; + size_t addrs_count = 0; + + if (guestNicInfo->connected != esxVI_Boolean_True || + !guestNicInfo->network) { + continue; + } + + if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) < 0) + goto cleanup; + + if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) < 0) + goto cleanup; + + iface = ifaces_ret[ifaces_count - 1]; + iface->naddrs = 0; + iface->name = g_strdup(guestNicInfo->network); + iface->hwaddr = g_strdup(guestNicInfo->macAddress); + + if (guestNicInfo->ipConfig) { + esxVI_NetIpConfigInfoIpAddress *ipAddress; + for (ipAddress = guestNicInfo->ipConfig->ipAddress; ipAddress; + ipAddress = ipAddress->_next) { + virDomainIPAddress ip_addr; + + ret = esxParseIPAddress(ipAddress->ipAddress, + ipAddress->prefixLength->value, &ip_addr); + if (ret < 0) + goto cleanup; + else if (ret == 0) + continue; + + if (VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr) < 0) + goto cleanup; + } + } else { + esxVI_String *str; + for (str = guestNicInfo->ipAddress; str; + str = str->_next) { + virDomainIPAddress ip_addr; + + /* Not even the netmask seems available... */ + ret = esxParseIPAddress(str->value, 0, &ip_addr); + if (ret < 0) + goto cleanup; + else if (ret == 0) + continue; + + if (VIR_APPEND_ELEMENT(iface->addrs, addrs_count, ip_addr) < 0) + goto cleanup; + + } + } + + iface->naddrs = addrs_count; + } + + *ifaces = ifaces_ret; + result = ifaces_count; + + cleanup: + if (result < 0) { + if (ifaces_ret) { + for (i = 0; i < ifaces_count; i++) + virDomainInterfaceFree(ifaces_ret[i]); + }
Small nit, ifaces_count can't be anything else than zero without ifaces_ret being not NULL. So I'd drop the ifces_ret check. I'll also post a patch to remove it from other places around our code. Michal

Signed-off-by: Pino Toscano <ptoscano@redhat.com> --- docs/news.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/news.xml b/docs/news.xml index 055353b9a5..6c29011d53 100644 --- a/docs/news.xml +++ b/docs/news.xml @@ -86,6 +86,20 @@ lzop should be used. </description> </change> + <change> + <summary> + esx: implement various APIs + </summary> + <description> + The <code>virConnectListAllStoragePools()</code>, + <code>virConnectListAllNetworks()</code>, + <code>virStoragePoolListAllVolumes()</code>, + <code>virDomainGetHostname</code>, + and <code>virDomainInterfaceAddresses</code> (only for + <code>VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT</code> source) + APIs were implemented in the esx driver. + </description> + </change> </section> <section title="Bug fixes"> </section> -- 2.24.1

On 12/20/19 3:58 PM, Pino Toscano wrote:
- fix a bug in the esx VI generator - implement connectListAllStoragePools, so virConnectListAllStoragePools() works - implement connectListAllNetworks, so virConnectListAllNetworks() works - implement storagePoolListAllVolumes, so virStoragePoolListAllVolumes() works - implement domainGetHostname, so virDomainGetHostname() works - implement domainInterfaceAddresses only for VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT, so virDomainInterfaceAddresses() partially works - improve virErrorNumber for some virReportError() calls
TODO: - handle the comments in v2 about esxStoragePoolListAllVolumes()
Changes from v2: - pushed patches reviewed with no changes required - integrated the Reviewed-By in patches that required very minor changes, will push them on request - fixed bool/size_t error/count handling - bumped API version numbers to 6.0.0 - fixed a bug in the esx VI generator - implemented domainGetHostname - implemented domainInterfaceAddresses
Pino Toscano (11): esx: implement connectListAllStoragePools esx: implement connectListAllNetworks esx: split datastorePathToStorageVol helper esx: split scsilunToStorageVol helper esx: implement storagePoolListAllVolumes esx: improve some of the virErrorNumber used esx: implement domainGetHostname esx: generator: fix free of elements in lists esx: generator: add GuestNicInfo object esx: implement domainInterfaceAddresses docs: document implemented APIs in esx
docs/drvesx.html.in | 7 + docs/news.xml | 14 ++ scripts/esx_vi_generator.py | 27 +++- src/esx/esx_driver.c | 220 ++++++++++++++++++++++++++++ src/esx/esx_network_driver.c | 68 ++++++++- src/esx/esx_storage_backend_iscsi.c | 202 +++++++++++++++++++++---- src/esx/esx_storage_backend_vmfs.c | 220 ++++++++++++++++++++++++++-- src/esx/esx_storage_driver.c | 84 +++++++++++ src/esx/esx_util.c | 4 +- src/esx/esx_vi.c | 36 ++--- src/esx/esx_vi_generator.input | 54 +++++++ 11 files changed, 862 insertions(+), 74 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (2)
-
Michal Privoznik
-
Pino Toscano