sureshanaparti commented on code in PR #10381:
URL: https://github.com/apache/cloudstack/pull/10381#discussion_r2075322057


##########
server/src/main/java/com/cloud/resource/ResourceManagerImpl.java:
##########
@@ -1917,6 +1936,741 @@ private void updateHostGuestOSCategory(Long hostId, 
Long guestOSCategoryId) {
         }
     }
 
+    private void removeStorageAccessGroupsOnPodsInZone(long zoneId, 
List<String> newStoragePoolTags, List<String> tagsToDeleteOnZone) {
+        List<HostPodVO> pods = _podDao.listByDataCenterId(zoneId);
+        for (HostPodVO pod : pods) {
+            removeStorageAccessGroupsOnClustersInPod(pod.getId(), 
newStoragePoolTags, tagsToDeleteOnZone);
+            updateStorageAccessGroupsToBeAddedOnPodInZone(pod.getId(), 
newStoragePoolTags);
+        }
+    }
+
+    private void removeStorageAccessGroupsOnClustersInPod(long podId, 
List<String> newStoragePoolTags, List<String> tagsToDeleteOnPod) {
+        List<ClusterVO> clusters = _clusterDao.listByPodId(podId);
+        for (ClusterVO cluster : clusters) {
+            
updateStorageAccessGroupsToBeDeletedOnHostsInCluster(cluster.getId(), 
tagsToDeleteOnPod);
+            
updateStorageAccessGroupsToBeAddedOnHostsInCluster(cluster.getId(), 
newStoragePoolTags);
+            updateStorageAccessGroupsToBeAddedOnClustersInPod(cluster.getId(), 
newStoragePoolTags);
+        }
+    }
+
+    private void updateStorageAccessGroupsToBeDeletedOnHostsInCluster(long 
clusterId, List<String> storageAccessGroupsToDeleteOnCluster) {
+        if (CollectionUtils.isEmpty(storageAccessGroupsToDeleteOnCluster)) {
+            return;
+        }
+
+        List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+        List<Long> hostIdsUsingStorageAccessGroups = 
listOfHostIdsUsingTheStorageAccessGroups(storageAccessGroupsToDeleteOnCluster, 
clusterId, null, null);
+        for (HostVO host : hosts) {
+            String hostStorageAccessGroups = host.getStorageAccessGroups();
+            if (hostIdsUsingStorageAccessGroups != null && 
hostIdsUsingStorageAccessGroups.contains(host.getId())) {
+                Set<String> mergedSet = hostStorageAccessGroups != null
+                        ? new 
HashSet<>(Arrays.asList(hostStorageAccessGroups.split(",")))
+                        : new HashSet<>();
+                mergedSet.addAll(storageAccessGroupsToDeleteOnCluster);
+                host.setStorageAccessGroups(String.join(",", mergedSet));
+                _hostDao.update(host.getId(), host);
+            } else {
+                if (hostStorageAccessGroups != null) {
+                    List<String> hostTagsList = new 
ArrayList<>(Arrays.asList(hostStorageAccessGroups.split(",")));
+                    
hostTagsList.removeAll(storageAccessGroupsToDeleteOnCluster);
+                    String updatedClusterStoragePoolTags = 
hostTagsList.isEmpty() ? null : String.join(",", hostTagsList);
+                    host.setStorageAccessGroups(updatedClusterStoragePoolTags);
+                    _hostDao.update(host.getId(), host);
+                }
+            }
+        }
+    }
+
+    private void updateStorageAccessGroupsToBeAddedOnHostsInCluster(long 
clusterId, List<String> tagsAddedOnCluster) {
+        if (CollectionUtils.isEmpty(tagsAddedOnCluster)) {
+            return;
+        }
+
+        List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+        for (HostVO host : hosts) {
+            String hostStoragePoolTags = host.getStorageAccessGroups();
+            Set<String> hostStoragePoolTagsSet = hostStoragePoolTags != null
+                    ? new 
HashSet<>(Arrays.asList(hostStoragePoolTags.split(",")))
+                    : new HashSet<>();
+
+            hostStoragePoolTagsSet.removeIf(tagsAddedOnCluster::contains);
+            host.setStorageAccessGroups(hostStoragePoolTagsSet.isEmpty() ? 
null : String.join(",", hostStoragePoolTagsSet));
+            _hostDao.update(host.getId(), host);
+        }
+    }
+
+    private void updateStorageAccessGroupsToBeAddedOnClustersInPod(long 
clusterId, List<String> tagsAddedOnPod) {
+        if (CollectionUtils.isEmpty(tagsAddedOnPod)) {
+            return;
+        }
+
+        ClusterVO cluster = _clusterDao.findById(clusterId);
+        String clusterStoragePoolTags = cluster.getStorageAccessGroups();
+        if (clusterStoragePoolTags != null) {
+            List<String> clusterTagsList = new 
ArrayList<>(Arrays.asList(clusterStoragePoolTags.split(",")));
+            clusterTagsList.removeAll(tagsAddedOnPod);
+            String updatedClusterStoragePoolTags = clusterTagsList.isEmpty() ? 
null : String.join(",", clusterTagsList);
+            cluster.setStorageAccessGroups(updatedClusterStoragePoolTags);
+            _clusterDao.update(cluster.getId(), cluster);
+        }
+    }
+
+    private void updateStorageAccessGroupsToBeAddedOnPodInZone(long podId, 
List<String> tagsAddedOnZone) {
+        if (CollectionUtils.isEmpty(tagsAddedOnZone)) {
+            return;
+        }
+
+        HostPodVO pod = _podDao.findById(podId);
+        String podStoragePoolTags = pod.getStorageAccessGroups();
+        if (podStoragePoolTags != null) {
+            List<String> podTagsList = new 
ArrayList<>(Arrays.asList(podStoragePoolTags.split(",")));
+            podTagsList.removeAll(tagsAddedOnZone);
+            String updatedClusterStoragePoolTags = podTagsList.isEmpty() ? 
null : String.join(",", podTagsList);
+            pod.setStorageAccessGroups(updatedClusterStoragePoolTags);
+            _podDao.update(pod.getId(), pod);
+        }
+    }
+
+    public List<Long> listOfHostIdsUsingTheStorageAccessGroups(List<String> 
storageAccessGroups, Long clusterId, Long podId, Long datacenterId) {
+        GenericSearchBuilder<VMInstanceVO, Long> vmInstanceSearch = 
_vmDao.createSearchBuilder(Long.class);
+        vmInstanceSearch.select(null, Func.DISTINCT, 
vmInstanceSearch.entity().getHostId());
+        vmInstanceSearch.and("hostId", vmInstanceSearch.entity().getHostId(), 
Op.NNULL);
+        vmInstanceSearch.and("removed", 
vmInstanceSearch.entity().getRemoved(), Op.NULL);
+
+        GenericSearchBuilder<VolumeVO, Long> volumeSearch = 
volumeDao.createSearchBuilder(Long.class);
+        volumeSearch.selectFields(volumeSearch.entity().getInstanceId());
+        volumeSearch.and("state", volumeSearch.entity().getState(), Op.NIN);
+
+        GenericSearchBuilder<StoragePoolVO, Long> storagePoolSearch = 
_storagePoolDao.createSearchBuilder(Long.class);
+        storagePoolSearch.and("clusterId", 
storagePoolSearch.entity().getClusterId(), Op.EQ);
+        storagePoolSearch.and("podId", storagePoolSearch.entity().getPodId(), 
Op.EQ);
+        storagePoolSearch.and("datacenterId", 
storagePoolSearch.entity().getDataCenterId(), Op.EQ);
+        storagePoolSearch.selectFields(storagePoolSearch.entity().getId());
+
+        GenericSearchBuilder<StoragePoolAndAccessGroupMapVO, Long> 
storageAccessGroupSearch = 
_storagePoolAccessGroupMapDao.createSearchBuilder(Long.class);
+        storageAccessGroupSearch.and("sag", 
storageAccessGroupSearch.entity().getStorageAccessGroup(), Op.IN);
+
+        storagePoolSearch.join("storageAccessGroupSearch", 
storageAccessGroupSearch, storagePoolSearch.entity().getId(), 
storageAccessGroupSearch.entity().getPoolId(), JoinBuilder.JoinType.INNER);
+        storageAccessGroupSearch.done();
+
+        volumeSearch.join("storagePoolSearch", storagePoolSearch, 
volumeSearch.entity().getPoolId(), storagePoolSearch.entity().getId(), 
JoinBuilder.JoinType.INNER);
+        storagePoolSearch.done();
+
+        vmInstanceSearch.join("volumeSearch", volumeSearch, 
vmInstanceSearch.entity().getId(), volumeSearch.entity().getInstanceId(), 
JoinBuilder.JoinType.INNER);
+        volumeSearch.done();
+
+        vmInstanceSearch.done();
+
+        SearchCriteria<Long> sc = vmInstanceSearch.create();
+        sc.setJoinParameters("storageAccessGroupSearch", "sag", 
storageAccessGroups.toArray());
+        sc.setJoinParameters("volumeSearch", "state", new String[]{"Destroy", 
"Error", "Expunging", "Expunged"});
+        if (clusterId != null) {
+            sc.setParameters("storagePoolSearch", "clusterId", clusterId);
+        }
+        if (podId != null) {
+            sc.setParameters("storagePoolSearch", "podId", podId);
+        }
+        if (datacenterId != null) {
+            sc.setParameters("storagePoolSearch", "datacenterId", 
datacenterId);
+        }
+
+        return _vmDao.customSearch(sc, null);
+    }
+
+    public List<Long> listOfHostIdsUsingTheStoragePool(Long storagePoolId) {
+        GenericSearchBuilder<VMInstanceVO, Long> vmInstanceSearch = 
_vmDao.createSearchBuilder(Long.class);
+        vmInstanceSearch.select(null, Func.DISTINCT, 
vmInstanceSearch.entity().getHostId());
+        vmInstanceSearch.and("hostId", vmInstanceSearch.entity().getHostId(), 
Op.NNULL);
+        vmInstanceSearch.and("removed", 
vmInstanceSearch.entity().getRemoved(), Op.NULL);
+
+        GenericSearchBuilder<VolumeVO, Long> volumeSearch = 
volumeDao.createSearchBuilder(Long.class);
+        volumeSearch.selectFields(volumeSearch.entity().getInstanceId());
+        volumeSearch.and("state", volumeSearch.entity().getState(), Op.NIN);
+
+        GenericSearchBuilder<StoragePoolVO, Long> storagePoolSearch = 
_storagePoolDao.createSearchBuilder(Long.class);
+        storagePoolSearch.selectFields(storagePoolSearch.entity().getId());
+        storagePoolSearch.and("poolId", storagePoolSearch.entity().getId(), 
Op.EQ);
+
+        volumeSearch.join("storagePoolSearch", storagePoolSearch, 
volumeSearch.entity().getPoolId(), storagePoolSearch.entity().getId(), 
JoinBuilder.JoinType.INNER);
+        storagePoolSearch.done();
+
+        vmInstanceSearch.join("volumeSearch", volumeSearch, 
vmInstanceSearch.entity().getId(), volumeSearch.entity().getInstanceId(), 
JoinBuilder.JoinType.INNER);
+        volumeSearch.done();
+
+        vmInstanceSearch.done();
+
+        SearchCriteria<Long> sc = vmInstanceSearch.create();
+        sc.setJoinParameters("storagePoolSearch", "poolId", storagePoolId);
+        sc.setJoinParameters("volumeSearch", "state", new String[]{"Destroy", 
"Error", "Expunging", "Expunged"});
+
+        return _vmDao.customSearch(sc, null);
+    }
+
+    public List<VolumeVO> 
listOfVolumesUsingTheStorageAccessGroups(List<String> storageAccessGroups, Long 
hostId, Long clusterId, Long podId, Long datacenterId) {
+        SearchBuilder<VolumeVO> volumeSearch = volumeDao.createSearchBuilder();
+        volumeSearch.and("state", volumeSearch.entity().getState(), Op.NIN);
+
+        GenericSearchBuilder<VMInstanceVO, Long> vmInstanceSearch = 
_vmDao.createSearchBuilder(Long.class);
+        vmInstanceSearch.selectFields(vmInstanceSearch.entity().getId());
+        vmInstanceSearch.and("hostId", vmInstanceSearch.entity().getHostId(), 
Op.EQ);
+        vmInstanceSearch.and("removed", 
vmInstanceSearch.entity().getRemoved(), Op.NULL);
+
+        GenericSearchBuilder<StoragePoolVO, Long> storagePoolSearch = 
_storagePoolDao.createSearchBuilder(Long.class);
+        storagePoolSearch.and("clusterId", 
storagePoolSearch.entity().getClusterId(), Op.EQ);
+        storagePoolSearch.and("podId", storagePoolSearch.entity().getPodId(), 
Op.EQ);
+        storagePoolSearch.and("datacenterId", 
storagePoolSearch.entity().getDataCenterId(), Op.EQ);
+        storagePoolSearch.selectFields(storagePoolSearch.entity().getId());
+
+        GenericSearchBuilder<StoragePoolAndAccessGroupMapVO, Long> 
storageAccessGroupSearch = 
_storagePoolAccessGroupMapDao.createSearchBuilder(Long.class);
+        storageAccessGroupSearch.and("sag", 
storageAccessGroupSearch.entity().getStorageAccessGroup(), Op.IN);
+
+        storagePoolSearch.join("storageAccessGroupSearch", 
storageAccessGroupSearch, storagePoolSearch.entity().getId(), 
storageAccessGroupSearch.entity().getPoolId(), JoinBuilder.JoinType.INNER);
+
+        volumeSearch.join("storagePoolSearch", storagePoolSearch, 
volumeSearch.entity().getPoolId(), storagePoolSearch.entity().getId(), 
JoinBuilder.JoinType.INNER);
+
+        volumeSearch.join("vmInstanceSearch", vmInstanceSearch, 
volumeSearch.entity().getInstanceId(), vmInstanceSearch.entity().getId(), 
JoinBuilder.JoinType.INNER);
+
+        storageAccessGroupSearch.done();
+        storagePoolSearch.done();
+        vmInstanceSearch.done();
+        volumeSearch.done();
+
+        SearchCriteria<VolumeVO> sc = volumeSearch.create();
+        sc.setParameters( "state", new String[]{"Destroy", "Error", 
"Expunging", "Expunged"});
+        sc.setJoinParameters("storageAccessGroupSearch", "sag", 
storageAccessGroups.toArray());
+        if (hostId != null) {
+            sc.setJoinParameters("vmInstanceSearch", "hostId", hostId);
+        }
+        if (clusterId != null) {
+            sc.setJoinParameters("storagePoolSearch", "clusterId", clusterId);
+        }
+        if (podId != null) {
+            sc.setJoinParameters("storagePoolSearch", "podId", podId);
+        }
+        if (datacenterId != null) {
+            sc.setJoinParameters("storagePoolSearch", "datacenterId", 
datacenterId);
+        }
+
+        return volumeDao.customSearch(sc, null);
+    }
+
+    private List<Long> listOfStoragePoolIDsUsedByHost(long hostId) {
+        GenericSearchBuilder<VMInstanceVO, Long> vmInstanceSearch = 
_vmDao.createSearchBuilder(Long.class);
+        vmInstanceSearch.selectFields(vmInstanceSearch.entity().getId());
+        vmInstanceSearch.and("hostId", vmInstanceSearch.entity().getHostId(), 
Op.EQ);
+
+        GenericSearchBuilder<VolumeVO, Long> volumeSearch = 
volumeDao.createSearchBuilder(Long.class);
+        volumeSearch.selectFields(volumeSearch.entity().getPoolId());
+        volumeSearch.and("state", volumeSearch.entity().getState(), Op.EQ);
+
+        volumeSearch.join("vmInstanceSearch", vmInstanceSearch, 
volumeSearch.entity().getInstanceId(), vmInstanceSearch.entity().getId(), 
JoinBuilder.JoinType.INNER);
+        vmInstanceSearch.done();
+
+        GenericSearchBuilder<StoragePoolVO, Long> storagePoolSearch = 
_storagePoolDao.createSearchBuilder(Long.class);
+        storagePoolSearch.select(null, Func.DISTINCT, 
storagePoolSearch.entity().getId());
+
+        storagePoolSearch.join("volumeSearch", volumeSearch, 
storagePoolSearch.entity().getId(), volumeSearch.entity().getPoolId(), 
JoinBuilder.JoinType.INNER);
+        volumeSearch.done();
+
+        storagePoolSearch.done();
+
+        SearchCriteria<Long> sc = storagePoolSearch.create();
+        sc.setJoinParameters("vmInstanceSearch", "hostId", hostId);
+        sc.setJoinParameters("volumeSearch", "state", "Ready");
+
+        List<Long> storagePoolsInUse = _storagePoolDao.customSearch(sc, null);
+        return storagePoolsInUse;
+    }
+
+    @Override
+    public void updateStoragePoolConnectionsOnHosts(Long poolId, List<String> 
storageAccessGroups) {
+        StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
+        List<HostVO> hosts = new ArrayList<>();
+
+        if (storagePool.getScope().equals(ScopeType.CLUSTER)) {
+            List<HostVO> hostsInCluster = listAllUpHosts(Host.Type.Routing, 
storagePool.getClusterId(), storagePool.getPodId(), 
storagePool.getDataCenterId());
+            hosts.addAll(hostsInCluster);
+        } else if (storagePool.getScope().equals(ScopeType.ZONE)) {
+            List<HostVO> hostsInZone = listAllUpHosts(Host.Type.Routing, null, 
null, storagePool.getDataCenterId());
+            hosts.addAll(hostsInZone);
+        }
+
+        List<HostVO> hostsToConnect = new ArrayList<>();
+        List<HostVO> hostsToDisconnect = new ArrayList<>();
+        boolean storagePoolHasAccessGroups = 
CollectionUtils.isNotEmpty(storageAccessGroups);
+
+        for (HostVO host : hosts) {
+            String[] storageAccessGroupsOnHost = 
_storageMgr.getStorageAccessGroups(null, null, null, host.getId());
+            List<String> listOfStorageAccessGroupsOnHost = 
Arrays.asList(storageAccessGroupsOnHost);
+            StoragePoolHostVO hostPoolRecord = 
_storagePoolHostDao.findByPoolHost(storagePool.getId(), host.getId());
+
+            if (storagePoolHasAccessGroups) {
+                List<String> intersection = new 
ArrayList<>(listOfStorageAccessGroupsOnHost);
+                intersection.retainAll(storageAccessGroups);
+                if (CollectionUtils.isNotEmpty(intersection)) {
+                    if (hostPoolRecord == null) {
+                        hostsToConnect.add(host);
+                    }
+                } else {
+                    hostsToDisconnect.add(host);
+                }
+            } else {
+                if (hostPoolRecord == null) {
+                    hostsToConnect.add(host);
+                }
+            }
+        }
+
+        if (CollectionUtils.isNotEmpty(hostsToDisconnect)) {
+            List<Long> hostIdsUsingTheStoragePool = 
listOfHostIdsUsingTheStoragePool(poolId);
+            List<Long> hostIdsToDisconnect = hostsToDisconnect.stream()
+                    .map(HostVO::getId)
+                    .collect(Collectors.toList());
+            List<Long> conflictingHostIds = new 
ArrayList<>(CollectionUtils.intersection(hostIdsToDisconnect, 
hostIdsUsingTheStoragePool));
+            if (CollectionUtils.isNotEmpty(conflictingHostIds)) {
+                Map<HostVO, List<VolumeVO>> hostVolumeMap = new HashMap<>();
+                List<VolumeVO> volumesInPool = volumeDao.findByPoolId(poolId);
+                Map<Long, VMInstanceVO> vmInstanceCache = new HashMap<>();
+
+                for (Long hostId : conflictingHostIds) {
+                    HostVO host = _hostDao.findById(hostId);
+                    List<VolumeVO> matchingVolumes = volumesInPool.stream()
+                            .filter(volume -> {
+                                Long vmId = volume.getInstanceId();
+                                if (vmId == null) return false;
+
+                                VMInstanceVO vmInstance = 
vmInstanceCache.computeIfAbsent(vmId, _vmDao::findById);
+                                return vmInstance != null && 
hostId.equals(vmInstance.getHostId());
+                            })
+                            .collect(Collectors.toList());
+                    if (!matchingVolumes.isEmpty()) {
+                        hostVolumeMap.put(host, matchingVolumes);
+                    }
+                }
+
+                logger.error(String.format("Conflict detected: Hosts using the 
storage pool that need to be disconnected or " +
+                        "connected to the pool: Host IDs and volumes: %s", 
hostVolumeMap));
+                throw new CloudRuntimeException("Storage access groups cannot 
be updated as they are currently in use by some hosts. Please check the logs.");
+            }
+        }
+
+        if (!hostsToConnect.isEmpty()) {
+            logger.debug(String.format("Hosts to connect to storage pool [%s]: 
%s", storagePool.getUuid(), hostsToConnect));

Review Comment:
   _hostsToConnect_ logged will be huge list if there are more hosts, better 
keep it inside loop (same for  _hostsToDisconnect_)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to