You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/05/09 16:03:18 UTC

[cloudstack] branch 4.11 updated: config-drive: support user data on L2 networks (#2615)

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

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


The following commit(s) were added to refs/heads/4.11 by this push:
     new bd89760  config-drive: support user data on L2 networks (#2615)
bd89760 is described below

commit bd8976010835acaa690c85775d0504a4ff8df894
Author: Nicolas Vazquez <ni...@gmail.com>
AuthorDate: Wed May 9 13:03:11 2018 -0300

    config-drive: support user data on L2 networks (#2615)
    
    Supporting ConfigDrive user data on L2 networks.
    Add UI checkbox to create L2 network offering with config drive.
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
 .../engine/orchestration/NetworkOrchestrator.java  | 20 +++++++++--
 .../orchestration/NetworkOrchestratorTest.java     | 41 ++++++++++++++++++++++
 server/src/com/cloud/network/NetworkModelImpl.java |  2 +-
 .../com/cloud/network/guru/GuestNetworkGuru.java   |  4 +--
 ui/scripts/configuration.js                        | 19 ++++++++++
 ui/scripts/docs.js                                 |  4 +++
 6 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 1b707c3..5508472 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -2291,13 +2291,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
         final boolean cidrRequired = zone.getNetworkType() == NetworkType.Advanced
                 && ntwkOff.getTrafficType() == TrafficType.Guest
                 && (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated
-                && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))
-                || ntwkOff.getGuestType() == GuestType.L2 && !_networkModel.listNetworkOfferingServices(ntwkOff.getId()).isEmpty());
+                && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)));
         if (cidr == null && ip6Cidr == null && cidrRequired) {
             throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared
                     + " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled");
         }
 
+        checkL2OfferingServices(ntwkOff);
+
         // No cidr can be specified in Basic zone
         if (zone.getNetworkType() == NetworkType.Basic && cidr != null) {
             throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask can't be specified for zone of type " + NetworkType.Basic);
@@ -2396,6 +2397,21 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
         return network;
     }
 
