From 259ba31e90237a701d51c98546b8e99a6111ea6e Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 9 Apr 2026 11:12:17 +0530 Subject: [PATCH] fix vms listing with tags, effectively tagged jobs Signed-off-by: Abhishek Kumar --- .../veeam/adapter/ServerAdapter.java | 14 +++++++-- .../veeam/api/DataCentersRouteHandler.java | 4 +-- .../cloudstack/veeam/api/VmsRouteHandler.java | 30 ++++++++----------- .../converter/UserVmJoinVOToVmConverter.java | 24 +++++++++------ .../veeam/api/request/ListQuery.java | 29 ++++++++++++++---- 5 files changed, 63 insertions(+), 38 deletions(-) diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java index 36252f58383..706752c6281 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java @@ -973,12 +973,19 @@ public class ServerAdapter extends ManagerBase { } @ApiAccess(command = ListVMsCmd.class) - public List listAllInstances(Long offset, Long limit) { + public List listAllInstances(boolean includeTags, boolean includeDisks, boolean includeNics, + boolean allContent, Long offset, Long limit) { Filter filter = new Filter(UserVmJoinVO.class, "id", true, offset, limit); Pair, String> ownerDetails = getResourceOwnerFilters(); List vms = userVmJoinDao.listByHypervisorTypeAndOwners(Hypervisor.HypervisorType.KVM, ownerDetails.first(), ownerDetails.second(), filter); - return UserVmJoinVOToVmConverter.toVmList(vms, this::getHostById, this::getDetailsByInstanceId); + return UserVmJoinVOToVmConverter.toVmList(vms, + this::getHostById, + this::getDetailsByInstanceId, + includeTags ? this::listTagsByInstanceId : null, + includeDisks ? this::listDiskAttachmentsByInstanceId : null, + includeNics ? this::listNicsByInstance : null, + allContent); } @ApiAccess(command = ListVMsCmd.class) @@ -988,7 +995,8 @@ public class ServerAdapter extends ManagerBase { if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); } - return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, + return UserVmJoinVOToVmConverter.toVm(vo, + this::getHostById, this::getDetailsByInstanceId, includeTags ? this::listTagsByInstanceId : null, includeDisks ? this::listDiskAttachmentsByInstanceId : null, diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java index 7e68375fe56..a06af4f2442 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java @@ -122,7 +122,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler throws IOException { try { ListQuery query = ListQuery.fromRequest(req); - List storageDomains = serverAdapter.listStorageDomainsByDcId(id, query.getPage(), + List storageDomains = serverAdapter.listStorageDomainsByDcId(id, query.getOffset(), query.getMax()); NamedList response = NamedList.of("storage_domain", storageDomains); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); @@ -138,7 +138,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler throws IOException { try { ListQuery query = ListQuery.fromRequest(req); - List networks = serverAdapter.listNetworksByDcId(id, query.getPage(), + List networks = serverAdapter.listNetworksByDcId(id, query.getOffset(), query.getMax()); NamedList response = NamedList.of("network", networks); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java index a2d720c4864..92156be5e69 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java @@ -19,7 +19,6 @@ package org.apache.cloudstack.veeam.api; import java.io.IOException; import java.util.List; -import java.util.Set; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; @@ -42,7 +41,6 @@ import org.apache.cloudstack.veeam.api.request.ListQuery; import org.apache.cloudstack.veeam.utils.Negotiation; import org.apache.cloudstack.veeam.utils.PathUtil; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; import com.cloud.exception.InvalidParameterValueException; import com.cloud.utils.component.ManagerBase; @@ -233,7 +231,12 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException { try { ListQuery query = ListQuery.fromRequest(req); - final List result = serverAdapter.listAllInstances(query.getOffset(), query.getLimit()); + final List result = serverAdapter.listAllInstances(query.followContains("tags"), + query.followContains("disk_attachments.disk"), + query.followContains("nics.reporteddevices"), + query.isAllContent(), + query.getOffset(), + query.getLimit()); NamedList response = NamedList.of("vm", result); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (CloudRuntimeException e) { @@ -255,22 +258,13 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { protected void handleGetById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { - String followStr = req.getParameter("follow"); - boolean includeTags = false; - boolean includeDisks = false; - boolean includeNics = false; - if (StringUtils.isNotBlank(followStr)) { - Set followParts = java.util.Arrays.stream(followStr.split(",")) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .collect(java.util.stream.Collectors.toSet()); - includeTags = followParts.contains("tags"); - includeDisks = followParts.contains("disk_attachments.disk"); - includeNics = followParts.contains("nics.reporteddevices"); - } - boolean allContent = Boolean.parseBoolean(req.getParameter("all_content")); try { - Vm response = serverAdapter.getInstance(id, includeTags, includeDisks, includeNics, allContent); + ListQuery query = ListQuery.fromRequest(req); + Vm response = serverAdapter.getInstance(id, + query.followContains("tags"), + query.followContains("disk_attachments.disk"), + query.followContains("nics.reporteddevices"), + query.isAllContent()); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { io.notFound(resp, e.getMessage(), outFormat); diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java index 61269ab0410..dafec627e96 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java @@ -56,12 +56,13 @@ public final class UserVmJoinVOToVmConverter { * * @param src UserVmJoinVO */ - public static Vm toVm(final UserVmJoinVO src, final Function hostResolver, - final Function> detailsResolver, - final Function> tagsResolver, - final Function> disksResolver, - final Function> nicsResolver, - final boolean allContent) { + public static Vm toVm(final UserVmJoinVO src, + final Function hostResolver, + final Function> detailsResolver, + final Function> tagsResolver, + final Function> disksResolver, + final Function> nicsResolver, + final boolean allContent) { if (src == null) { return null; } @@ -190,10 +191,15 @@ public final class UserVmJoinVOToVmConverter { return initialization; } - public static List toVmList(final List srcList, final Function hostResolver, - final Function> detailsResolver) { + public static List toVmList(final List srcList, + final Function hostResolver, + final Function> detailsResolver, + final Function> tagsResolver, + final Function> disksResolver, + final Function> nicsResolver, + final boolean allContent) { return srcList.stream() - .map(v -> toVm(v, hostResolver, detailsResolver, null, null, null, false)) + .map(v -> toVm(v, hostResolver, detailsResolver, tagsResolver, disksResolver, nicsResolver, allContent)) .collect(Collectors.toList()); } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/request/ListQuery.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/request/ListQuery.java index 8a21b595b77..f57edf76e04 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/request/ListQuery.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/request/ListQuery.java @@ -17,11 +17,15 @@ package org.apache.cloudstack.veeam.api.request; +import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -31,6 +35,7 @@ public class ListQuery { Long max; Long page; Map search; + List follow; public boolean isAllContent() { return allContent; @@ -48,16 +53,19 @@ public class ListQuery { this.max = max; } - public Map getSearch() { - return search; - } - public void setSearch(Map search) { this.search = search; } - public Long getPage() { - return page; + public void setFollow(String followStr) { + if (StringUtils.isBlank(followStr)) { + this.follow = null; + return; + } + this.follow = Arrays.stream(followStr.split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); } public Long getOffset() { @@ -71,6 +79,13 @@ public class ListQuery { return max; } + public boolean followContains(String part) { + if (CollectionUtils.isEmpty(follow)) { + return false; + } + return follow.contains(part); + } + public static ListQuery fromRequest(HttpServletRequest request) { ListQuery query = new ListQuery(); if (MapUtils.isEmpty(request.getParameterMap())) { @@ -89,6 +104,8 @@ public class ListQuery { // Ignore invalid max and keep default null value. } } + String follow = request.getParameter("follow"); + query.setFollow(follow); Map searchItems = getSearchMap(request.getParameter("search")); if (!searchItems.isEmpty()) { try {