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());

Reply via email to