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: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]