diff --git a/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java index ec3df0e7abc..46be654f581 100644 --- a/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java @@ -219,6 +219,20 @@ public interface ConfigurationManager { void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; + /** + * Release dedicated virtual ip ranges of a domain. + * + * @param domainId + * @return success/failure + */ + boolean releaseDomainSpecificVirtualRanges(long domainId); + + /** + * Release dedicated virtual ip ranges of an account. + * + * @param accountId + * @return success/failure + */ boolean releaseAccountSpecificVirtualRanges(long accountId); /** diff --git a/engine/schema/src/com/cloud/domain/DomainVO.java b/engine/schema/src/com/cloud/domain/DomainVO.java index f6494b3a230..34376c7d019 100644 --- a/engine/schema/src/com/cloud/domain/DomainVO.java +++ b/engine/schema/src/com/cloud/domain/DomainVO.java @@ -103,6 +103,10 @@ public class DomainVO implements Domain { return id; } + public void setId(long id) { + this.id = id; + } + @Override public Long getParent() { return parent; @@ -135,6 +139,10 @@ public class DomainVO implements Domain { return accountId; } + public void setAccountId(long accountId) { + this.accountId = accountId; + } + @Override public Date getRemoved() { return removed; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 6c66fa39e69..3d2c236c39c 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -34,13 +34,6 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.google.common.base.MoreObjects; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections.MapUtils; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -72,6 +65,7 @@ import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; @@ -86,11 +80,15 @@ import org.apache.cloudstack.region.PortableIpVO; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.region.RegionVO; import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.log4j.Logger; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; @@ -221,7 +219,7 @@ import com.cloud.vm.dao.NicIpAliasDao; import com.cloud.vm.dao.NicIpAliasVO; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.VMInstanceDao; - +import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable { @@ -5063,6 +5061,32 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return _networkOfferingDao.search(sc, searchFilter); } + @Override + @DB + public boolean releaseDomainSpecificVirtualRanges(final long domainId) { + final List maps = _domainVlanMapDao.listDomainVlanMapsByDomain(domainId); + if (CollectionUtils.isNotEmpty(maps)) { + try { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(final TransactionStatus status) { + for (DomainVlanMapVO map : maps) { + if (!releasePublicIpRange(map.getVlanDbId(), _accountMgr.getSystemUser().getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM))) { + throw new CloudRuntimeException("Failed to release domain specific virtual ip ranges for domain id=" + domainId); + } + } + } + }); + } catch (final CloudRuntimeException e) { + s_logger.error(e); + return false; + } + } else { + s_logger.trace("Domain id=" + domainId + " has no domain specific virtual ip ranges, nothing to release"); + } + return true; + } + @Override @DB public boolean releaseAccountSpecificVirtualRanges(final long accountId) { diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index 09c4272a071..60c48fa574e 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -23,9 +23,6 @@ import java.util.UUID; import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; @@ -36,7 +33,10 @@ import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.region.RegionManager; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.BooleanUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; +import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceOwnerType; import com.cloud.configuration.ResourceLimit; import com.cloud.configuration.dao.ResourceCountDao; @@ -108,6 +108,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom private NetworkOrchestrationService _networkMgr; @Inject private NetworkDomainDao _networkDomainDao; + @Inject + private ConfigurationManager _configMgr; @Inject MessageBus _messageBus; @@ -309,6 +311,14 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom removeDomainWithNoAccountsForCleanupNetworksOrDedicatedResources(domain); } + if (!_configMgr.releaseDomainSpecificVirtualRanges(domain.getId())) { + CloudRuntimeException e = new CloudRuntimeException("Can't delete the domain yet because failed to release domain specific virtual ip ranges"); + e.addProxyObject(domain.getUuid(), "domainId"); + throw e; + } else { + s_logger.debug("Domain specific Virtual IP ranges " + " are successfully released as a part of domain id=" + domain.getId() + " cleanup."); + } + cleanupDomainOfferings(domain.getId()); CallContext.current().putContextParameter(Domain.class, domain.getUuid()); return true; diff --git a/server/test/com/cloud/user/DomainManagerImplTest.java b/server/test/com/cloud/user/DomainManagerImplTest.java index 4c4fcccc5bb..03ab340a2dc 100644 --- a/server/test/com/cloud/user/DomainManagerImplTest.java +++ b/server/test/com/cloud/user/DomainManagerImplTest.java @@ -17,27 +17,11 @@ package com.cloud.user; -import com.cloud.configuration.dao.ResourceCountDao; -import com.cloud.configuration.dao.ResourceLimitDao; -import com.cloud.dc.DedicatedResourceVO; -import com.cloud.dc.dao.DedicatedResourceDao; -import com.cloud.domain.Domain; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.network.dao.NetworkDomainDao; -import com.cloud.projects.ProjectManager; -import com.cloud.projects.dao.ProjectDao; -import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.user.dao.AccountDao; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.exception.CloudRuntimeException; - import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; @@ -53,6 +37,30 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.Resource.ResourceOwnerType; +import com.cloud.configuration.dao.ResourceCountDao; +import com.cloud.configuration.dao.ResourceLimitDao; +import com.cloud.dc.DedicatedResourceVO; +import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.dao.NetworkDomainDao; +import com.cloud.projects.ProjectManager; +import com.cloud.projects.dao.ProjectDao; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; + @RunWith(MockitoJUnitRunner.class) public class DomainManagerImplTest { @Mock @@ -83,6 +91,8 @@ public class DomainManagerImplTest { NetworkDomainDao _networkDomainDao; @Mock MessageBus _messageBus; + @Mock + ConfigurationManager _configMgr; @Spy @InjectMocks @@ -178,6 +188,7 @@ public class DomainManagerImplTest { @Test public void testDeleteDomainNoCleanup() { + Mockito.when(_configMgr.releaseDomainSpecificVirtualRanges(Mockito.anyLong())).thenReturn(true); domainManager.deleteDomain(DOMAIN_ID, testDomainCleanup); Mockito.verify(domainManager).deleteDomain(domain, testDomainCleanup); Mockito.verify(domainManager).removeDomainWithNoAccountsForCleanupNetworksOrDedicatedResources(domain); @@ -224,4 +235,64 @@ public class DomainManagerImplTest { domainManager.failRemoveOperation(domain, domainAccountsForCleanup, domainNetworkIds, true); } + @Test + public void deleteDomain() { + DomainVO domain = new DomainVO(); + domain.setId(20l); + domain.setAccountId(30l); + Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); + UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + + Mockito.when(_domainDao.findById(20l)).thenReturn(domain); + Mockito.doNothing().when(_accountMgr).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class)); + Mockito.when(_domainDao.update(Mockito.eq(20l), Mockito.any(DomainVO.class))).thenReturn(true); + Mockito.when(_accountDao.search(Mockito.any(SearchCriteria.class), (Filter)org.mockito.Matchers.isNull())).thenReturn(new ArrayList()); + Mockito.when(_networkDomainDao.listNetworkIdsByDomain(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_accountDao.findCleanupsForRemovedAccounts(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_dedicatedDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_domainDao.remove(Mockito.anyLong())).thenReturn(true); + Mockito.when(_configMgr.releaseDomainSpecificVirtualRanges(Mockito.anyLong())).thenReturn(true); + Mockito.when(_diskOfferingDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + + try { + Assert.assertTrue(domainManager.deleteDomain(20l, false)); + } finally { + CallContext.unregister(); + } + } + + @Test + public void deleteDomainCleanup() { + DomainVO domain = new DomainVO(); + domain.setId(20l); + domain.setAccountId(30l); + Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); + UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + + Mockito.when(_domainDao.findById(20l)).thenReturn(domain); + Mockito.doNothing().when(_accountMgr).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class)); + Mockito.when(_domainDao.update(Mockito.eq(20l), Mockito.any(DomainVO.class))).thenReturn(true); + Mockito.when(_domainDao.createSearchCriteria()).thenReturn(Mockito.mock(SearchCriteria.class)); + Mockito.when(_domainDao.search(Mockito.any(SearchCriteria.class), (Filter)org.mockito.Matchers.isNull())).thenReturn(new ArrayList()); + Mockito.when(_accountDao.createSearchCriteria()).thenReturn(Mockito.mock(SearchCriteria.class)); + Mockito.when(_accountDao.search(Mockito.any(SearchCriteria.class), (Filter)org.mockito.Matchers.isNull())).thenReturn(new ArrayList()); + Mockito.when(_networkDomainDao.listNetworkIdsByDomain(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_accountDao.findCleanupsForRemovedAccounts(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_dedicatedDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_domainDao.remove(Mockito.anyLong())).thenReturn(true); + Mockito.when(_resourceCountDao.removeEntriesByOwner(Mockito.anyLong(), Mockito.eq(ResourceOwnerType.Domain))).thenReturn(1l); + Mockito.when(_resourceLimitDao.removeEntriesByOwner(Mockito.anyLong(), Mockito.eq(ResourceOwnerType.Domain))).thenReturn(1l); + Mockito.when(_configMgr.releaseDomainSpecificVirtualRanges(Mockito.anyLong())).thenReturn(true); + Mockito.when(_diskOfferingDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + + try { + Assert.assertTrue(domainManager.deleteDomain(20l, true)); + } finally { + CallContext.unregister(); + } + } } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 28a6d96f733..bcee896ca30 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -456,7 +456,16 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu } /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationManager#deleteAccountSpecificVirtualRanges(long) + * @see com.cloud.configuration.ConfigurationManager#releaseDomainSpecificVirtualRanges(long) + */ + @Override + public boolean releaseDomainSpecificVirtualRanges(long domainId) { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationManager#releaseAccountSpecificVirtualRanges(long) */ @Override public boolean releaseAccountSpecificVirtualRanges(long accountId) {