This is an automated email from the ASF dual-hosted git repository.
shwstppr pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.20 by this push:
new 57331aca2fc Skip removal of offerings if in use during domain removal
(#11780)
57331aca2fc is described below
commit 57331aca2fc4b0c7051a94a52b18969ac6920fd4
Author: Manoj Kumar <[email protected]>
AuthorDate: Wed Jan 7 09:25:11 2026 +0530
Skip removal of offerings if in use during domain removal (#11780)
This PR fixes #11502
- Prevent service offering update to specific domains if any instance
for the offering are outside of those
- Removal of offerings is skipped if it is in use by any Instance.
---
.../main/java/com/cloud/storage/dao/VolumeDao.java | 2 ++
.../java/com/cloud/storage/dao/VolumeDaoImpl.java | 14 ++++++++
.../main/java/com/cloud/vm/dao/VMInstanceDao.java | 3 ++
.../java/com/cloud/vm/dao/VMInstanceDaoImpl.java | 37 ++++++++++++++++++++++
.../configuration/ConfigurationManagerImpl.java | 8 ++++-
.../java/com/cloud/user/DomainManagerImpl.java | 25 ++++++++++++---
6 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java
b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java
index e6ffca06f9e..4936af3caab 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java
@@ -162,4 +162,6 @@ public interface VolumeDao extends GenericDao<VolumeVO,
Long>, StateDao<Volume.S
List<VolumeVO> searchRemovedByVms(List<Long> vmIds, Long batchSize);
VolumeVO findOneByIScsiName(String iScsiName);
+
+ int getVolumeCountByOfferingId(long diskOfferingId);
}
diff --git
a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
index 750dbf2bee0..5ef64b04664 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
@@ -77,6 +77,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO,
Long> implements Vol
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
private final SearchBuilder<VolumeVO> poolAndPathSearch;
+ final GenericSearchBuilder<VolumeVO, Integer> CountByOfferingId;
@Inject
ReservationDao reservationDao;
@@ -504,6 +505,11 @@ public class VolumeDaoImpl extends
GenericDaoBase<VolumeVO, Long> implements Vol
poolAndPathSearch.and("poolId",
poolAndPathSearch.entity().getPoolId(), Op.EQ);
poolAndPathSearch.and("path", poolAndPathSearch.entity().getPath(),
Op.EQ);
poolAndPathSearch.done();
+
+ CountByOfferingId = createSearchBuilder(Integer.class);
+ CountByOfferingId.select(null, Func.COUNT,
CountByOfferingId.entity().getId());
+ CountByOfferingId.and("diskOfferingId",
CountByOfferingId.entity().getDiskOfferingId(), Op.EQ);
+ CountByOfferingId.done();
}
@Override
@@ -909,4 +915,12 @@ public class VolumeDaoImpl extends
GenericDaoBase<VolumeVO, Long> implements Vol
sc.setParameters("iScsiName", iScsiName);
return findOneIncludingRemovedBy(sc);
}
+
+ @Override
+ public int getVolumeCountByOfferingId(long diskOfferingId) {
+ SearchCriteria<Integer> sc = CountByOfferingId.create();
+ sc.setParameters("diskOfferingId", diskOfferingId);
+ List<Integer> results = customSearch(sc, null);
+ return results.get(0);
+ }
}
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 823642d8c3d..56e16ddd871 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
@@ -187,4 +187,7 @@ public interface VMInstanceDao extends
GenericDao<VMInstanceVO, Long>, StateDao<
Map<String, Long> getNameIdMapForVmIds(Collection<Long> ids);
+ int getVmCountByOfferingId(Long serviceOfferingId);
+
+ int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List<Long>
domainIds);
}
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 29ab74dfbfd..518bc3cf497 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
@@ -104,6 +104,8 @@ public class VMInstanceDaoImpl extends
GenericDaoBase<VMInstanceVO, Long> implem
protected SearchBuilder<VMInstanceVO> LastHostAndStatesSearch;
protected SearchBuilder<VMInstanceVO> VmsNotInClusterUsingPool;
protected SearchBuilder<VMInstanceVO> IdsPowerStateSelectSearch;
+ GenericSearchBuilder<VMInstanceVO, Integer> CountByOfferingId;
+ GenericSearchBuilder<VMInstanceVO, Integer> CountUserVmNotInDomain;
@Inject
ResourceTagDao tagsDao;
@@ -344,6 +346,18 @@ public class VMInstanceDaoImpl extends
GenericDaoBase<VMInstanceVO, Long> implem
IdsPowerStateSelectSearch.entity().getPowerStateUpdateCount(),
IdsPowerStateSelectSearch.entity().getPowerStateUpdateTime());
IdsPowerStateSelectSearch.done();
+
+ CountByOfferingId = createSearchBuilder(Integer.class);
+ CountByOfferingId.select(null, Func.COUNT,
CountByOfferingId.entity().getId());
+ CountByOfferingId.and("serviceOfferingId",
CountByOfferingId.entity().getServiceOfferingId(), Op.EQ);
+ CountByOfferingId.done();
+
+ CountUserVmNotInDomain = createSearchBuilder(Integer.class);
+ CountUserVmNotInDomain.select(null, Func.COUNT,
CountUserVmNotInDomain.entity().getId());
+ CountUserVmNotInDomain.and("serviceOfferingId",
CountUserVmNotInDomain.entity().getServiceOfferingId(), Op.EQ);
+ CountUserVmNotInDomain.and("domainIdsNotIn",
CountUserVmNotInDomain.entity().getDomainId(), Op.NIN);
+ CountUserVmNotInDomain.done();
+
}
@Override
@@ -1224,4 +1238,27 @@ public class VMInstanceDaoImpl extends
GenericDaoBase<VMInstanceVO, Long> implem
return vms.stream()
.collect(Collectors.toMap(VMInstanceVO::getInstanceName,
VMInstanceVO::getId));
}
+
+ @Override
+ public int getVmCountByOfferingId(Long serviceOfferingId) {
+ if (serviceOfferingId == null) {
+ return 0;
+ }
+ SearchCriteria<Integer> sc = CountByOfferingId.create();
+ sc.setParameters("serviceOfferingId", serviceOfferingId);
+ List<Integer> count = customSearch(sc, null);
+ return count.get(0);
+ }
+
+ @Override
+ public int getVmCountByOfferingNotInDomain(Long serviceOfferingId,
List<Long> domainIds) {
+ if (serviceOfferingId == null || CollectionUtils.isEmpty(domainIds)) {
+ return 0;
+ }
+ SearchCriteria<Integer> sc = CountUserVmNotInDomain.create();
+ sc.setParameters("serviceOfferingId", serviceOfferingId);
+ sc.setParameters("domainIdsNotIn", domainIds.toArray());
+ List<Integer> count = customSearch(sc, null);
+ return count.get(0);
+ }
}
diff --git
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 246681f7585..62b3c23d27e 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -50,7 +50,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
-
+import com.cloud.exception.UnsupportedServiceException;
import com.cloud.network.as.AutoScaleManager;
import com.cloud.user.AccountManagerImpl;
import org.apache.cloudstack.acl.RoleType;
@@ -3722,6 +3722,12 @@ public class ConfigurationManagerImpl extends
ManagerBase implements Configurati
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
Collections.sort(filteredDomainIds);
+ // avoid domain update of service offering if any instance is
associated to it
+ int instanceCount =
_vmInstanceDao.getVmCountByOfferingNotInDomain(offeringHandle.getId(),
filteredDomainIds);
+ if (instanceCount > 0) {
+ throw new UnsupportedServiceException("There are Instances
associated to this service offering outside of the specified domains.");
+ }
+
List<Long> filteredZoneIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(zoneIds)) {
filteredZoneIds.addAll(zoneIds);
diff --git a/server/src/main/java/com/cloud/user/DomainManagerImpl.java
b/server/src/main/java/com/cloud/user/DomainManagerImpl.java
index 6fc9c6f5ef5..28f9bd3ab39 100644
--- a/server/src/main/java/com/cloud/user/DomainManagerImpl.java
+++ b/server/src/main/java/com/cloud/user/DomainManagerImpl.java
@@ -34,6 +34,8 @@ import com.cloud.api.query.vo.NetworkOfferingJoinVO;
import com.cloud.api.query.vo.VpcOfferingJoinVO;
import com.cloud.configuration.Resource;
import com.cloud.domain.dao.DomainDetailsDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.network.vpc.dao.VpcOfferingDao;
import com.cloud.network.vpc.dao.VpcOfferingDetailsDao;
import com.cloud.offerings.dao.NetworkOfferingDao;
@@ -85,6 +87,7 @@ import com.cloud.projects.dao.ProjectDao;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
@@ -101,6 +104,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
+import com.cloud.vm.dao.VMInstanceDao;
+
import org.apache.commons.lang3.StringUtils;
@Component
@@ -141,6 +146,14 @@ public class DomainManagerImpl extends ManagerBase
implements DomainManager, Dom
@Inject
private ProjectDao _projectDao;
@Inject
+ private VMInstanceDao vmInstanceDao;
+ @Inject
+ private NetworkDao networkDao;
+ @Inject
+ private VolumeDao volumeDao;
+ @Inject
+ private VpcDao vpcDao;
+ @Inject
private ProjectManager _projectMgr;
@Inject
private RegionManager _regionMgr;
@@ -543,7 +556,8 @@ public class DomainManagerImpl extends ManagerBase
implements DomainManager, Dom
List<Long> vpcOfferingsDetailsToRemove = new ArrayList<>();
List<VpcOfferingJoinVO> vpcOfferingsForThisDomain =
vpcOfferingJoinDao.findByDomainId(domainId);
for (VpcOfferingJoinVO vpcOffering : vpcOfferingsForThisDomain) {
- if (domainIdString.equals(vpcOffering.getDomainId())) {
+ int vpcCount = vpcDao.getVpcCountByOfferingId(vpcOffering.getId());
+ if (vpcCount == 0) {
vpcOfferingDao.remove(vpcOffering.getId());
} else {
vpcOfferingsDetailsToRemove.add(vpcOffering.getId());
@@ -558,7 +572,8 @@ public class DomainManagerImpl extends ManagerBase
implements DomainManager, Dom
List<Long> networkOfferingsDetailsToRemove = new ArrayList<>();
List<NetworkOfferingJoinVO> networkOfferingsForThisDomain =
networkOfferingJoinDao.findByDomainId(domainId, false);
for (NetworkOfferingJoinVO networkOffering :
networkOfferingsForThisDomain) {
- if (domainIdString.equals(networkOffering.getDomainId())) {
+ int networkCount =
networkDao.getNetworkCountByNetworkOffId(networkOffering.getId());
+ if (networkCount == 0) {
networkOfferingDao.remove(networkOffering.getId());
} else {
networkOfferingsDetailsToRemove.add(networkOffering.getId());
@@ -573,7 +588,8 @@ public class DomainManagerImpl extends ManagerBase
implements DomainManager, Dom
List<Long> serviceOfferingsDetailsToRemove = new ArrayList<>();
List<ServiceOfferingJoinVO> serviceOfferingsForThisDomain =
serviceOfferingJoinDao.findByDomainId(domainId);
for (ServiceOfferingJoinVO serviceOffering :
serviceOfferingsForThisDomain) {
- if (domainIdString.equals(serviceOffering.getDomainId())) {
+ int vmCount =
vmInstanceDao.getVmCountByOfferingId(serviceOffering.getId());
+ if (vmCount == 0) {
serviceOfferingDao.remove(serviceOffering.getId());
} else {
serviceOfferingsDetailsToRemove.add(serviceOffering.getId());
@@ -588,7 +604,8 @@ public class DomainManagerImpl extends ManagerBase
implements DomainManager, Dom
List<Long> diskOfferingsDetailsToRemove = new ArrayList<>();
List<DiskOfferingJoinVO> diskOfferingsForThisDomain =
diskOfferingJoinDao.findByDomainId(domainId);
for (DiskOfferingJoinVO diskOffering : diskOfferingsForThisDomain) {
- if (domainIdString.equals(diskOffering.getDomainId())) {
+ int volumeCount =
volumeDao.getVolumeCountByOfferingId(diskOffering.getId());
+ if (volumeCount == 0) {
diskOfferingDao.remove(diskOffering.getId());
} else {
diskOfferingsDetailsToRemove.add(diskOffering.getId());