rhtyd closed pull request #2615: config-drive: support user data on L2 networks
URL: https://github.com/apache/cloudstack/pull/2615
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
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 cec2e5926c1..f9d63676f8c 100644
---
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -2290,13 +2290,14 @@ public Network createGuestNetwork(final long
networkOfferingId, final String nam
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);
@@ -2395,6 +2396,21 @@ public Network doInTransaction(final TransactionStatus
status) {
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 2d15403a865..b0283f35c1b 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.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 @@
/**
* NetworkManagerImpl implements NetworkManager.
*/
+@RunWith(JUnit4.class)
public class NetworkOrchestratorTest extends TestCase {
static final Logger s_logger =
Logger.getLogger(NetworkOrchestratorTest.class);
@@ -65,6 +71,10 @@
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 void setUp() {
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 void testDontRemoveDhcpServiceWhenNotProvided() {
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 5edd2288231..60b21c382eb 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -580,7 +580,7 @@ public boolean canUseForDeploy(Network network) {
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 c7e6aca22b8..3f6562e0eee 100644
--- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
@@ -200,7 +200,7 @@ public Network design(final NetworkOffering offering, final
DeploymentPlan plan,
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 NicProfile allocate(final Network network,
NicProfile nic, final VirtualM
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 79916f5e411..2eee7bbeae0 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 583db58bb45..bbe8f3e64b4 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: ''
}
};
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services