+    /**
+     * Checks for L2 network offering services. Only 2 cases allowed:
+     * - No services
+     * - User Data service only, provided by ConfigDrive
+     * @param ntwkOff network offering
+     */
+    protected void checkL2OfferingServices(NetworkOfferingVO ntwkOff) {
+        if (ntwkOff.getGuestType() == GuestType.L2 && !_networkModel.listNetworkOfferingServices(ntwkOff.getId()).isEmpty() &&
+                (!_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.UserData) ||
+                        (_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.UserData) &&
+                                _networkModel.listNetworkOfferingServices(ntwkOff.getId()).size() > 1))) {
+            throw new InvalidParameterValueException("For L2 networks, only UserData service is allowed");
+        }
+    }
+
     @Override
     @DB
     public boolean shutdownNetwork(final long networkId, final ReservationContext context, final boolean cleanupElements) {
diff --git a/engine/orchestration/test/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java b/engine/orchestration/test/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
index 2d15403..b0283f3 100644
--- a/engine/orchestration/test/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
+++ b/engine/orchestration/test/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
@@ -26,10 +26,15 @@ import java.util.ArrayList;
 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.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Matchers;
 
 import com.cloud.network.Network;
@@ -56,6 +61,7 @@ import junit.framework.TestCase;
 /**
  * NetworkManagerImpl implements NetworkManager.
  */
+@RunWith(JUnit4.class)
 public class NetworkOrchestratorTest extends TestCase {
     static final Logger s_logger = Logger.getLogger(NetworkOrchestratorTest.class);
 
@@ -65,6 +71,10 @@ public class NetworkOrchestratorTest extends TestCase {
     String dhcpProvider = "VirtualRouter";
     NetworkGuru guru = mock(NetworkGuru.class);
 
+    NetworkOfferingVO networkOffering = mock(NetworkOfferingVO.class);
+
+    private static final long networkOfferingId = 1l;
+
     @Override
     @Before
     public void setUp() {
@@ -90,6 +100,9 @@ public class NetworkOrchestratorTest extends TestCase {
         List<NetworkGuru> networkGurus = new ArrayList<NetworkGuru>();
         networkGurus.add(guru);
         testOrchastrator.networkGurus = networkGurus;
+
+        when(networkOffering.getGuestType()).thenReturn(GuestType.L2);
+        when(networkOffering.getId()).thenReturn(networkOfferingId);
     }
 
     @Test
@@ -159,4 +172,32 @@ public class NetworkOrchestratorTest extends TestCase {
         verify(testOrchastrator._ntwkSrvcDao, never()).getProviderForServiceInNetwork(network.getId(), Service.Dhcp);
         verify(testOrchastrator._networksDao, times(1)).findById(nic.getNetworkId());
     }
+
+    @Test
+    public void testCheckL2OfferingServicesEmptyServices() {
+        when(testOrchastrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(new ArrayList<>());
+        when(testOrchastrator._networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.UserData)).thenReturn(false);
+        testOrchastrator.checkL2OfferingServices(networkOffering);
+    }
+
+    @Test
+    public void testCheckL2OfferingServicesUserDataOnly() {
+        when(testOrchastrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.UserData));
+        when(testOrchastrator._networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.UserData)).thenReturn(true);
+        testOrchastrator.checkL2OfferingServices(networkOffering);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckL2OfferingServicesMultipleServicesIncludingUserData() {
+        when(testOrchastrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.UserData, Service.Dhcp));
+        when(testOrchastrator._networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.UserData)).thenReturn(true);
+        testOrchastrator.checkL2OfferingServices(networkOffering);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckL2OfferingServicesMultipleServicesNotIncludingUserData() {
+        when(testOrchastrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
+        when(testOrchastrator._networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.UserData)).thenReturn(false);
+        testOrchastrator.checkL2OfferingServices(networkOffering);
+    }
 }
diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java
index 5edd228..60b21c3 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -580,7 +580,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
         if (network.getTrafficType() != TrafficType.Guest) {
             return false;
         }
-        if (listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
+        if (network.getGuestType() == GuestType.L2 || listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
             return true; // do not check free IPs if there is no service in the network
         }
         boolean hasFreeIps = true;
diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
index c7e6aca..3f6562e 100644
--- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
@@ -200,7 +200,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
             if (userSpecified.getCidr() != null) {
                 network.setCidr(userSpecified.getCidr());
                 network.setGateway(userSpecified.getGateway());
-            } else if (offering.getGuestType() == GuestType.Shared || !_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty()) {
+            } else if (offering.getGuestType() != GuestType.L2 && (offering.getGuestType() == GuestType.Shared || !_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty())) {
                 final String guestNetworkCidr = dc.getGuestNetworkCidr();
                 if (guestNetworkCidr != null) {
                     final String[] cidrTuple = guestNetworkCidr.split("\\/");
@@ -370,7 +370,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
                     guestIp = network.getGateway();
                 } else {
                     guestIp = _ipAddrMgr.acquireGuestIpAddress(network, nic.getRequestedIPv4());
-                    if (guestIp == null && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
+                    if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
                         throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class,
                                 dc.getId());
                     }
diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js
index 79916f5..2eee7bb 100644
--- a/ui/scripts/configuration.js
+++ b/ui/scripts/configuration.js
@@ -2404,8 +2404,10 @@
                                         var $useVpc = args.$form.find('.form-item[rel=\"useVpc\"]');
                                         var $useVpcCb = $useVpc.find("input[type=checkbox]");
                                         var $supportedServices = args.$form.find('.form-item[rel=\"supportedServices\"]');
+                                        var $userDataL2 = args.$form.find('.form-item[rel=\"userDataL2\"]');
                                         if ($guestTypeField.val() == 'Shared') { //Shared network offering
                                             $useVpc.hide();
+                                            $userDataL2.hide();
                                             $supportedServices.css('display', 'inline-block');
                                             if ($useVpcCb.is(':checked')) { //if useVpc is checked,
                                                 $useVpcCb.removeAttr("checked"); //remove "checked" attribute in useVpc
@@ -2413,9 +2415,11 @@
                                         } else if ($guestTypeField.val() == 'Isolated') { //Isolated network offering
                                             $useVpc.css('display', 'inline-block');
                                             $supportedServices.css('display', 'inline-block');
+                                            $userDataL2.hide();
                                         } else if ($guestTypeField.val() == 'L2') {
                                             $useVpc.hide();
                                             $supportedServices.hide();
+                                            $userDataL2.css('display', 'inline-block');
                                         }
                                         var $providers = $useVpcCb.closest('form').find('.dynamic-input select[name!="service.Connectivity.provider"]');
                                         var $optionsOfProviders = $providers.find('option');
@@ -2803,6 +2807,13 @@
                                         isBoolean: true
                                     },
 
+                                    userDataL2: {
+                                        label: 'label.user.data',
+                                        docID: 'helpL2UserData',
+                                        isBoolean: true,
+                                        isHidden: true
+                                    },
+
                                     lbType: { //only shown when VPC is checked and LB service is checked
                                         label: 'label.load.balancer.type',
                                         isHidden: true,
@@ -3384,6 +3395,14 @@
                                     } else { //specifyVlan checkbox is unchecked
                                         delete inputData.specifyVlan; //if specifyVlan checkbox is unchecked, do not pass specifyVlan parameter to API call since we need to keep API call's size as small as possible (p.s. specifyVlan is defaulted as false at server-side)
                                     }
+
+                                    if (inputData['userDataL2'] == 'on') {
+                                        inputData['serviceProviderList[0].service'] = 'UserData';
+                                        inputData['serviceProviderList[0].provider'] = 'ConfigDrive';
+                                        inputData['supportedServices'] = 'UserData';
+                                    } else {
+                                        delete inputData.serviceProviderList;
+                                    }
                                 }
 
                                 if (inputData['forvpc'] == 'on') {
diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js
index 583db58..bbe8f3e 100755
--- a/ui/scripts/docs.js
+++ b/ui/scripts/docs.js
@@ -1351,5 +1351,9 @@ cloudStack.docs = {
     },
     helpSetReservationSystemVms: {
         desc: 'If enabled, IP range reservation is set for SSVM & CPVM. Global setting "system.vm.public.ip.reservation.mode.strictness" is used to control whether reservation is strict or not (preferred)'
+    },
+    helpL2UserData: {
+        desc: 'Pass user and meta data to VMs (via ConfigDrive)',
+        externalLink: ''
     }
 };

-- 
To stop receiving notification emails like this one, please contact
rohit@apache.org.