From e9f59e2fd3ce7a44981971f4771c335f651bf8e1 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Thu, 18 Jun 2020 03:35:36 +0000 Subject: [PATCH] server: Adding showunique parameter to list templates and isos (#4140) Adds a new parameter showunique to listTemplate and listIsos to return only unique templates / isos across all zones Fixes #4041 --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../api/command/user/iso/ListIsosCmd.java | 9 +++- .../user/template/ListTemplatesCmd.java | 9 +++- .../com/cloud/api/query/QueryManagerImpl.java | 54 ++++++++++++------- .../cloud/api/query/dao/TemplateJoinDao.java | 1 + .../api/query/dao/TemplateJoinDaoImpl.java | 17 ++++++ 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index e8595e67745..83ec10a9e2d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -300,6 +300,7 @@ public class ApiConstants { public static final String SESSIONKEY = "sessionkey"; public static final String SHOW_CAPACITIES = "showcapacities"; public static final String SHOW_REMOVED = "showremoved"; + public static final String SHOW_UNIQUE = "showunique"; public static final String SIGNATURE = "signature"; public static final String SIGNATURE_VERSION = "signatureversion"; public static final String SIZE = "size"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java index dee60f4f8d5..d45c8cd37e9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java @@ -78,6 +78,9 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.SHOW_REMOVED, type=CommandType.BOOLEAN, description="show removed ISOs as well") private Boolean showRemoved; + @Parameter(name = ApiConstants.SHOW_UNIQUE, type = CommandType.BOOLEAN, description = "If set to true, list only unique isos across zones", since = "4.13.2") + private Boolean showUnique; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -115,7 +118,11 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd { } public Boolean getShowRemoved() { - return (showRemoved != null ? showRemoved : false); + return showRemoved != null && showRemoved; + } + + public Boolean getShowUnique() { + return showUnique != null && showUnique; } public boolean listInReadyState() { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index e7d328495ed..481cfd13406 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -75,6 +75,9 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.SHOW_REMOVED, type = CommandType.BOOLEAN, description = "show removed templates as well") private Boolean showRemoved; + @Parameter(name = ApiConstants.SHOW_UNIQUE, type = CommandType.BOOLEAN, description = "If set to true, list only unique templates across zones", since = "4.13.2") + private Boolean showUnique; + @Parameter(name = ApiConstants.PARENT_TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "list datadisk templates by parent template id", since = "4.4") private Long parentTemplateId; @@ -103,7 +106,11 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { } public Boolean getShowRemoved() { - return (showRemoved != null ? showRemoved : false); + return showRemoved != null && showRemoved; + } + + public Boolean getShowUnique() { + return showUnique != null && showUnique; } public Long getParentTemplateId() { 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 fae76122f07..127ac9037a1 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -3154,12 +3154,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor()); return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, - showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId); + showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique()); } private Pair, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags, boolean showRemovedTmpl, List ids, Long parentTemplateId) { + ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags, boolean showRemovedTmpl, List ids, Long parentTemplateId, Boolean showUnique) { // check if zone is configured, if not, just return empty list List hypers = null; @@ -3176,7 +3176,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q searchFilter.addOrderBy(TemplateJoinVO.class, "tempZonePair", SortKeyAscending.value()); SearchBuilder sb = _templateJoinDao.createSearchBuilder(); - sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair + if (showUnique) { + sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct templateId + } else { + sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair + } if (ids != null && !ids.isEmpty()) { sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); } @@ -3413,23 +3417,16 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter); } else { sc.addAnd("templateState", SearchCriteria.Op.IN, new State[] {State.Active, State.UploadAbandoned, State.UploadError, State.NotUploaded, State.UploadInProgress}); - final String[] distinctColumns = {"temp_zone_pair"}; - uniqueTmplPair = _templateJoinDao.searchAndDistinctCount(sc, searchFilter, distinctColumns); + if (showUnique) { + final String[] distinctColumns = {"id"}; + uniqueTmplPair = _templateJoinDao.searchAndDistinctCount(sc, searchFilter, distinctColumns); + } else { + final String[] distinctColumns = {"temp_zone_pair"}; + uniqueTmplPair = _templateJoinDao.searchAndDistinctCount(sc, searchFilter, distinctColumns); + } } - Integer count = uniqueTmplPair.second(); - if (count.intValue() == 0) { - // empty result - return uniqueTmplPair; - } - List uniqueTmpls = uniqueTmplPair.first(); - String[] tzIds = new String[uniqueTmpls.size()]; - int i = 0; - for (TemplateJoinVO v : uniqueTmpls) { - tzIds[i++] = v.getTempZonePair(); - } - List vrs = _templateJoinDao.searchByTemplateZonePair(showRemovedTmpl, tzIds); - return new Pair, Integer>(vrs, count); + return findTemplatesByIdOrTempZonePair(uniqueTmplPair, showRemovedTmpl, showUnique); // TODO: revisit the special logic for iso search in // VMTemplateDaoImpl.searchForTemplates and understand why we need to @@ -3438,6 +3435,25 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q } + // findTemplatesByIdOrTempZonePair returns the templates with the given ids if showUnique is true, or else by the TempZonePair + private Pair, Integer> findTemplatesByIdOrTempZonePair(Pair, Integer> templateDataPair, boolean showRemoved, boolean showUnique) { + Integer count = templateDataPair.second(); + if (count.intValue() == 0) { + // empty result + return templateDataPair; + } + List templateData = templateDataPair.first(); + List templates = null; + if (showUnique) { + Long[] templateIds = templateData.stream().map(template -> template.getId()).toArray(Long[]::new); + templates = _templateJoinDao.findByDistinctIds(templateIds); + } else { + String[] templateZonePairs = templateData.stream().map(template -> template.getTempZonePair()).toArray(String[]::new); + templates = _templateJoinDao.searchByTemplateZonePair(showRemoved, templateZonePairs); + } + return new Pair, Integer>(templates, count); + } + @Override public ListResponse listIsos(ListIsosCmd cmd) { Pair, Integer> result = searchForIsosInternal(cmd); @@ -3480,7 +3496,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor()); return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), - hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, null, null); + hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, null, null, cmd.getShowUnique()); } @Override diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDao.java index 298be4d6f01..c9d7eba48b2 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDao.java @@ -48,4 +48,5 @@ public interface TemplateJoinDao extends GenericDao { Pair, Integer> searchIncludingRemovedAndCount(final SearchCriteria sc, final Filter filter); + List findByDistinctIds(Long... ids); } diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 54686f73df2..27380ffaa93 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -73,6 +73,8 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation tmpltIdSearch; + private final SearchBuilder tmpltIdsSearch; + private final SearchBuilder tmpltZoneSearch; private final SearchBuilder activeTmpltSearch; @@ -88,6 +90,11 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation, Integer>(objects, count); } + @Override + public List findByDistinctIds(Long... ids) { + if (ids == null || ids.length == 0) { + return new ArrayList(); + } + SearchCriteria sc = tmpltIdsSearch.create(); + sc.setParameters("idsIN", ids); + return searchIncludingRemoved(sc, null, null, false); + } + }