in server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java [6694:7037]
public NetworkOfferingVO createNetworkOffering(final String name, final String displayText, final TrafficType trafficType, String tags, final boolean specifyVlan,
final Availability availability,
final Integer networkRate, final Map<Service, Set<Provider>> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly,
final Long serviceOfferingId,
final boolean conserveMode, final Map<Service, Map<Capability, String>> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent,
final Map<Detail, String> details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc,
Boolean forTungsten, boolean forNsx, NetworkOffering.NetworkMode networkMode, final List<Long> domainIds, final List<Long> zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol,
final NetworkOffering.RoutingMode routingMode, final boolean specifyAsNumber) {
String servicePackageUuid;
String spDescription = null;
if (details == null) {
servicePackageUuid = null;
} else {
servicePackageUuid = details.get(NetworkOffering.Detail.servicepackageuuid);
spDescription = details.get(NetworkOffering.Detail.servicepackagedescription);
}
final String multicastRateStr = _configDao.getValue("multicast.throttling.rate");
final int multicastRate = multicastRateStr == null ? 10 : Integer.parseInt(multicastRateStr);
tags = com.cloud.utils.StringUtils.cleanupTags(tags);
// specifyIpRanges should always be true for Shared networks
// specifyIpRanges can only be true for Isolated networks with no Source
// Nat service
if (specifyIpRanges) {
if (type == GuestType.Isolated) {
if (serviceProviderMap.containsKey(Service.SourceNat)) {
throw new InvalidParameterValueException("SpecifyIpRanges can only be true for Shared network offerings and Isolated with no SourceNat service");
}
}
} else {
if (type == GuestType.Shared) {
throw new InvalidParameterValueException("SpecifyIpRanges should always be true for Shared network offerings");
}
}
if (specifyAsNumber && !forNsx) {
String msg = "SpecifyAsNumber can only be true for network offerings for NSX";
logger.error(msg);
throw new InvalidParameterValueException(msg);
}
if (specifyAsNumber && !Dynamic.equals(routingMode)) {
String msg = "SpecifyAsNumber can only be true for Dynamic Route Mode network offerings";
logger.error(msg);
throw new InvalidParameterValueException(msg);
}
if (specifyAsNumber && Boolean.TRUE.equals(forVpc)) {
String msg = "SpecifyAsNumber cannot be set for VPC network tiers. It needs to be defined at VPC level";
logger.error(msg);
throw new InvalidParameterValueException(msg);
}
// isPersistent should always be false for Shared network Offerings
if (isPersistent && type == GuestType.Shared) {
throw new InvalidParameterValueException("isPersistent should be false if network offering's type is " + type);
}
// Validate network mode
if (networkMode != null) {
if (type != GuestType.Isolated) {
throw new InvalidParameterValueException("networkMode should be set only for Isolated network offerings");
}
if (NetworkOffering.NetworkMode.ROUTED.equals(networkMode)) {
if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.value()) {
throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed networks", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key()));
}
if (zoneIds != null) {
for (Long zoneId: zoneIds) {
if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.valueIn(zoneId)) {
throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed networks in zone (ID: %s)", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key(), zoneId));
}
}
}
boolean useVirtualRouterOnly = true;
for (Service service : serviceProviderMap.keySet()) {
Set<Provider> providers = serviceProviderMap.get(service);
if (Arrays.asList(Service.SourceNat, Service.StaticNat, Service.Lb, Service.PortForwarding, Service.Vpn).contains(service)) {
if (providers != null) {
throw new InvalidParameterValueException("SourceNat/StaticNat/Lb/PortForwarding/Vpn service are not supported in ROUTED mode");
}
}
if (useVirtualRouterOnly && Arrays.asList(Service.Firewall, Service.NetworkACL).contains(service)) {
for (Provider provider : providers) {
if (!Provider.VirtualRouter.equals(provider) && !Provider.VPCVirtualRouter.equals(provider)) {
useVirtualRouterOnly = false;
break;
}
}
}
}
if (useVirtualRouterOnly) {
// Add VirtualRouter/VPCVirtualRouter as provider of Gateway service
if (forVpc) {
serviceProviderMap.put(Service.Gateway, Sets.newHashSet(Provider.VPCVirtualRouter));
} else {
serviceProviderMap.put(Service.Gateway, Sets.newHashSet(Provider.VirtualRouter));
}
}
}
}
// validate availability value
if (availability == NetworkOffering.Availability.Required) {
final boolean canOffBeRequired = type == GuestType.Isolated && serviceProviderMap.containsKey(Service.SourceNat);
if (!canOffBeRequired) {
throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + " only for networkOfferings of type "
+ GuestType.Isolated + " and with " + Service.SourceNat.getName() + " enabled");
}
// only one network offering in the system can be Required
final List<NetworkOfferingVO> offerings = _networkOfferingDao.listByAvailability(Availability.Required, false);
if (!offerings.isEmpty()) {
throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + " with availability " + Availability.Required);
}
}
boolean dedicatedLb = false;
boolean elasticLb = false;
boolean sharedSourceNat = false;
boolean redundantRouter = false;
boolean elasticIp = false;
boolean associatePublicIp = false;
boolean inline = false;
boolean publicLb = false;
boolean internalLb = false;
boolean strechedL2Subnet = false;
boolean publicAccess = false;
boolean vmAutoScaling = false;
if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) {
final Map<Capability, String> lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb);
if (lbServiceCapabilityMap != null && !lbServiceCapabilityMap.isEmpty()) {
final String isolationCapability = lbServiceCapabilityMap.get(Capability.SupportedLBIsolation);
if (isolationCapability != null) {
_networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.SupportedLBIsolation, isolationCapability);
dedicatedLb = isolationCapability.contains("dedicated");
} else {
dedicatedLb = true;
}
final String param = lbServiceCapabilityMap.get(Capability.ElasticLb);
if (param != null) {
elasticLb = param.contains("true");
}
final String inlineMode = lbServiceCapabilityMap.get(Capability.InlineMode);
if (inlineMode != null) {
_networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.InlineMode, inlineMode);
inline = inlineMode.contains("true");
} else {
inline = false;
}
final String publicLbStr = lbServiceCapabilityMap.get(Capability.LbSchemes);
if (serviceProviderMap.containsKey(Service.Lb)) {
if (publicLbStr != null) {
_networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.LbSchemes, publicLbStr);
internalLb = publicLbStr.contains("internal");
publicLb = publicLbStr.contains("public");
}
}
final String vmAutoScalingStr = lbServiceCapabilityMap.get(Capability.VmAutoScaling);
if (vmAutoScalingStr != null) {
_networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.VmAutoScaling, vmAutoScalingStr);
vmAutoScaling = vmAutoScalingStr.contains("true");
}
}
// in the current version of the code, publicLb and specificLb can't
// both be set to true for the same network offering
if (publicLb && internalLb) {
throw new InvalidParameterValueException("Public lb and internal lb can't be enabled at the same time on the offering");
}
final Map<Capability, String> sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat);
if (MapUtils.isNotEmpty(sourceNatServiceCapabilityMap)) {
sharedSourceNat = isSharedSourceNat(serviceProviderMap, sourceNatServiceCapabilityMap);
redundantRouter = isRedundantRouter(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, sourceNatServiceCapabilityMap);
}
final Map<Capability, String> gatewayServiceCapabilityMap = serviceCapabilityMap.get(Service.Gateway);
if (MapUtils.isNotEmpty(gatewayServiceCapabilityMap)) {
redundantRouter = redundantRouter || isRedundantRouter(serviceProviderMap.get(Service.Gateway), Service.Gateway, gatewayServiceCapabilityMap);
}
final Map<Capability, String> staticNatServiceCapabilityMap = serviceCapabilityMap.get(Service.StaticNat);
if (staticNatServiceCapabilityMap != null && !staticNatServiceCapabilityMap.isEmpty()) {
final String param = staticNatServiceCapabilityMap.get(Capability.ElasticIp);
if (param != null) {
elasticIp = param.contains("true");
final String associatePublicIP = staticNatServiceCapabilityMap.get(Capability.AssociatePublicIP);
if (associatePublicIP != null) {
associatePublicIp = associatePublicIP.contains("true");
}
}
}
final Map<Capability, String> connectivityServiceCapabilityMap = serviceCapabilityMap.get(Service.Connectivity);
if (connectivityServiceCapabilityMap != null && !connectivityServiceCapabilityMap.isEmpty()) {
if (connectivityServiceCapabilityMap.containsKey(Capability.StretchedL2Subnet)) {
final String value = connectivityServiceCapabilityMap.get(Capability.StretchedL2Subnet);
if ("true".equalsIgnoreCase(value)) {
strechedL2Subnet = true;
}
}
if (connectivityServiceCapabilityMap.containsKey(Capability.PublicAccess)) {
final String value = connectivityServiceCapabilityMap.get(Capability.PublicAccess);
if ("true".equalsIgnoreCase(value)) {
publicAccess = true;
}
}
}
}
if (serviceProviderMap != null && serviceProviderMap.containsKey(Service.Lb) && !internalLb && !publicLb) {
//if not specified, default public lb to true
publicLb = true;
}
final NetworkOfferingVO offeringFinal = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, networkRate, multicastRate, isDefault, availability,
tags, type, conserveMode, dedicatedLb, sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp, publicLb,
internalLb, forVpc, egressDefaultPolicy, strechedL2Subnet, publicAccess);
if (serviceOfferingId != null) {
offeringFinal.setServiceOfferingId(serviceOfferingId);
}
offeringFinal.setForTungsten(Objects.requireNonNullElse(forTungsten, false));
offeringFinal.setForNsx(Objects.requireNonNullElse(forNsx, false));
offeringFinal.setNetworkMode(networkMode);
if (enableOffering) {
offeringFinal.setState(NetworkOffering.State.Enabled);
}
offeringFinal.setSpecifyAsNumber(specifyAsNumber);
if (routingMode != null) {
offeringFinal.setRoutingMode(routingMode);
}
// Set VM AutoScaling capability
offeringFinal.setSupportsVmAutoScaling(vmAutoScaling);
//Set Service package id
offeringFinal.setServicePackage(servicePackageUuid);
// validate the details
if (details != null) {
validateNtwkOffDetails(details, serviceProviderMap);
}
boolean vpcOff = false;
boolean nsOff = false;
if (serviceProviderMap != null && spDescription != null) {
for (final Network.Service service : serviceProviderMap.keySet()) {
final Set<Provider> providers = serviceProviderMap.get(service);
if (providers != null && !providers.isEmpty()) {
for (final Network.Provider provider : providers) {
if (provider == Provider.VPCVirtualRouter) {
vpcOff = true;
}
if (provider == Provider.Netscaler) {
nsOff = true;
}
}
}
}
if(vpcOff && nsOff) {
if(!(spDescription.equalsIgnoreCase("A NetScalerVPX is dedicated per network.") || spDescription.contains("dedicated NetScaler"))) {
throw new InvalidParameterValueException("Only NetScaler Service Package with Dedicated Device Mode is Supported in VPC Type Guest Network");
}
}
}
return Transaction.execute(new TransactionCallback<NetworkOfferingVO>() {
@Override
public NetworkOfferingVO doInTransaction(final TransactionStatus status) {
NetworkOfferingVO offering = offeringFinal;
// 1) create network offering object
logger.debug("Adding network offering " + offering);
offering.setConcurrentConnections(maxconn);
offering.setKeepAliveEnabled(enableKeepAlive);
offering = _networkOfferingDao.persist(offering, details);
// 2) populate services and providers
if (serviceProviderMap != null) {
for (final Network.Service service : serviceProviderMap.keySet()) {
final Set<Provider> providers = serviceProviderMap.get(service);
if (providers != null && !providers.isEmpty()) {
boolean vpcOff = false;
for (final Network.Provider provider : providers) {
if (provider == Provider.VPCVirtualRouter) {
vpcOff = true;
}
final NetworkOfferingServiceMapVO offService = new NetworkOfferingServiceMapVO(offering.getId(), service, provider);
_ntwkOffServiceMapDao.persist(offService);
logger.trace("Added service for the network offering: " + offService + " with provider " + provider.getName());
}
if (vpcOff && !forNsx) {
final List<Service> supportedSvcs = new ArrayList<Service>();
supportedSvcs.addAll(serviceProviderMap.keySet());
_vpcMgr.validateNtwkOffForVpc(offering, supportedSvcs);
}
} else {
final NetworkOfferingServiceMapVO offService = new NetworkOfferingServiceMapVO(offering.getId(), service, null);
_ntwkOffServiceMapDao.persist(offService);
logger.trace("Added service for the network offering: " + offService + " with null provider");
}
}
if (offering != null) {
// Filter child domains when both parent and child domains are present
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
List<NetworkOfferingDetailsVO> detailsVO = new ArrayList<>();
for (Long domainId : filteredDomainIds) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.domainid, String.valueOf(domainId), false));
}
if (CollectionUtils.isNotEmpty(zoneIds)) {
for (Long zoneId : zoneIds) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId), false));
}
}
if (internetProtocol != null) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.internetProtocol, String.valueOf(internetProtocol), true));
}
if (!detailsVO.isEmpty()) {
for (NetworkOfferingDetailsVO detail : detailsVO) {
networkOfferingDetailsDao.persist(detail);
}
}
}
}
return offering;
}
});
}