From c756e4370adb3d7a3d1ba85fd516691f29562e87 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Wed, 12 Jun 2024 16:13:56 +0530 Subject: [PATCH] List volumes by service offering id (#9211) * Allow listing of volumes by service offering id * Address comments --- .../command/user/volume/ListVolumesCmd.java | 11 ++++ .../com/cloud/api/query/QueryManagerImpl.java | 14 ++++- ui/src/components/view/SearchView.vue | 62 ++++++++++++++++++- ui/src/config/section/storage.js | 2 +- 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index 18a32e324f7..6510106557b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; @@ -82,6 +83,12 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme RoleType.Admin}) private String storageId; + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, + entityType = ServiceOfferingResponse.class, + description = "list volumes by disk offering of a service offering. If both service offering and " + + "disk offering are passed, service offering is ignored", since = "4.19.1") + private Long serviceOfferingId; + @Parameter(name = ApiConstants.DISK_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "list volumes by disk offering", since = "4.4") private Long diskOfferingId; @@ -123,6 +130,10 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme return podId; } + public Long getServiceOfferingId() { + return serviceOfferingId; + } + public Long getDiskOfferingId() { return diskOfferingId; } diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index f83192350db..320432c5f9f 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -2406,7 +2406,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Map tags = cmd.getTags(); String storageId = cmd.getStorageId(); Long clusterId = cmd.getClusterId(); - Long diskOffId = cmd.getDiskOfferingId(); + Long serviceOfferingId = cmd.getServiceOfferingId(); + Long diskOfferingId = cmd.getDiskOfferingId(); Boolean display = cmd.getDisplay(); String state = cmd.getState(); boolean shouldListSystemVms = shouldListSystemVms(cmd, caller.getId()); @@ -2416,6 +2417,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + if (diskOfferingId == null && serviceOfferingId != null) { + ServiceOfferingVO serviceOffering = _srvOfferingDao.findById(serviceOfferingId); + if (serviceOffering != null) { + diskOfferingId = serviceOffering.getDiskOfferingId(); + } + } + Ternary domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); @@ -2546,8 +2554,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q } } - if (diskOffId != null) { - sc.setParameters("diskOfferingId", diskOffId); + if (diskOfferingId != null) { + sc.setParameters("diskOfferingId", diskOfferingId); } if (id != null) { diff --git a/ui/src/components/view/SearchView.vue b/ui/src/components/view/SearchView.vue index 43f07c7456b..c284b8a635a 100644 --- a/ui/src/components/view/SearchView.vue +++ b/ui/src/components/view/SearchView.vue @@ -285,7 +285,7 @@ export default { } if (['zoneid', 'domainid', 'imagestoreid', 'storageid', 'state', 'account', 'hypervisor', 'level', 'clusterid', 'podid', 'groupid', 'entitytype', 'accounttype', 'systemvmtype', 'scope', 'provider', - 'type'].includes(item) + 'type', 'serviceofferingid', 'diskofferingid'].includes(item) ) { type = 'list' } else if (item === 'tags') { @@ -397,6 +397,8 @@ export default { let podIndex = -1 let clusterIndex = -1 let groupIndex = -1 + let serviceOfferingIndex = -1 + let diskOfferingIndex = -1 if (arrayField.includes('type')) { if (this.$route.path === '/alert') { @@ -464,6 +466,18 @@ export default { promises.push(await this.fetchInstanceGroups(searchKeyword)) } + if (arrayField.includes('serviceofferingid')) { + serviceOfferingIndex = this.fields.findIndex(item => item.name === 'serviceofferingid') + this.fields[serviceOfferingIndex].loading = true + promises.push(await this.fetchServiceOfferings(searchKeyword)) + } + + if (arrayField.includes('diskofferingid')) { + diskOfferingIndex = this.fields.findIndex(item => item.name === 'diskofferingid') + this.fields[diskOfferingIndex].loading = true + promises.push(await this.fetchDiskOfferings(searchKeyword)) + } + Promise.all(promises).then(response => { if (typeIndex > -1) { const types = response.filter(item => item.type === 'type') @@ -525,6 +539,20 @@ export default { this.fields[groupIndex].opts = this.sortArray(groups[0].data) } } + + if (serviceOfferingIndex > -1) { + const serviceOfferings = response.filter(item => item.type === 'serviceofferingid') + if (serviceOfferings && serviceOfferings.length > 0) { + this.fields[serviceOfferingIndex].opts = this.sortArray(serviceOfferings[0].data) + } + } + + if (diskOfferingIndex > -1) { + const diskOfferings = response.filter(item => item.type === 'diskofferingid') + if (diskOfferings && diskOfferings.length > 0) { + this.fields[diskOfferingIndex].opts = this.sortArray(diskOfferings[0].data) + } + } }).finally(() => { if (typeIndex > -1) { this.fields[typeIndex].loading = false @@ -550,6 +578,12 @@ export default { if (groupIndex > -1) { this.fields[groupIndex].loading = false } + if (serviceOfferingIndex > -1) { + this.fields[serviceOfferingIndex].loading = false + } + if (diskOfferingIndex > -1) { + this.fields[diskOfferingIndex].loading = false + } this.fillFormFieldValues() }) }, @@ -699,6 +733,32 @@ export default { }) }) }, + fetchServiceOfferings (searchKeyword) { + return new Promise((resolve, reject) => { + api('listServiceOfferings', { listAll: true, keyword: searchKeyword }).then(json => { + const serviceOfferings = json.listserviceofferingsresponse.serviceoffering + resolve({ + type: 'serviceofferingid', + data: serviceOfferings + }) + }).catch(error => { + reject(error.response.headers['x-description']) + }) + }) + }, + fetchDiskOfferings (searchKeyword) { + return new Promise((resolve, reject) => { + api('listDiskOfferings', { listAll: true, keyword: searchKeyword }).then(json => { + const diskOfferings = json.listdiskofferingsresponse.diskoffering + resolve({ + type: 'diskofferingid', + data: diskOfferings + }) + }).catch(error => { + reject(error.response.headers['x-description']) + }) + }) + }, fetchAlertTypes () { if (this.alertTypes.length > 0) { return new Promise((resolve, reject) => { diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index ff0fd99242d..772f2a3fd3b 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -91,7 +91,7 @@ export default { } ], searchFilters: () => { - var filters = ['name', 'zoneid', 'domainid', 'account', 'state', 'tags'] + var filters = ['name', 'zoneid', 'domainid', 'account', 'state', 'tags', 'serviceofferingid', 'diskofferingid'] if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { filters.push('storageid') }