mirror of https://github.com/apache/cloudstack.git
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 <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
253f7d7728
commit
bd89760108
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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') {
|
||||
|
|
|
|||
|
|
@ -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: ''
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue