This is an automated email from the ASF dual-hosted git repository.

gabriel pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 2334145  Support requesting a specific IPv4 address (#2595)
2334145 is described below

commit 2334145602606caa781e04600273a5ed6ce60c8c
Author: Gabriel Beims Bräscher <[email protected]>
AuthorDate: Tue Nov 27 09:39:10 2018 -0200

    Support requesting a specific IPv4 address (#2595)
    
    This commit allows deploying VMs with a specific IPv4 address.
    
    DirectPodBasedNetworkGuru does not support requesting a custom
    IP-Address while creating a new NIC/Instance, throwing the following
    error:
    
        Error 530: Does not support custom ip allocation at this time:
    NicProfile[0-0-null-null-null
        Unknown macro: { "cserrorcode"}
    
    Some use-cases prefer the ability to request the IPv4 address which the
    Instance will get.
    
    This implementation adds unit test cases to cover and it was manually
    tested in Basic Networking. I can perform more tests if requested.
---
 .../engine/orchestration/NetworkOrchestrator.java  | 100 ++++++-
 .../orchestration/NetworkOrchestratorTest.java     | 293 +++++++++++++++++++--
 .../src/main/java/com/cloud/dc/dao/VlanDao.java    |   2 +
 .../main/java/com/cloud/dc/dao/VlanDaoImpl.java    |  19 ++
 .../network/guru/DirectPodBasedNetworkGuru.java    |   9 +-
 .../main/java/com/cloud/utils/net/NetUtils.java    |  16 +-
 6 files changed, 408 insertions(+), 31 deletions(-)

diff --git 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index b451974..c4db7dc 100644
--- 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -231,27 +231,27 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
     @Inject
     EntityManager _entityMgr;
     @Inject
-    DataCenterDao _dcDao = null;
+    DataCenterDao _dcDao;
     @Inject
-    VlanDao _vlanDao = null;
+    VlanDao _vlanDao;
     @Inject
-    IPAddressDao _ipAddressDao = null;
+    IPAddressDao _ipAddressDao;
     @Inject
-    AccountDao _accountDao = null;
+    AccountDao _accountDao;
     @Inject
     ConfigurationDao _configDao;
     @Inject
-    UserVmDao _userVmDao = null;
+    UserVmDao _userVmDao;
     @Inject
     AlertManager _alertMgr;
     @Inject
     ConfigurationManager _configMgr;
     @Inject
-    NetworkOfferingDao _networkOfferingDao = null;
+    NetworkOfferingDao _networkOfferingDao;
     @Inject
-    NetworkDao _networksDao = null;
+    NetworkDao _networksDao;
     @Inject
-    NicDao _nicDao = null;
+    NicDao _nicDao;
     @Inject
     RulesManager _rulesMgr;
     @Inject
@@ -860,6 +860,11 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
 
         NicVO vo = new NicVO(guru.getName(), vm.getId(), network.getId(), 
vm.getType());
 
+        DataCenterVO dcVo = _dcDao.findById(network.getDataCenterId());
+        if (dcVo.getNetworkType() == NetworkType.Basic) {
+            configureNicProfileBasedOnRequestedIp(requested, profile, network);
+        }
+
         deviceId = applyProfileToNic(vo, profile, deviceId);
 
         vo = _nicDao.persist(vo);
@@ -871,6 +876,85 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
         return new Pair<NicProfile, Integer>(vmNic, Integer.valueOf(deviceId));
     }
 
+    /**
+     * If the requested IPv4 address from the NicProfile was configured then 
it configures the IPv4 address, Netmask and Gateway to deploy the VM with the 
requested IP.
+     */
+    protected void configureNicProfileBasedOnRequestedIp(NicProfile 
requestedNicProfile, NicProfile nicProfile, Network network) {
+        if (requestedNicProfile == null) {
+            return;
+        }
+        String requestedIpv4Address = requestedNicProfile.getRequestedIPv4();
+        if (requestedIpv4Address == null) {
+            return;
+        }
+        if (!NetUtils.isValidIp4(requestedIpv4Address)) {
+            throw new InvalidParameterValueException(String.format("The 
requested [IPv4 address='%s'] is not a valid IP address", 
requestedIpv4Address));
+        }
+
+        VlanVO vlanVo = _vlanDao.findByNetworkIdAndIpv4(network.getId(), 
requestedIpv4Address);
+        if (vlanVo == null) {
+            throw new InvalidParameterValueException(String.format("Trying to 
configure a Nic with the requested [IPv4='%s'] but cannot find a Vlan for the 
[network id='%s']",
+                    requestedIpv4Address, network.getId()));
+        }
+
+        String ipv4Gateway = vlanVo.getVlanGateway();
+        String ipv4Netmask = vlanVo.getVlanNetmask();
+
+        if (!NetUtils.isValidIp4(ipv4Gateway)) {
+            throw new InvalidParameterValueException(String.format("The 
[IPv4Gateway='%s'] from [VlanId='%s'] is not valid", ipv4Gateway, 
vlanVo.getId()));
+        }
+        if (!NetUtils.isValidIp4Netmask(ipv4Netmask)) {
+            throw new InvalidParameterValueException(String.format("The 
[IPv4Netmask='%s'] from [VlanId='%s'] is not valid", ipv4Netmask, 
vlanVo.getId()));
+        }
+
+        acquireLockAndCheckIfIpv4IsFree(network, requestedIpv4Address);
+
+        nicProfile.setIPv4Address(requestedIpv4Address);
+        nicProfile.setIPv4Gateway(ipv4Gateway);
+        nicProfile.setIPv4Netmask(ipv4Netmask);
+
+        if (nicProfile.getMacAddress() == null) {
+            try {
+                String macAddress = 
_networkModel.getNextAvailableMacAddressInNetwork(network.getId());
+                nicProfile.setMacAddress(macAddress);
+            } catch (InsufficientAddressCapacityException e) {
+                throw new CloudRuntimeException(String.format("Cannot get next 
available mac address in [network id='%s']", network.getId()), e);
+            }
+        }
+    }
+
+    /**
+     *  Acquires lock in "user_ip_address" and checks if the requested IPv4 
address is Free.
+     */
+    protected void acquireLockAndCheckIfIpv4IsFree(Network network, String 
requestedIpv4Address) {
+        IPAddressVO ipVO = 
_ipAddressDao.findByIpAndSourceNetworkId(network.getId(), requestedIpv4Address);
+        if (ipVO == null) {
+            throw new InvalidParameterValueException(
+                    String.format("Cannot find IPAddressVO for guest [IPv4 
address='%s'] and [network id='%s']", requestedIpv4Address, network.getId()));
+        }
+        try {
+            IPAddressVO lockedIpVO = 
_ipAddressDao.acquireInLockTable(ipVO.getId());
+            validateLockedRequestedIp(ipVO, lockedIpVO);
+            lockedIpVO.setState(IPAddressVO.State.Allocated);
+            _ipAddressDao.update(lockedIpVO.getId(), lockedIpVO);
+        } finally {
+            _ipAddressDao.releaseFromLockTable(ipVO.getId());
+        }
+    }
+
+    /**
+     * Validates the locked IP, throwing an exeption if the locked IP is null 
or the locked IP is not in 'Free' state.
+     */
+    protected void validateLockedRequestedIp(IPAddressVO ipVO, IPAddressVO 
lockedIpVO) {
+        if (lockedIpVO == null) {
+            throw new InvalidParameterValueException(String.format("Cannot 
acquire guest [IPv4 address='%s'] as it was removed while acquiring lock", 
ipVO.getAddress()));
+        }
+        if (lockedIpVO.getState() != IPAddressVO.State.Free) {
+            throw new InvalidParameterValueException(
+                    String.format("Cannot acquire guest [IPv4 address='%s']; 
The Ip address is in [state='%s']", ipVO.getAddress(), 
lockedIpVO.getState().toString()));
+        }
+    }
+
     protected Integer applyProfileToNic(final NicVO vo, final NicProfile 
profile, Integer deviceId) {
         if (profile.getDeviceId() != null) {
             vo.setDeviceId(profile.getDeviceId());
diff --git 
a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
 
b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
index b0283f3..3450c09 100644
--- 
a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
+++ 
b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
@@ -23,31 +23,42 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Arrays;
 
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.offerings.NetworkOfferingVO;
 import org.apache.log4j.Logger;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.mockito.Matchers;
+import org.mockito.Mockito;
 
+import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkModel;
+import com.cloud.network.IpAddress.State;
 import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkServiceMapDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.element.DhcpServiceProvider;
 import com.cloud.network.guru.NetworkGuru;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.utils.net.Ip;
 import com.cloud.vm.Nic;
+import com.cloud.vm.NicProfile;
 import com.cloud.vm.NicVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.Type;
@@ -65,11 +76,11 @@ import junit.framework.TestCase;
 public class NetworkOrchestratorTest extends TestCase {
     static final Logger s_logger = 
Logger.getLogger(NetworkOrchestratorTest.class);
 
-    NetworkOrchestrator testOrchastrator = new NetworkOrchestrator();
+    NetworkOrchestrator testOrchastrator = Mockito.spy(new 
NetworkOrchestrator());
 
-    String guruName = "GuestNetworkGuru";
-    String dhcpProvider = "VirtualRouter";
-    NetworkGuru guru = mock(NetworkGuru.class);
+    private String guruName = "GuestNetworkGuru";
+    private String dhcpProvider = "VirtualRouter";
+    private NetworkGuru guru = mock(NetworkGuru.class);
 
     NetworkOfferingVO networkOffering = mock(NetworkOfferingVO.class);
 
@@ -85,11 +96,13 @@ public class NetworkOrchestratorTest extends TestCase {
         testOrchastrator._nicSecondaryIpDao = mock(NicSecondaryIpDao.class);
         testOrchastrator._ntwkSrvcDao = mock(NetworkServiceMapDao.class);
         testOrchastrator._nicIpAliasDao = mock(NicIpAliasDao.class);
+        testOrchastrator._ipAddressDao = mock(IPAddressDao.class);
+        testOrchastrator._vlanDao = mock(VlanDao.class);
         DhcpServiceProvider provider = mock(DhcpServiceProvider.class);
 
         Map<Network.Capability, String> capabilities = new 
HashMap<Network.Capability, String>();
-        Map<Network.Service,Map<Network.Capability, String>> services = new 
HashMap<Network.Service,Map<Network.Capability, String>>();
-        services.put(Network.Service.Dhcp,capabilities);
+        Map<Network.Service, Map<Network.Capability, String>> services = new 
HashMap<Network.Service, Map<Network.Capability, String>>();
+        services.put(Network.Service.Dhcp, capabilities);
         when(provider.getCapabilities()).thenReturn(services);
         capabilities.put(Network.Capability.DhcpAccrossMultipleSubnets, 
"true");
 
@@ -108,7 +121,7 @@ public class NetworkOrchestratorTest extends TestCase {
     @Test
     public void testRemoveDhcpServiceWithNic() {
         // make local mocks
-        VirtualMachineProfile vm =  mock(VirtualMachineProfile.class);
+        VirtualMachineProfile vm = mock(VirtualMachineProfile.class);
         NicVO nic = mock(NicVO.class);
         NetworkVO network = mock(NetworkVO.class);
 
@@ -117,9 +130,8 @@ public class NetworkOrchestratorTest extends TestCase {
         
when(testOrchastrator._networkModel.areServicesSupportedInNetwork(network.getId(),
 Service.Dhcp)).thenReturn(true);
         when(network.getTrafficType()).thenReturn(TrafficType.Guest);
         when(network.getGuestType()).thenReturn(GuestType.Shared);
-        
when(testOrchastrator._nicDao.listByNetworkIdTypeAndGatewayAndBroadcastUri(nic.getNetworkId(),
 VirtualMachine.Type.User, nic.getIPv4Gateway(), 
nic.getBroadcastUri())).thenReturn(new ArrayList<NicVO>());
-
-
+        
when(testOrchastrator._nicDao.listByNetworkIdTypeAndGatewayAndBroadcastUri(nic.getNetworkId(),
 VirtualMachine.Type.User, nic.getIPv4Gateway(), nic.getBroadcastUri()))
+                .thenReturn(new ArrayList<NicVO>());
 
         when(network.getGuruName()).thenReturn(guruName);
         
when(testOrchastrator._networksDao.findById(nic.getNetworkId())).thenReturn(network);
@@ -134,7 +146,7 @@ public class NetworkOrchestratorTest extends TestCase {
     @Test
     public void testDontRemoveDhcpServiceFromDomainRouter() {
         // make local mocks
-        VirtualMachineProfile vm =  mock(VirtualMachineProfile.class);
+        VirtualMachineProfile vm = mock(VirtualMachineProfile.class);
         NicVO nic = mock(NicVO.class);
         NetworkVO network = mock(NetworkVO.class);
 
@@ -154,7 +166,7 @@ public class NetworkOrchestratorTest extends TestCase {
     @Test
     public void testDontRemoveDhcpServiceWhenNotProvided() {
         // make local mocks
-        VirtualMachineProfile vm =  mock(VirtualMachineProfile.class);
+        VirtualMachineProfile vm = mock(VirtualMachineProfile.class);
         NicVO nic = mock(NicVO.class);
         NetworkVO network = mock(NetworkVO.class);
 
@@ -200,4 +212,255 @@ public class NetworkOrchestratorTest extends TestCase {
         
when(testOrchastrator._networkModel.areServicesSupportedByNetworkOffering(networkOfferingId,
 Service.UserData)).thenReturn(false);
         testOrchastrator.checkL2OfferingServices(networkOffering);
     }
+
+    @Test
+    public void testConfigureNicProfileBasedOnRequestedIpTestMacNull() {
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, "192.168.100.1", "255.255.255.0", 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, null, "192.168.100.150");
+
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+
+        verifyAndAssert("192.168.100.150", "192.168.100.1", "255.255.255.0", 
nicProfile, 1, 1);
+    }
+
+    @Test
+    public void 
testConfigureNicProfileBasedOnRequestedIpTestNicProfileMacNotNull() {
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, "192.168.100.1", "255.255.255.0", 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, "00-88-14-4D-4C-FB", "192.168.100.150");
+
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+
+        verifyAndAssert("192.168.100.150", "192.168.100.1", "255.255.255.0", 
nicProfile, 1, 0);
+    }
+
+    @Test
+    public void testConfigureNicProfileBasedOnRequestedIpTestRequestedIpNull() 
{
+        testConfigureNicProfileBasedOnRequestedIpTestRequestedIp(null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
testConfigureNicProfileBasedOnRequestedIpTestRequestedIpIsBlank() {
+        testConfigureNicProfileBasedOnRequestedIpTestRequestedIp("");
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
testConfigureNicProfileBasedOnRequestedIpTestRequestedIpIsNotValid() {
+        testConfigureNicProfileBasedOnRequestedIpTestRequestedIp("123");
+    }
+
+    private void 
testConfigureNicProfileBasedOnRequestedIpTestRequestedIp(String 
requestedIpv4Address) {
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, "192.168.100.1", "255.255.255.0", 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, null, requestedIpv4Address);
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+
+        verifyAndAssert(null, null, null, nicProfile, 0, 0);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testConfigureNicProfileBasedOnRequestedIpTestGatewayIsBlank() {
+        testConfigureNicProfileBasedOnRequestedIpTestGateway("");
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
testConfigureNicProfileBasedOnRequestedIpTestGatewayIsNotValid() {
+        testConfigureNicProfileBasedOnRequestedIpTestGateway("123");
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testConfigureNicProfileBasedOnRequestedIpTestGatewayIsNull() {
+        testConfigureNicProfileBasedOnRequestedIpTestGateway(null);
+    }
+
+    private void testConfigureNicProfileBasedOnRequestedIpTestGateway(String 
ipv4Gateway) {
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, ipv4Gateway, "255.255.255.0", 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, "00-88-14-4D-4C-FB", "192.168.100.150");
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+        verifyAndAssert(null, null, null, nicProfile, 1, 0);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testConfigureNicProfileBasedOnRequestedIpTestNetmaskIsNull() {
+        testConfigureNicProfileBasedOnRequestedIpTestNetmask(null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testConfigureNicProfileBasedOnRequestedIpTestNetmaskIsBlank() {
+        testConfigureNicProfileBasedOnRequestedIpTestNetmask("");
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
testConfigureNicProfileBasedOnRequestedIpTestNetmaskIsNotValid() {
+        testConfigureNicProfileBasedOnRequestedIpTestNetmask("123");
+    }
+
+    private void testConfigureNicProfileBasedOnRequestedIpTestNetmask(String 
ipv4Netmask) {
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, "192.168.100.1", ipv4Netmask, 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, "00-88-14-4D-4C-FB", "192.168.100.150");
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+        verifyAndAssert(null, null, null, nicProfile, 1, 0);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testConfigureNicProfileBasedOnRequestedIpTestIPAddressVONull() 
{
+        Network network = mock(Network.class);
+        NicProfile requestedNicProfile = new NicProfile();
+        NicProfile nicProfile = Mockito.spy(new NicProfile());
+
+        configureTestConfigureNicProfileBasedOnRequestedIpTests(nicProfile, 
0l, false, IPAddressVO.State.Free, "192.168.100.1", "255.255.255.0", 
"00-88-14-4D-4C-FB",
+                requestedNicProfile, "00-88-14-4D-4C-FB", "192.168.100.150");
+        
when(testOrchastrator._vlanDao.findByNetworkIdAndIpv4(Mockito.anyLong(), 
Mockito.anyString())).thenReturn(null);
+
+        
testOrchastrator.configureNicProfileBasedOnRequestedIp(requestedNicProfile, 
nicProfile, network);
+        verifyAndAssert(null, null, null, nicProfile, 0, 0);
+    }
+
+    private void 
configureTestConfigureNicProfileBasedOnRequestedIpTests(NicProfile nicProfile, 
long ipvoId, boolean ipVoIsNull, IPAddressVO.State state, String vlanGateway,
+            String vlanNetmask, String macAddress, NicProfile 
requestedNicProfile, String nicProfileMacAddress, String requestedIpv4Address) {
+        IPAddressVO ipVoSpy = Mockito.spy(new IPAddressVO(new 
Ip("192.168.100.100"), 0l, 0l, 0l, true));
+        ipVoSpy.setState(state);
+
+        requestedNicProfile.setRequestedIPv4(requestedIpv4Address);
+        nicProfile.setMacAddress(nicProfileMacAddress);
+
+        when(ipVoSpy.getId()).thenReturn(ipvoId);
+        when(ipVoSpy.getState()).thenReturn(state);
+
+        if (ipVoIsNull) {
+            
when(testOrchastrator._ipAddressDao.findByIpAndSourceNetworkId(Mockito.anyLong(),
 Mockito.anyString())).thenReturn(ipVoSpy);
+        } else {
+            
when(testOrchastrator._ipAddressDao.findByIpAndSourceNetworkId(Mockito.anyLong(),
 Mockito.anyString())).thenReturn(ipVoSpy);
+        }
+
+        VlanVO vlanSpy = Mockito.spy(new VlanVO(Vlan.VlanType.DirectAttached, 
"vlanTag", vlanGateway, vlanNetmask, 0l, "192.168.100.100 - 192.168.100.200", 
0l, new Long(0l),
+                "ip6Gateway", "ip6Cidr", "ip6Range"));
+
+        Mockito.doReturn(0l).when(vlanSpy).getId();
+        
when(testOrchastrator._vlanDao.findByNetworkIdAndIpv4(Mockito.anyLong(), 
Mockito.anyString())).thenReturn(vlanSpy);
+        
when(testOrchastrator._ipAddressDao.acquireInLockTable(Mockito.anyLong())).thenReturn(ipVoSpy);
+        when(testOrchastrator._ipAddressDao.update(Mockito.anyLong(), 
Mockito.any(IPAddressVO.class))).thenReturn(true);
+        
when(testOrchastrator._ipAddressDao.releaseFromLockTable(Mockito.anyLong())).thenReturn(true);
+        try {
+            
when(testOrchastrator._networkModel.getNextAvailableMacAddressInNetwork(Mockito.anyLong())).thenReturn(macAddress);
+        } catch (InsufficientAddressCapacityException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void verifyAndAssert(String requestedIpv4Address, String 
ipv4Gateway, String ipv4Netmask, NicProfile nicProfile, int 
acquireLockAndCheckIfIpv4IsFreeTimes,
+            int nextMacAddressTimes) {
+        verify(testOrchastrator, 
times(acquireLockAndCheckIfIpv4IsFreeTimes)).acquireLockAndCheckIfIpv4IsFree(Mockito.any(Network.class),
 Mockito.anyString());
+        try {
+            verify(testOrchastrator._networkModel, 
times(nextMacAddressTimes)).getNextAvailableMacAddressInNetwork(Mockito.anyLong());
+        } catch (InsufficientAddressCapacityException e) {
+            e.printStackTrace();
+        }
+
+        assertEquals(requestedIpv4Address, nicProfile.getIPv4Address());
+        assertEquals(ipv4Gateway, nicProfile.getIPv4Gateway());
+        assertEquals(ipv4Netmask, nicProfile.getIPv4Netmask());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testAcquireLockAndCheckIfIpv4IsFreeTestIpvoNull() {
+        executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State.Free, 
true, 1, 0, 0, 0, 0);
+    }
+
+    @Test
+    public void testAcquireLockAndCheckIfIpv4IsFreeTestExpectedFlow() {
+        executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State.Free, 
false, 1, 1, 1, 1, 1);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testAcquireLockAndCheckIfIpv4IsFreeTestAllocatedIp() {
+        
executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State.Allocated, false, 
1, 1, 1, 0, 1);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testAcquireLockAndCheckIfIpv4IsFreeTestAllocatingIp() {
+        
executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State.Allocating, false, 
1, 1, 1, 0, 1);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testAcquireLockAndCheckIfIpv4IsFreeTestReleasingIp() {
+        
executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State.Releasing, false, 
1, 1, 1, 0, 1);
+    }
+
+    private void executeTestAcquireLockAndCheckIfIpv4IsFree(IPAddressVO.State 
state, boolean isIPAddressVONull, int findByIpTimes, int acquireLockTimes, int 
releaseFromLockTimes,
+            int updateTimes, int validateTimes) {
+        Network network = Mockito.spy(new NetworkVO());
+        IPAddressVO ipVoSpy = Mockito.spy(new IPAddressVO(new 
Ip("192.168.100.100"), 0l, 0l, 0l, true));
+        ipVoSpy.setState(state);
+        ipVoSpy.setState(state);
+        if (isIPAddressVONull) {
+            
when(testOrchastrator._ipAddressDao.findByIpAndSourceNetworkId(Mockito.anyLong(),
 Mockito.anyString())).thenReturn(null);
+        } else {
+            
when(testOrchastrator._ipAddressDao.findByIpAndSourceNetworkId(Mockito.anyLong(),
 Mockito.anyString())).thenReturn(ipVoSpy);
+        }
+        
when(testOrchastrator._ipAddressDao.acquireInLockTable(Mockito.anyLong())).thenReturn(ipVoSpy);
+        
when(testOrchastrator._ipAddressDao.releaseFromLockTable(Mockito.anyLong())).thenReturn(true);
+        when(testOrchastrator._ipAddressDao.update(Mockito.anyLong(), 
Mockito.any(IPAddressVO.class))).thenReturn(true);
+
+        testOrchastrator.acquireLockAndCheckIfIpv4IsFree(network, 
"192.168.100.150");
+
+        verify(testOrchastrator._ipAddressDao, 
Mockito.times(findByIpTimes)).findByIpAndSourceNetworkId(Mockito.anyLong(), 
Mockito.anyString());
+        verify(testOrchastrator._ipAddressDao, 
Mockito.times(acquireLockTimes)).acquireInLockTable(Mockito.anyLong());
+        verify(testOrchastrator._ipAddressDao, 
Mockito.times(releaseFromLockTimes)).releaseFromLockTable(Mockito.anyLong());
+        verify(testOrchastrator._ipAddressDao, 
Mockito.times(updateTimes)).update(Mockito.anyLong(), 
Mockito.any(IPAddressVO.class));
+        verify(testOrchastrator, 
Mockito.times(validateTimes)).validateLockedRequestedIp(Mockito.any(IPAddressVO.class),
 Mockito.any(IPAddressVO.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateLockedRequestedIpTestNullLockedIp() {
+        IPAddressVO ipVoSpy = Mockito.spy(new IPAddressVO(new 
Ip("192.168.100.100"), 0l, 0l, 0l, true));
+        testOrchastrator.validateLockedRequestedIp(ipVoSpy, null);
+    }
+
+    @Test
+    public void validateLockedRequestedIpTestNotFreeLockedIp() {
+        IPAddressVO ipVoSpy = Mockito.spy(new IPAddressVO(new 
Ip("192.168.100.100"), 0l, 0l, 0l, true));
+        State[] states = State.values();
+        for(int i=0; i < states.length;i++) {
+            boolean expectedException = false;
+            if (states[i] == State.Free) {
+                continue;
+            }
+            IPAddressVO lockedIp = ipVoSpy;
+            lockedIp.setState(states[i]);
+            try {
+                testOrchastrator.validateLockedRequestedIp(ipVoSpy, lockedIp);
+            } catch (InvalidParameterValueException e) {
+                expectedException = true;
+            }
+            Assert.assertTrue(expectedException);
+        }
+    }
+
+    @Test
+    public void validateLockedRequestedIpTestFreeAndNotNullIp() {
+        IPAddressVO ipVoSpy = Mockito.spy(new IPAddressVO(new 
Ip("192.168.100.100"), 0l, 0l, 0l, true));
+        IPAddressVO lockedIp = ipVoSpy;
+        lockedIp.setState(State.Free);
+        testOrchastrator.validateLockedRequestedIp(ipVoSpy, lockedIp);
+    }
+
 }
diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java 
b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java
index e92a5cc..a3e3c60 100644
--- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java
+++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java
@@ -27,6 +27,8 @@ public interface VlanDao extends GenericDao<VlanVO, Long> {
 
     VlanVO findByZoneAndVlanId(long zoneId, String vlanId);
 
+    VlanVO findByNetworkIdAndIpv4(long networkId, String ipv4Address);
+
     List<VlanVO> listByZone(long zoneId);
 
     List<VlanVO> listByType(Vlan.VlanType vlanType);
diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java
index 0c59148..2737beb 100644
--- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java
@@ -43,6 +43,7 @@ import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
 
 @Component
 public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements 
VlanDao {
@@ -82,6 +83,24 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, 
Long> implements VlanDao
         return findOneBy(sc);
     }
 
+    /**
+     * Returns a vlan by the network id and if the given IPv4 is in the 
network IP range.
+     */
+    @Override
+    public VlanVO findByNetworkIdAndIpv4(long networkId, String ipv4Address) {
+        List<VlanVO> vlanVoList = listVlansByNetworkId(networkId);
+        for (VlanVO vlan : vlanVoList) {
+            String ipRange = vlan.getIpRange();
+            String[] ipRangeParts = ipRange.split("-");
+            String startIP = ipRangeParts[0];
+            String endIP = ipRangeParts[1];
+            if (NetUtils.isIpInRange(ipv4Address, startIP, endIP)) {
+                return vlan;
+            }
+        }
+        return null;
+    }
+
     @Override
     public List<VlanVO> listByZone(long zoneId) {
         SearchCriteria<VlanVO> sc = ZoneSearch.create();
diff --git 
a/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java 
b/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
index a797b24..01b3389 100644
--- a/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
@@ -30,8 +30,8 @@ import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.Pod;
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.Vlan;
-import com.cloud.dc.VlanVO;
 import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.PodVlanMapDao;
 import com.cloud.dc.dao.VlanDao;
@@ -44,10 +44,10 @@ import com.cloud.network.Network;
 import com.cloud.network.Networks.AddressFormat;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.IsolationType;
+import com.cloud.network.PhysicalNetwork;
 import com.cloud.network.addr.PublicIp;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
-import com.cloud.network.PhysicalNetwork;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.utils.db.DB;
@@ -55,7 +55,6 @@ import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 import com.cloud.utils.db.TransactionStatus;
-import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.Nic;
 import com.cloud.vm.Nic.ReservationStrategy;
@@ -106,10 +105,6 @@ public class DirectPodBasedNetworkGuru extends 
DirectNetworkGuru {
             rsStrategy = ReservationStrategy.Create;
         }
 
-        if (nic != null && nic.getRequestedIPv4() != null) {
-            throw new CloudRuntimeException("Does not support custom ip 
allocation at this time: " + nic);
-        }
-
         if (nic == null) {
             nic = new NicProfile(rsStrategy, null, null, null, null);
         } else if (nic.getIPv4Address() == null) {
diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java 
b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
index b9762fd..958dfc6 100644
--- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
@@ -479,9 +479,23 @@ public class NetUtils {
         return validator.isValidInet4Address(ip);
     }
 
+    /**
+     * Returns true if the given IPv4 address is in the specific Ipv4 range
+     */
+    public static boolean isIpInRange(final String ipInRange, final String 
startIP, final String endIP) {
+        if (ipInRange == null || !validIpRange(startIP, endIP))
+            return false;
+
+        final long ipInRangeLong = NetUtils.ip2Long(ipInRange);
+        final long startIPLong = NetUtils.ip2Long(startIP);
+        final long endIPLong = NetUtils.ip2Long(endIP);
+
+        return startIPLong <= ipInRangeLong && ipInRangeLong <= endIPLong;
+    }
+
     public static boolean is31PrefixCidr(final String cidr) {
         final boolean isValidCird = isValidIp4Cidr(cidr);
-        if (isValidCird){
+        if (isValidCird) {
             final String[] cidrPair = cidr.split("\\/");
             final String cidrSize = cidrPair[1];
 

Reply via email to