diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java index 1a5b8cedd9ea..4316a483954d 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java @@ -199,4 +199,6 @@ List searchRemovedByRemoveDate(final Date startDate, final Date en List listDeleteProtectedVmsByDomainIds(Set domainIds); List listIdsByHostIdForVolumeStats(long hostIds); + + List listByIds(List ids); } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java index ae1e838649ba..b69857ce001a 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -1352,4 +1352,17 @@ public List listIdsByHostIdForVolumeStats(long hostId) { sc.setParameters("lastHost", hostId); return customSearch(sc, null); } + + @Override + public List listByIds(List ids) { + if (ids == null || ids.isEmpty()) { + return new ArrayList<>(); + } + SearchBuilder sb = createSearchBuilder(); + sb.and("id", sb.entity().getId(), Op.IN); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("id", ids.toArray()); + return listBy(sc); + } } diff --git a/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java b/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java index 3b533d588d38..5d765267178b 100644 --- a/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java +++ b/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; import java.util.Arrays; +import java.util.List; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; @@ -153,6 +154,7 @@ public void initMocks() throws StorageConflictException { .thenReturn(Arrays.asList(host1, host2)); when(hostDao.findById(anyLong())).thenReturn(mock(HostVO.class)); + when(hostDao.listByIds(List.of(1L, 2L))).thenReturn(List.of(host1, host2)); when(agentMgr.easySend(anyLong(), Mockito.any(ModifyStoragePoolCommand.class))).thenReturn(answer); when(answer.getResult()).thenReturn(true); diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java index 324f3c08cb8f..2e71eb6b161c 100644 --- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java +++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java @@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyMap; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -65,7 +64,6 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; -import com.cloud.storage.DataStoreRole; import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManagerImpl; import com.cloud.storage.StoragePoolAutomation; @@ -129,9 +127,8 @@ public void tearDown() throws Exception { } @Test - public void testAttachZone() throws Exception { + public void testAttachZone() { final DataStore dataStore = mock(DataStore.class); - when(dataStore.getId()).thenReturn(1L); MockedStatic scaleIOGatewayClientConnectionPoolMocked = mockStatic(ScaleIOGatewayClientConnectionPool.class); ScaleIOGatewayClientImpl client = mock(ScaleIOGatewayClientImpl.class); @@ -152,12 +149,6 @@ public void testAttachZone() throws Exception { when(resourceManager.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), Hypervisor.HypervisorType.KVM)) .thenReturn(Arrays.asList(host1, host2)); - when(dataStoreMgr.getDataStore(anyLong(), eq(DataStoreRole.Primary))).thenReturn(store); - when(store.isShared()).thenReturn(true); - when(store.getStorageProviderName()).thenReturn(ScaleIOUtil.PROVIDER_NAME); - - when(dataStoreProviderMgr.getDataStoreProvider(ScaleIOUtil.PROVIDER_NAME)).thenReturn(dataStoreProvider); - when(dataStoreProvider.getName()).thenReturn(ScaleIOUtil.PROVIDER_NAME); storageMgr.registerHostListener(ScaleIOUtil.PROVIDER_NAME, hostListener); when(dataStoreHelper.attachZone(Mockito.any(DataStore.class))).thenReturn(null); diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 7c501c78beeb..5490fa97ebe7 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -1846,6 +1846,10 @@ public void connectHostsToPool(DataStore primaryStore, List hostIds, Scope if (CollectionUtils.isEmpty(hostIds)) { return; } + Map hostMap = new HashMap<>(); + for (HostVO h : _hostDao.listByIds(hostIds)) { + hostMap.put(h.getId(), h); + } CopyOnWriteArrayList poolHostIds = new CopyOnWriteArrayList<>(); ExecutorService executorService = Executors.newFixedThreadPool(Math.max(1, Math.min(hostIds.size(), StoragePoolHostConnectWorkers.value()))); @@ -1856,10 +1860,14 @@ public void connectHostsToPool(DataStore primaryStore, List hostIds, Scope if (exceptionOccurred.get()) { return null; } + HostVO host = hostMap.get(hostId); + if (host == null) { + logger.warn("Host [{}] not found, skipping pool connection for {}", hostId, primaryStore); + return null; + } Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) throws Exception { - HostVO host = _hostDao.findById(hostId); try { connectHostToSharedPool(host, primaryStore.getId()); poolHostIds.add(hostId); @@ -2126,9 +2134,18 @@ public void cleanupStorage(boolean recurring) { cleanupSecondaryStorage(recurring); List vols = volumeDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long)StorageCleanupDelay.value() << 10))); + List rootVolumeVmIds = vols.stream() + .filter(v -> Type.ROOT.equals(v.getVolumeType()) && v.getInstanceId() != null) + .map(VolumeVO::getInstanceId) + .distinct() + .collect(Collectors.toList()); + Map vmMap = new HashMap<>(); + for (VMInstanceVO vm : _vmInstanceDao.listByIds(rootVolumeVmIds)) { + vmMap.put(vm.getId(), vm); + } for (VolumeVO vol : vols) { if (Type.ROOT.equals(vol.getVolumeType())) { - VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vol.getInstanceId()); + VMInstanceVO vmInstanceVO = vol.getInstanceId() != null ? vmMap.get(vol.getInstanceId()) : null; if (vmInstanceVO != null && vmInstanceVO.getState() == State.Destroyed) { logger.debug("ROOT volume [{}] will not be expunged because the VM is [{}], therefore this volume will be expunged with the VM" + " cleanup job.", vol, vmInstanceVO.getState());