This is an automated email from the ASF dual-hosted git repository.
weizhouapache pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 89b2b030e02 veeam-control-service: fix vm pagination (#13383)
89b2b030e02 is described below
commit 89b2b030e024fb9ebcfe49b6bea900be29fa6fcb
Author: Abhishek Kumar <[email protected]>
AuthorDate: Tue Jul 7 16:38:58 2026 +0530
veeam-control-service: fix vm pagination (#13383)
Only consider page in pagination for search clause
https://ovirt.github.io/ovirt-engine-api-model/4.5/#_pagination
Signed-off-by: Abhishek Kumar <[email protected]>
---
.../cloudstack/veeam/api/request/ListQuery.java | 57 ++++++++++------------
.../veeam/api/request/ListQueryTest.java | 10 ++--
2 files changed, 31 insertions(+), 36 deletions(-)
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 f57edf76e04..1cb560a3d89 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
@@ -22,6 +22,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
@@ -31,6 +33,8 @@ import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
public class ListQuery {
+ private static final Pattern PAGE_CLAUSE_PATTERN =
Pattern.compile("(?i)\\bpage\\s+(\\d+)\\b");
+
boolean allContent;
Long max;
Long page;
@@ -53,6 +57,14 @@ public class ListQuery {
this.max = max;
}
+ public Long getPage() {
+ return page;
+ }
+
+ public void setPage(Long page) {
+ this.page = page;
+ }
+
public void setSearch(Map<String, String> search) {
this.search = search;
}
@@ -108,10 +120,13 @@ public class ListQuery {
query.setFollow(follow);
Map<String, String> searchItems =
getSearchMap(request.getParameter("search"));
if (!searchItems.isEmpty()) {
- try {
- query.setMax(Long.parseLong(searchItems.get("page")));
- } catch (NumberFormatException e) {
- // Ignore invalid page and keep default null value.
+ String pageValue = searchItems.get("page");
+ if (StringUtils.isNotBlank(pageValue)) {
+ try {
+ query.setPage(Long.parseLong(pageValue));
+ } catch (NumberFormatException e) {
+ // Ignore invalid page and keep default null value.
+ }
}
query.setSearch(searchItems);
}
@@ -119,39 +134,19 @@ public class ListQuery {
return query;
}
- // Parse search clause. Only keep items which use simple '=' operator, and
ignore others. For example:
- // name=myvm and status=up --> {name=myvm, status=up}
- // name=myvm and status!=down --> {name=myvm} (ignore status!=down
because it uses '!=' operator)
+ // Parse search clause. For now, only extract the oVirt paging clause.
+ // Examples:
+ // page 3 --> {page=3}
+ // sortby name page 2 --> {page=2}
@NotNull
private static Map<String, String> getSearchMap(String searchClause) {
Map<String, String> searchItems = new LinkedHashMap<>();
if (StringUtils.isBlank(searchClause)) {
return searchItems;
}
- String[] terms = searchClause.trim().split("(?i)\\s+and\\s+");
- for (String term : terms) {
- if (term == null) {
- continue;
- }
- String trimmedTerm = term.trim();
- if (trimmedTerm.isEmpty()) {
- continue;
- }
-
- int eqIdx = trimmedTerm.indexOf('=');
- if (eqIdx <= 0 || eqIdx != trimmedTerm.lastIndexOf('=')) {
- continue;
- }
- char prev = trimmedTerm.charAt(eqIdx - 1);
- if (prev == '!' || prev == '<' || prev == '>') {
- continue;
- }
-
- String key = trimmedTerm.substring(0, eqIdx).trim();
- String value = trimmedTerm.substring(eqIdx + 1).trim();
- if (!key.isEmpty() && !value.isEmpty()) {
- searchItems.put(key, value);
- }
+ Matcher matcher = PAGE_CLAUSE_PATTERN.matcher(searchClause);
+ if (matcher.find()) {
+ searchItems.put("page", matcher.group(1));
}
return searchItems;
}
diff --git
a/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/api/request/ListQueryTest.java
b/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/api/request/ListQueryTest.java
index 16fbd02669c..a6d8bfef1d4 100644
---
a/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/api/request/ListQueryTest.java
+++
b/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/api/request/ListQueryTest.java
@@ -67,18 +67,18 @@ public class ListQueryTest {
}
@Test
- public void
testFromRequest_SearchParserIgnoresNonEqualsAndUsesPageValueAsMaxCurrentBehavior()
{
+ public void testFromRequest_SearchParserExtractsPageOnly() {
final HttpServletRequest request = mock(HttpServletRequest.class);
- when(request.getParameterMap()).thenReturn(Map.of("search", new
String[]{"name=vm and page=3 and status!=down and x>=1"}));
+ when(request.getParameterMap()).thenReturn(Map.of("search", new
String[]{"sortby name page 3"}));
when(request.getParameter("all_content")).thenReturn(null);
when(request.getParameter("max")).thenReturn(null);
when(request.getParameter("follow")).thenReturn(null);
- when(request.getParameter("search")).thenReturn("name=vm and page=3
and status!=down and x>=1");
+ when(request.getParameter("search")).thenReturn("sortby name page 3");
final ListQuery query = ListQuery.fromRequest(request);
- // Document existing behavior: when search contains page=..., max is
set from it.
- org.junit.Assert.assertEquals(Long.valueOf(3L), query.getLimit());
+ // Only page key is extracted from search clause in oVirt format "page
N"
+ org.junit.Assert.assertEquals(Long.valueOf(3L), query.getPage());
}
@Test