From 100a5c5cdabbecc8f014940c537c4652808171a5 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 5 May 2026 14:22:11 +0530 Subject: [PATCH] filter storagedomains for hypervisor Signed-off-by: Abhishek Kumar --- .../veeam/adapter/ServerAdapter.java | 4 +- .../veeam/adapter/ServerAdapterTest.java | 3 +- .../api/query/dao/StoragePoolJoinDao.java | 3 +- .../api/query/dao/StoragePoolJoinDaoImpl.java | 9 +- .../query/dao/StoragePoolJoinDaoImplTest.java | 121 ++++++++++++++++++ 5 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 server/src/test/java/com/cloud/api/query/dao/StoragePoolJoinDaoImplTest.java 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 7c5a25daea0..4387bdd6e05 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 @@ -791,8 +791,8 @@ public class ServerAdapter extends ManagerBase { throw new InvalidParameterValueException("DataCenter with ID " + uuid + " not found"); } Filter filter = new Filter(StoragePoolJoinVO.class, "id", true, offset, limit); - List storagePoolVOS = storagePoolJoinDao.listByZoneAndType(dataCenterVO.getId(), - SUPPORTED_STORAGE_TYPES, filter); + List storagePoolVOS = storagePoolJoinDao.listByZoneHypervisorAndType(dataCenterVO.getId(), + Hypervisor.HypervisorType.KVM, SUPPORTED_STORAGE_TYPES, filter); return StoreVOToStorageDomainConverter.toStorageDomainListFromPools(storagePoolVOS); } diff --git a/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/adapter/ServerAdapterTest.java b/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/adapter/ServerAdapterTest.java index bfa407ba49f..0faf1bfebd2 100644 --- a/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/adapter/ServerAdapterTest.java +++ b/plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/adapter/ServerAdapterTest.java @@ -76,6 +76,7 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; +import com.cloud.hypervisor.Hypervisor; import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.dao.NetworkDao; @@ -676,7 +677,7 @@ public class ServerAdapterTest { when(dcVO.getId()).thenReturn(1L); when(dataCenterDao.findByUuid("dc-uuid")).thenReturn(dcVO); StoragePoolJoinVO poolVO = mock(StoragePoolJoinVO.class); - when(storagePoolJoinDao.listByZoneAndType(eq(1L), any(), any())).thenReturn(List.of(poolVO)); + when(storagePoolJoinDao.listByZoneHypervisorAndType(eq(1L), eq(Hypervisor.HypervisorType.KVM), any(), any())).thenReturn(List.of(poolVO)); assertNotNull(serverAdapter.listStorageDomainsByDcId("dc-uuid", 0L, 10L)); } diff --git a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDao.java index 54a98a225bc..7bd4105113d 100644 --- a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDao.java @@ -18,6 +18,7 @@ package com.cloud.api.query.dao; import java.util.List; +import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.ScopeType; import org.apache.cloudstack.api.response.StoragePoolResponse; @@ -46,6 +47,6 @@ public interface StoragePoolJoinDao extends GenericDao List findStoragePoolByScopeAndRuleTags(Long datacenterId, Long podId, Long clusterId, ScopeType scopeType, List tags); - List listByZoneAndType(long zoneId, List types, Filter filter); + List listByZoneHypervisorAndType(long zoneId, Hypervisor.HypervisorType hypervisorType, List types, Filter filter); } diff --git a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java index fe040f8011e..2a3dc0a349a 100644 --- a/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java @@ -41,6 +41,7 @@ import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.StoragePoolJoinVO; import com.cloud.capacity.CapacityManager; +import com.cloud.hypervisor.Hypervisor; import com.cloud.server.ResourceTag; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; @@ -412,14 +413,18 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase listByZoneAndType(long zoneId, List types, Filter filter) { + public List listByZoneHypervisorAndType(long zoneId, Hypervisor.HypervisorType hypervisorType, List types, Filter filter) { SearchBuilder sb = createSearchBuilder(); sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); + sb.and("hypervisors", sb.entity().getHypervisor(), SearchCriteria.Op.IN); sb.and("types", sb.entity().getPoolType(), SearchCriteria.Op.IN); sb.done(); SearchCriteria sc = sb.create(); sc.setParameters("zoneId", zoneId); + List hypervisors = new ArrayList<>(); + hypervisors.add(Hypervisor.HypervisorType.Any); + hypervisors.add(hypervisorType); + sc.setParameters("hypervisors", hypervisors.toArray()); if (CollectionUtils.isNotEmpty(types)) { sc.setParameters("types", types.toArray()); } diff --git a/server/src/test/java/com/cloud/api/query/dao/StoragePoolJoinDaoImplTest.java b/server/src/test/java/com/cloud/api/query/dao/StoragePoolJoinDaoImplTest.java new file mode 100644 index 00000000000..20c355551a5 --- /dev/null +++ b/server/src/test/java/com/cloud/api/query/dao/StoragePoolJoinDaoImplTest.java @@ -0,0 +1,121 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.query.dao; + +import static org.junit.Assert.assertSame; +import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import com.cloud.api.query.vo.StoragePoolJoinVO; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.storage.Storage; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@RunWith(MockitoJUnitRunner.class) +public class StoragePoolJoinDaoImplTest { + + @Spy + @InjectMocks + private StoragePoolJoinDaoImpl storagePoolJoinDao = new StoragePoolJoinDaoImpl(); + + @Mock + private SearchCriteria searchCriteria; + + @Before + @SuppressWarnings("unchecked") + public void setUp() { + StoragePoolJoinVO storagePoolJoinVO = mock(StoragePoolJoinVO.class); + SearchBuilder searchBuilder = mock(SearchBuilder.class); + when(searchBuilder.entity()).thenReturn(storagePoolJoinVO); + when(searchBuilder.create()).thenReturn(searchCriteria); + doReturn(searchBuilder).when(storagePoolJoinDao).createSearchBuilder(); + } + + @Test + public void listByZoneHypervisorAndTypeReturnsMatchingPoolsWhenTypesAreProvided() { + long zoneId = 42L; + Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM; + List types = Arrays.asList(Storage.StoragePoolType.NetworkFilesystem, Storage.StoragePoolType.Filesystem); + Filter filter = mock(Filter.class); + List expectedPools = Collections.singletonList(mock(StoragePoolJoinVO.class)); + + doReturn(expectedPools).when(storagePoolJoinDao).listBy(searchCriteria, filter); + + List result = storagePoolJoinDao.listByZoneHypervisorAndType(zoneId, hypervisorType, types, filter); + + assertSame(expectedPools, result); + verify(searchCriteria).setParameters("zoneId", zoneId); + verify(searchCriteria).setParameters(eq("hypervisors"), aryEq(new Object[]{Hypervisor.HypervisorType.Any, hypervisorType})); + verify(searchCriteria).setParameters(eq("types"), aryEq(types.toArray())); + verify(storagePoolJoinDao).listBy(searchCriteria, filter); + } + + @Test + public void listByZoneHypervisorAndTypeSkipsTypeFilterWhenTypesAreNull() { + long zoneId = 7L; + Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.VMware; + Filter filter = mock(Filter.class); + List expectedPools = Collections.emptyList(); + + doReturn(expectedPools).when(storagePoolJoinDao).listBy(searchCriteria, filter); + + List result = storagePoolJoinDao.listByZoneHypervisorAndType(zoneId, hypervisorType, null, filter); + + assertSame(expectedPools, result); + verify(searchCriteria).setParameters("zoneId", zoneId); + verify(searchCriteria).setParameters(eq("hypervisors"), aryEq(new Object[]{Hypervisor.HypervisorType.Any, hypervisorType})); + verify(searchCriteria, never()).setParameters(eq("types"), any(Object[].class)); + verify(storagePoolJoinDao).listBy(searchCriteria, filter); + } + + @Test + public void listByZoneHypervisorAndTypeSkipsTypeFilterForEmptyTypesAndPassesNullFilter() { + long zoneId = 9L; + Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.XenServer; + List expectedPools = Collections.singletonList(mock(StoragePoolJoinVO.class)); + + doReturn(expectedPools).when(storagePoolJoinDao).listBy(searchCriteria, null); + + List result = storagePoolJoinDao.listByZoneHypervisorAndType(zoneId, hypervisorType, Collections.emptyList(), null); + + assertSame(expectedPools, result); + verify(searchCriteria).setParameters("zoneId", zoneId); + verify(searchCriteria).setParameters(eq("hypervisors"), aryEq(new Object[]{Hypervisor.HypervisorType.Any, hypervisorType})); + verify(searchCriteria, never()).setParameters(eq("types"), any(Object[].class)); + verify(storagePoolJoinDao).listBy(searchCriteria, null); + } +}