Merge branch '4.9' into 4.10

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
diff --git a/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java
index ec3df0e..46be654 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 @@
 
     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 f6494b3..34376c7 100644
--- a/engine/schema/src/com/cloud/domain/DomainVO.java
+++ b/engine/schema/src/com/cloud/domain/DomainVO.java
@@ -103,6 +103,10 @@
         return id;
     }
 
+    public void setId(long id) {
+        this.id = id;
+    }
+
     @Override
     public Long getParent() {
         return parent;
@@ -135,6 +139,10 @@
         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 f6e040f..a936e97 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -34,13 +34,6 @@
 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.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.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.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 {
@@ -5026,6 +5024,32 @@
         return _networkOfferingDao.search(sc, searchFilter);
     }
 
+     @Override
+     @DB
+     public boolean releaseDomainSpecificVirtualRanges(final long domainId) {
+        final List<DomainVlanMapVO> 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 09c4272..60c48fa 100644
--- a/server/src/com/cloud/user/DomainManagerImpl.java
+++ b/server/src/com/cloud/user/DomainManagerImpl.java
@@ -23,9 +23,6 @@
 
 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.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 @@
     private NetworkOrchestrationService _networkMgr;
     @Inject
     private NetworkDomainDao _networkDomainDao;
+    @Inject
+    private ConfigurationManager _configMgr;
 
     @Inject
     MessageBus _messageBus;
@@ -309,6 +311,14 @@
                     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 4c4fccc..03ab340 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.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 @@
     NetworkDomainDao _networkDomainDao;
     @Mock
     MessageBus _messageBus;
+    @Mock
+    ConfigurationManager _configMgr;
 
     @Spy
     @InjectMocks
@@ -178,6 +188,7 @@
 
     @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 @@
         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<AccountVO>());
+        Mockito.when(_networkDomainDao.listNetworkIdsByDomain(Mockito.anyLong())).thenReturn(new ArrayList<Long>());
+        Mockito.when(_accountDao.findCleanupsForRemovedAccounts(Mockito.anyLong())).thenReturn(new ArrayList<AccountVO>());
+        Mockito.when(_dedicatedDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList<DedicatedResourceVO>());
+        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<DiskOfferingVO>());
+        Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList<ServiceOfferingVO>());
+
+        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<DomainVO>());
+        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<AccountVO>());
+        Mockito.when(_networkDomainDao.listNetworkIdsByDomain(Mockito.anyLong())).thenReturn(new ArrayList<Long>());
+        Mockito.when(_accountDao.findCleanupsForRemovedAccounts(Mockito.anyLong())).thenReturn(new ArrayList<AccountVO>());
+        Mockito.when(_dedicatedDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList<DedicatedResourceVO>());
+        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<DiskOfferingVO>());
+        Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList<ServiceOfferingVO>());
+
+        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 28a6d96..bcee896 100644
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -456,7 +456,16 @@
     }
 
     /* (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) {