diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java index 962bea638d0f..661174d18dd8 100644 --- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.lang3.StringUtils; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -177,7 +178,10 @@ public interface StorageManager extends StorageService { "If set to false, the disk is created with a disk provisioning type supported by the pool. Default value is false, and this is currently supported for VMware only.", true, ConfigKey.Scope.Zone); ConfigKey PreferredStoragePool = new ConfigKey<>(String.class, "preferred.storage.pool", "Advanced", "", - "The UUID of preferred storage pool for allocation.", true, ConfigKey.Scope.Account, null); + "The UUID of preferred storage pool for allocation. It can be set at Account or Cluster level: " + + "the Account value takes precedence over the Cluster value, which takes precedence over the Global value. " + + "The preferred storage pool is only used if it is suitable for the allocation, otherwise it is ignored.", + true, List.of(ConfigKey.Scope.Account, ConfigKey.Scope.Cluster), null); ConfigKey MountDisabledStoragePool = new ConfigKey<>(Boolean.class, "mount.disabled.storage.pool", @@ -447,4 +451,25 @@ void connectHostsToPool(DataStore primaryStore, List hostIds, Scope scope, static ConfigKey getMountDisabledStoragePool() { return MountDisabledStoragePool; } + + /** + * Resolves the preferred storage pool UUID, checking the Account scope first, then the Cluster scope and finally the Global value. + * @return a pair of the scope where the value was found and the storage pool UUID, or null if it is not set at any level + */ + static Pair getPreferredStoragePoolUuid(Long accountId, Long clusterId) { + if (accountId != null) { + String uuid = PreferredStoragePool.valueInScope(ConfigKey.Scope.Account, accountId, true); + if (StringUtils.isNotBlank(uuid)) { + return new Pair<>(ConfigKey.Scope.Account, uuid); + } + } + if (clusterId != null) { + String uuid = PreferredStoragePool.valueInScope(ConfigKey.Scope.Cluster, clusterId, true); + if (StringUtils.isNotBlank(uuid)) { + return new Pair<>(ConfigKey.Scope.Cluster, uuid); + } + } + String uuid = PreferredStoragePool.value(); + return StringUtils.isNotBlank(uuid) ? new Pair<>(ConfigKey.Scope.Global, uuid) : null; + } } diff --git a/engine/components-api/src/test/java/com/cloud/storage/StorageManagerTest.java b/engine/components-api/src/test/java/com/cloud/storage/StorageManagerTest.java new file mode 100644 index 000000000000..c9d585c56159 --- /dev/null +++ b/engine/components-api/src/test/java/com/cloud/storage/StorageManagerTest.java @@ -0,0 +1,117 @@ +// 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.storage; + +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.test.util.ReflectionTestUtils; + +import com.cloud.utils.Pair; + +public class StorageManagerTest { + + private static final long ACCOUNT_ID = 2L; + private static final long CLUSTER_ID = 3L; + private static final String ACCOUNT_POOL_UUID = "account-pool-uuid"; + private static final String CLUSTER_POOL_UUID = "cluster-pool-uuid"; + private static final String GLOBAL_POOL_UUID = "global-pool-uuid"; + + private ConfigDepotImpl configDepot; + private Object previousDepot; + + @Before + public void setUp() { + previousDepot = ReflectionTestUtils.getField(ConfigKey.class, "s_depot"); + configDepot = Mockito.mock(ConfigDepotImpl.class); + ConfigKey.init(configDepot); + } + + @After + public void tearDown() { + ConfigKey.init((ConfigDepotImpl) previousDepot); + } + + private void mockPreferredStoragePool(ConfigKey.Scope scope, Long id, String uuid) { + Mockito.when(configDepot.getConfigStringValue(StorageManager.PreferredStoragePool.key(), scope, id)).thenReturn(uuid); + } + + @Test + public void testGetPreferredStoragePoolUuidNotSetAtAnyLevel() { + Assert.assertNull(StorageManager.getPreferredStoragePoolUuid(ACCOUNT_ID, CLUSTER_ID)); + } + + @Test + public void testGetPreferredStoragePoolUuidSetAtAccountLevel() { + mockPreferredStoragePool(ConfigKey.Scope.Account, ACCOUNT_ID, ACCOUNT_POOL_UUID); + mockPreferredStoragePool(ConfigKey.Scope.Cluster, CLUSTER_ID, CLUSTER_POOL_UUID); + mockPreferredStoragePool(ConfigKey.Scope.Global, null, GLOBAL_POOL_UUID); + + Pair result = StorageManager.getPreferredStoragePoolUuid(ACCOUNT_ID, CLUSTER_ID); + + Assert.assertEquals(ConfigKey.Scope.Account, result.first()); + Assert.assertEquals(ACCOUNT_POOL_UUID, result.second()); + } + + @Test + public void testGetPreferredStoragePoolUuidSetAtClusterLevel() { + mockPreferredStoragePool(ConfigKey.Scope.Cluster, CLUSTER_ID, CLUSTER_POOL_UUID); + mockPreferredStoragePool(ConfigKey.Scope.Global, null, GLOBAL_POOL_UUID); + + Pair result = StorageManager.getPreferredStoragePoolUuid(ACCOUNT_ID, CLUSTER_ID); + + Assert.assertEquals(ConfigKey.Scope.Cluster, result.first()); + Assert.assertEquals(CLUSTER_POOL_UUID, result.second()); + } + + @Test + public void testGetPreferredStoragePoolUuidEmptyAccountValueFallsBackToCluster() { + mockPreferredStoragePool(ConfigKey.Scope.Account, ACCOUNT_ID, ""); + mockPreferredStoragePool(ConfigKey.Scope.Cluster, CLUSTER_ID, CLUSTER_POOL_UUID); + + Pair result = StorageManager.getPreferredStoragePoolUuid(ACCOUNT_ID, CLUSTER_ID); + + Assert.assertEquals(ConfigKey.Scope.Cluster, result.first()); + Assert.assertEquals(CLUSTER_POOL_UUID, result.second()); + } + + @Test + public void testGetPreferredStoragePoolUuidSetAtGlobalLevel() { + mockPreferredStoragePool(ConfigKey.Scope.Global, null, GLOBAL_POOL_UUID); + + Pair result = StorageManager.getPreferredStoragePoolUuid(ACCOUNT_ID, CLUSTER_ID); + + Assert.assertEquals(ConfigKey.Scope.Global, result.first()); + Assert.assertEquals(GLOBAL_POOL_UUID, result.second()); + } + + @Test + public void testGetPreferredStoragePoolUuidNullIdsUseGlobalLevel() { + mockPreferredStoragePool(ConfigKey.Scope.Global, null, GLOBAL_POOL_UUID); + + Pair result = StorageManager.getPreferredStoragePoolUuid(null, null); + + Assert.assertEquals(ConfigKey.Scope.Global, result.first()); + Assert.assertEquals(GLOBAL_POOL_UUID, result.second()); + Mockito.verify(configDepot, Mockito.never()).getConfigStringValue(Mockito.anyString(), Mockito.eq(ConfigKey.Scope.Account), Mockito.any()); + Mockito.verify(configDepot, Mockito.never()).getConfigStringValue(Mockito.anyString(), Mockito.eq(ConfigKey.Scope.Cluster), Mockito.any()); + } +} diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 2b9b41b6e8ac..9272487d1e9e 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -396,23 +396,15 @@ private Optional getMatchingStoragePool(String preferredPoolId, Lis .findFirst(); } - private Optional getPreferredStoragePool(List poolList, VirtualMachine vm) { - String accountStoragePoolUuid = null; - if (vm != null) { - accountStoragePoolUuid = StorageManager.PreferredStoragePool.valueIn(vm.getAccountId()); - } - Optional storagePool = getMatchingStoragePool(accountStoragePoolUuid, poolList); - - if (storagePool.isPresent()) { - String storagePoolToString = getReflectOnlySelectedFields(storagePool.get()); - logger.debug("The storage pool [{}] was specified for this account [{}] and will be used for allocation.", storagePoolToString, vm.getAccountId()); - - } else { - String globalStoragePoolUuid = StorageManager.PreferredStoragePool.value(); - storagePool = getMatchingStoragePool(globalStoragePoolUuid, poolList); - storagePool.ifPresent(pool -> logger.debug("The storage pool [{}] was specified in the Global Settings and will be used for allocation.", - getReflectOnlySelectedFields(pool))); + protected Optional getPreferredStoragePool(List poolList, VirtualMachine vm, Long clusterId) { + Long accountId = vm != null ? vm.getAccountId() : null; + Pair preferredStoragePool = StorageManager.getPreferredStoragePoolUuid(accountId, clusterId); + if (preferredStoragePool == null) { + return Optional.empty(); } + Optional storagePool = getMatchingStoragePool(preferredStoragePool.second(), poolList); + storagePool.ifPresent(pool -> logger.debug("The storage pool [{}] was specified at the [{}] level (account [{}], cluster [{}]) and will be used for allocation.", + getReflectOnlySelectedFields(pool), preferredStoragePool.first(), accountId, clusterId)); return storagePool; } @@ -433,7 +425,7 @@ public StoragePool findStoragePool(DiskProfile dskCh, DataCenter dc, Pod pod, Lo if (poolList != null && !poolList.isEmpty()) { StorageUtil.traceLogStoragePools(poolList, logger, "pools to choose from: "); // Check if the preferred storage pool can be used. If yes, use it. - Optional storagePool = getPreferredStoragePool(poolList, vm); + Optional storagePool = getPreferredStoragePool(poolList, vm, clusterId); logger.trace("we have a preferred pool: {}", storagePool.isPresent()); StoragePool storage; diff --git a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java index 04e80212e8cc..4f196ae803ab 100644 --- a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java +++ b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestratorTest.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.Set; import java.lang.reflect.Field; @@ -36,6 +37,8 @@ import com.cloud.storage.ScopeType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; @@ -62,6 +65,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl; import org.apache.cloudstack.secret.PassphraseVO; import org.apache.cloudstack.secret.dao.PassphraseDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -79,6 +83,7 @@ import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; +import org.springframework.test.util.ReflectionTestUtils; import static org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService.VolumeAllocationAlgorithm; import static org.junit.Assert.assertNotNull; @@ -970,4 +975,94 @@ private Field findField(Class clazz, String fieldName) { return null; } + private Optional runGetPreferredStoragePoolTest(String accountPoolUuid, String clusterPoolUuid, String globalPoolUuid, + List poolList, VirtualMachine vm, Long clusterId) { + Object previousDepot = ReflectionTestUtils.getField(ConfigKey.class, "s_depot"); + ConfigDepotImpl configDepotImpl = Mockito.mock(ConfigDepotImpl.class); + String key = StorageManager.PreferredStoragePool.key(); + Mockito.lenient().when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Account, 2L)).thenReturn(accountPoolUuid); + Mockito.lenient().when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Cluster, 3L)).thenReturn(clusterPoolUuid); + Mockito.lenient().when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Global, null)).thenReturn(globalPoolUuid); + ConfigKey.init(configDepotImpl); + try { + return volumeOrchestrator.getPreferredStoragePool(poolList, vm, clusterId); + } finally { + ConfigKey.init((ConfigDepotImpl) previousDepot); + } + } + + private StoragePool mockStoragePoolWithUuid(String uuid) { + StoragePool pool = Mockito.mock(StoragePool.class); + Mockito.lenient().when(pool.getUuid()).thenReturn(uuid); + return pool; + } + + private VirtualMachine mockVmWithAccount() { + VirtualMachine vm = Mockito.mock(VirtualMachine.class); + Mockito.when(vm.getAccountId()).thenReturn(2L); + return vm; + } + + @Test + public void getPreferredStoragePoolAccountTakesPrecedenceOverCluster() { + StoragePool accountPool = mockStoragePoolWithUuid("account-pool"); + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + + Optional result = runGetPreferredStoragePoolTest("account-pool", "cluster-pool", null, + List.of(clusterPool, accountPool), mockVmWithAccount(), 3L); + + Assert.assertEquals(Optional.of(accountPool), result); + } + + @Test + public void getPreferredStoragePoolUsesClusterValueWhenAccountNotSet() { + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + StoragePool globalPool = mockStoragePoolWithUuid("global-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, "cluster-pool", "global-pool", + List.of(globalPool, clusterPool), mockVmWithAccount(), 3L); + + Assert.assertEquals(Optional.of(clusterPool), result); + } + + @Test + public void getPreferredStoragePoolIgnoresClusterValueWhenNoClusterGiven() { + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + StoragePool globalPool = mockStoragePoolWithUuid("global-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, "cluster-pool", "global-pool", + List.of(clusterPool, globalPool), mockVmWithAccount(), null); + + Assert.assertEquals(Optional.of(globalPool), result); + } + + @Test + public void getPreferredStoragePoolWithoutVmUsesClusterValue() { + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + + Optional result = runGetPreferredStoragePoolTest("account-pool", "cluster-pool", null, + List.of(clusterPool), null, 3L); + + Assert.assertEquals(Optional.of(clusterPool), result); + } + + @Test + public void getPreferredStoragePoolNotInSuitablePools() { + StoragePool otherPool = mockStoragePoolWithUuid("other-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, "cluster-pool", null, + List.of(otherPool), mockVmWithAccount(), 3L); + + Assert.assertTrue(result.isEmpty()); + } + + @Test + public void getPreferredStoragePoolNotSet() { + StoragePool otherPool = mockStoragePoolWithUuid("other-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, null, null, + List.of(otherPool), mockVmWithAccount(), 3L); + + Assert.assertTrue(result.isEmpty()); + } } diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 4c062b1eaff1..470bd4d4cbb7 100644 --- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -1924,7 +1924,7 @@ private boolean tryToFindPotentialPoolsToAlocateVolume(VirtualMachineProfile vmP if (suitablePools != null && !suitablePools.isEmpty()) { logger.debug("StoragePoolAllocator [{}] found {} suitable pools to allocate volume [{}] necessary to deploy VM [{}].", allocator.getClass().getSimpleName(), suitablePools.size(), toBeCreated, vmProfile); - checkForPreferredStoragePool(suitablePools, vmProfile.getVirtualMachine(), suitableVolumeStoragePools, toBeCreated); + checkForPreferredStoragePool(suitablePools, vmProfile.getVirtualMachine(), plan.getClusterId(), suitableVolumeStoragePools, toBeCreated); return true; } } @@ -1986,10 +1986,11 @@ private boolean canReusePool(VirtualMachineProfile vmProfile, DeploymentPlan pla private void checkForPreferredStoragePool(List suitablePools, VirtualMachine vm, + Long clusterId, Map> suitableVolumeStoragePools, VolumeVO toBeCreated) { List pools = new ArrayList<>(); - Optional storagePool = getPreferredStoragePool(suitablePools, vm); + Optional storagePool = getPreferredStoragePool(suitablePools, vm, clusterId); storagePool.ifPresent(pools::add); pools.addAll(suitablePools); @@ -2005,17 +2006,14 @@ private Optional getMatchingStoragePool(String preferredPoolId, Lis .findFirst(); } - private Optional getPreferredStoragePool(List poolList, VirtualMachine vm) { - String accountStoragePoolUuid = StorageManager.PreferredStoragePool.valueIn(vm.getAccountId()); - Optional storagePool = getMatchingStoragePool(accountStoragePoolUuid, poolList); - - if (storagePool.isPresent()) { - logger.debug("A storage pool is specified for this account, so we will use this storage pool for allocation: {}", storagePool.get()); - } else { - String globalStoragePoolUuid = StorageManager.PreferredStoragePool.value(); - storagePool = getMatchingStoragePool(globalStoragePoolUuid, poolList); - storagePool.ifPresent(pool -> logger.debug("A storage pool is specified in global setting, so we will use this storage pool for allocation: {}", pool)); + protected Optional getPreferredStoragePool(List poolList, VirtualMachine vm, Long clusterId) { + Pair preferredStoragePool = StorageManager.getPreferredStoragePoolUuid(vm.getAccountId(), clusterId); + if (preferredStoragePool == null) { + return Optional.empty(); } + Optional storagePool = getMatchingStoragePool(preferredStoragePool.second(), poolList); + storagePool.ifPresent(pool -> logger.debug("A storage pool is specified at the [{}] level (account [{}], cluster [{}]), so we will use this storage pool for allocation: {}", + preferredStoragePool.first(), vm.getAccountId(), clusterId, pool)); return storagePool; } diff --git a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java index e77fdaee500c..615ed0dbec6a 100644 --- a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java +++ b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java @@ -95,6 +95,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -123,6 +124,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.test.util.ReflectionTestUtils; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -134,6 +136,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import static org.junit.Assert.assertFalse; @@ -236,6 +239,7 @@ public class DeploymentPlanningManagerImplTest { private static final long hostId = 0L; private static final long podId = 2L; private static final long clusterId = 3L; + private static final long accountId = 7L; private static final long ADMIN_ACCOUNT_ROLE_ID = 1L; private AutoCloseable closeable; @@ -1354,4 +1358,70 @@ public void avoidOtherClustersForDeploymentIfMigrationDisabledValid() { Assert.assertEquals(allClusters.size() - 1, avoidedClusters.size()); Assert.assertFalse(avoidedClusters.contains(allClusters.get(0))); } + + private Optional runGetPreferredStoragePoolTest(String accountPoolUuid, String clusterPoolUuid, String globalPoolUuid, + List poolList) { + Object previousDepot = ReflectionTestUtils.getField(ConfigKey.class, "s_depot"); + ConfigDepotImpl configDepotImpl = Mockito.mock(ConfigDepotImpl.class); + String key = StorageManager.PreferredStoragePool.key(); + Mockito.when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Account, accountId)).thenReturn(accountPoolUuid); + Mockito.when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Cluster, clusterId)).thenReturn(clusterPoolUuid); + Mockito.when(configDepotImpl.getConfigStringValue(key, ConfigKey.Scope.Global, null)).thenReturn(globalPoolUuid); + ConfigKey.init(configDepotImpl); + VirtualMachine vm = Mockito.mock(VirtualMachine.class); + Mockito.when(vm.getAccountId()).thenReturn(accountId); + try { + return _dpm.getPreferredStoragePool(poolList, vm, clusterId); + } finally { + ConfigKey.init((ConfigDepotImpl) previousDepot); + } + } + + private StoragePool mockStoragePoolWithUuid(String uuid) { + StoragePool pool = Mockito.mock(StoragePool.class); + Mockito.when(pool.getUuid()).thenReturn(uuid); + return pool; + } + + @Test + public void getPreferredStoragePoolAccountTakesPrecedenceOverCluster() { + StoragePool accountPool = mockStoragePoolWithUuid("account-pool"); + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + + Optional result = runGetPreferredStoragePoolTest("account-pool", "cluster-pool", null, + List.of(clusterPool, accountPool)); + + Assert.assertEquals(Optional.of(accountPool), result); + } + + @Test + public void getPreferredStoragePoolUsesPlanClusterValueWhenAccountNotSet() { + StoragePool clusterPool = mockStoragePoolWithUuid("cluster-pool"); + StoragePool globalPool = mockStoragePoolWithUuid("global-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, "cluster-pool", "global-pool", + List.of(globalPool, clusterPool)); + + Assert.assertEquals(Optional.of(clusterPool), result); + } + + @Test + public void getPreferredStoragePoolFallsBackToGlobalValue() { + StoragePool globalPool = mockStoragePoolWithUuid("global-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, null, "global-pool", + List.of(globalPool)); + + Assert.assertEquals(Optional.of(globalPool), result); + } + + @Test + public void getPreferredStoragePoolNotInSuitablePools() { + StoragePool otherPool = mockStoragePoolWithUuid("other-pool"); + + Optional result = runGetPreferredStoragePoolTest(null, "cluster-pool", null, + List.of(otherPool)); + + Assert.assertTrue(result.isEmpty()); + } }