From c7989c0f24e83ac8e2f09059b06f1c3cc770abb2 Mon Sep 17 00:00:00 2001 From: Fabricio Duarte Date: Wed, 17 Dec 2025 23:16:00 -0300 Subject: [PATCH 1/4] Fix VM and volume metrics listing regression --- .../metrics/MetricsServiceImpl.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java index c305d9312baa..4606b14fd9c3 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java @@ -254,9 +254,15 @@ protected Pair, Integer> searchForUserVmsInternal(ListVMsUsageHis final Long id = cmd.getId(); Account caller = CallContext.current().getCallingAccount(); List permittedAccounts = new ArrayList<>(); - boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(caller.getType()); + Account.Type callerType = caller.getType(); + boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(callerType); Ternary domainIdRecursiveListProject = new Ternary<>(null, recursive, null); - accountMgr.buildACLSearchParameters(caller, id, null, null, permittedAccounts, domainIdRecursiveListProject, true, false); + + // Allow users to also list metrics of resources owned by projects they belong to (-1L), and admins to list all + // metrics belonging to their domains recursively (null) + Long projectId = callerType == Account.Type.NORMAL ? -1L : null; + + accountMgr.buildACLSearchParameters(caller, id, null, projectId, permittedAccounts, domainIdRecursiveListProject, true, false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); @@ -360,9 +366,15 @@ protected Pair, Integer> searchForVolumesInternal(ListVolumesUsag final Long id = cmd.getId(); Account caller = CallContext.current().getCallingAccount(); List permittedAccounts = new ArrayList<>(); - boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(caller.getType()); + Account.Type callerType = caller.getType(); + boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(callerType); Ternary domainIdRecursiveListProject = new Ternary<>(null, recursive, null); - accountMgr.buildACLSearchParameters(caller, id, null, null, permittedAccounts, domainIdRecursiveListProject, true, false); + + // Allow users to also list metrics of resources owned by projects they belong to (-1L), and admins to list all + // metrics belonging to their domains recursively (null) + Long projectId = callerType == Account.Type.NORMAL ? -1L : null; + + accountMgr.buildACLSearchParameters(caller, id, null, projectId, permittedAccounts, domainIdRecursiveListProject, true, false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); From c56594b49c45afdbb6ec6bbc8b29968daab4129c Mon Sep 17 00:00:00 2001 From: Fabricio Duarte Date: Thu, 18 Dec 2025 16:02:17 -0300 Subject: [PATCH 2/4] Extract creation of search parameters & fix project resources being ignored when passing multiple IDs --- .../api/ListVolumesUsageHistoryCmd.java | 2 +- .../metrics/MetricsServiceImpl.java | 55 ++++++++++++------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java index 4e9191a16f8d..212b6d15162d 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java @@ -37,7 +37,7 @@ public class ListVolumesUsageHistoryCmd extends BaseResourceUsageHistoryCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VolumeResponse.class, description = "the ID of the volume.") private Long id; - @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType= SystemVmResponse.class, description="the IDs of the volumes, mutually exclusive with id.") + @Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = VolumeResponse.class, description = "the IDs of the volumes, mutually exclusive with id.") private List ids; @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the volume (a substring match is made against the parameter value returning the data for all matching Volumes).") diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java index 4606b14fd9c3..8ec2cf6fdb96 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java @@ -82,6 +82,7 @@ import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -245,30 +246,48 @@ public ListResponse searchForVolumeMetricsStats(List } /** - * Searches VMs based on {@code ListVMsUsageHistoryCmd} parameters. - * - * @param cmd the {@link ListVMsUsageHistoryCmd} specifying the parameters. - * @return the list of VMs. + * Outputs the parameters that should be used for access control in the query of a resource to + * {@code permittedAccounts} and {@code domainIdRecursiveListProject}. + * @param isIdProvided indicates whether any ID was provided to the command */ - protected Pair, Integer> searchForUserVmsInternal(ListVMsUsageHistoryCmd cmd) { - final Long id = cmd.getId(); + private void buildBaseACLSearchParametersForMetrics(boolean isIdProvided, List permittedAccounts, Ternary domainIdRecursiveListProject) { Account caller = CallContext.current().getCallingAccount(); - List permittedAccounts = new ArrayList<>(); Account.Type callerType = caller.getType(); + boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(callerType); - Ternary domainIdRecursiveListProject = new Ternary<>(null, recursive, null); + domainIdRecursiveListProject.second(recursive); + + // If no ID was provided, then the listing will skip project resources (null); otherwise, project resources should + // be listed as well (any long allows this) + Long id = isIdProvided ? 1L : null; // Allow users to also list metrics of resources owned by projects they belong to (-1L), and admins to list all // metrics belonging to their domains recursively (null) - Long projectId = callerType == Account.Type.NORMAL ? -1L : null; + Long projectId = isIdProvided && callerType == Account.Type.NORMAL ? -1L : null; accountMgr.buildACLSearchParameters(caller, id, null, projectId, permittedAccounts, domainIdRecursiveListProject, true, false); + } + + /** + * Searches VMs based on {@code ListVMsUsageHistoryCmd} parameters. + * + * @param cmd the {@link ListVMsUsageHistoryCmd} specifying the parameters. + * @return the list of VMs. + */ + protected Pair, Integer> searchForUserVmsInternal(ListVMsUsageHistoryCmd cmd) { + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + + boolean isIdProvided = CollectionUtils.isNotEmpty(ids); + List permittedAccounts = new ArrayList<>(); + Ternary domainIdRecursiveListProject = new Ternary<>(null, null, null); + buildBaseACLSearchParametersForMetrics(isIdProvided, permittedAccounts, domainIdRecursiveListProject); + Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); - List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); String name = cmd.getName(); String keyword = cmd.getKeyword(); @@ -363,24 +382,18 @@ protected Map> searchForVmMetricsStatsInternal(Date startDa * @return the list of VMs. */ protected Pair, Integer> searchForVolumesInternal(ListVolumesUsageHistoryCmd cmd) { - final Long id = cmd.getId(); - Account caller = CallContext.current().getCallingAccount(); - List permittedAccounts = new ArrayList<>(); - Account.Type callerType = caller.getType(); - boolean recursive = AccountTypesWithRecursiveUsageAccess.contains(callerType); - Ternary domainIdRecursiveListProject = new Ternary<>(null, recursive, null); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); - // Allow users to also list metrics of resources owned by projects they belong to (-1L), and admins to list all - // metrics belonging to their domains recursively (null) - Long projectId = callerType == Account.Type.NORMAL ? -1L : null; + boolean isIdProvided = CollectionUtils.isNotEmpty(ids); + List permittedAccounts = new ArrayList<>(); + Ternary domainIdRecursiveListProject = new Ternary<>(null, null, null); + buildBaseACLSearchParametersForMetrics(isIdProvided, permittedAccounts, domainIdRecursiveListProject); - accountMgr.buildACLSearchParameters(caller, id, null, projectId, permittedAccounts, domainIdRecursiveListProject, true, false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); Filter searchFilter = new Filter(VolumeVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); - List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); String name = cmd.getName(); String keyword = cmd.getKeyword(); From fbf755116632141ae12c755be61638980a6dca2a Mon Sep 17 00:00:00 2001 From: Fabricio Duarte Date: Thu, 18 Dec 2025 17:09:58 -0300 Subject: [PATCH 3/4] Remove unused import --- .../org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java index 212b6d15162d..e5d6a2429d26 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/api/ListVolumesUsageHistoryCmd.java @@ -21,7 +21,6 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.SystemVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.response.VolumeMetricsStatsResponse; From 67c524175e36e7ede9ce6e6c11c5d8d3aff6a8f4 Mon Sep 17 00:00:00 2001 From: Fabricio Duarte Date: Thu, 18 Dec 2025 17:45:27 -0300 Subject: [PATCH 4/4] Remove another unused import --- .../java/org/apache/cloudstack/metrics/MetricsServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java index 8ec2cf6fdb96..77785133428e 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java @@ -82,7 +82,6 @@ import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle;