diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 6dc67521663..88f23f05e66 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -57,7 +57,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Service PortForwarding = new Service("PortForwarding"); public static final Service SecurityGroup = new Service("SecurityGroup"); public static final Service NetworkACL = new Service("NetworkACL", Capability.SupportedProtocols); - public static final Service Connectivity = new Service("Connectivity"); + public static final Service Connectivity = new Service("Connectivity", Capability.RegionLevelVpc); private final String name; private final Capability[] caps; @@ -186,6 +186,8 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability SslTermination = new Capability("SslTermination"); public static final Capability LbSchemes = new Capability("LbSchemes"); public static final Capability DhcpAccrossMultipleSubnets = new Capability("DhcpAccrossMultipleSubnets"); + public static final Capability StretchedL2Subnet = new Capability("StretchedL2Subnet"); + public static final Capability RegionLevelVpc = new Capability("RegionLevelVpc"); private final String name; diff --git a/api/src/com/cloud/network/vpc/VpcOffering.java b/api/src/com/cloud/network/vpc/VpcOffering.java index 6e75a2f2500..a56a68540e6 100644 --- a/api/src/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/com/cloud/network/vpc/VpcOffering.java @@ -55,4 +55,9 @@ public interface VpcOffering extends InternalIdentity, Identity { */ Long getServiceOfferingId(); + /** + * + * @return true if VPC created with the offering can span multiple zones in the region + */ + boolean offersRegionLevelVPC(); } diff --git a/api/src/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/com/cloud/network/vpc/VpcProvisioningService.java index 174b71f34a2..82a7baae959 100644 --- a/api/src/com/cloud/network/vpc/VpcProvisioningService.java +++ b/api/src/com/cloud/network/vpc/VpcProvisioningService.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.vpc; + import java.util.List; import java.util.Map; @@ -23,8 +24,10 @@ public interface VpcProvisioningService { public VpcOffering getVpcOffering(long vpcOfferingId); - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders, - Long serviceOfferingId); + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, + Map> serviceProviders, + Map serviceCapabilitystList, + Long serviceOfferingId); List listVpcOfferings(Long id, String name, String displayText, List supportedServicesStr, Boolean isDefault, String keyword, String state, Long startIndex, Long pageSizeVal); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 0a3fafda312..37852500d73 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -586,6 +586,7 @@ public class ApiConstants { public static final String VGPU = "vgpu"; public static final String VGPUTYPE = "vgputype"; public static final String REMAININGCAPACITY = "remainingcapacity"; + public static final String SUPPORTS_REGION_LEVEL_VPC = "supportsregionLevelvpc"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 6b2c4ba5cab..60b403c36ce 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -23,6 +23,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -62,6 +64,9 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { description = "services supported by the vpc offering") private List supportedServices; + @Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "desired service capabilities as part of vpc offering") + private Map serviceCapabilitystList; + @Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST, type = CommandType.MAP, description = "provider to service mapping. " + "If not specified, the provider for the service will be mapped to the default provider on the physical network") private Map serviceProviderList; @@ -118,7 +123,8 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException { - VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), getServiceProviders(), getServiceOfferingId()); + VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), + getServiceProviders(), serviceCapabilitystList, getServiceOfferingId()); if (vpcOff != null) { setEntityId(vpcOff.getId()); setEntityUuid(vpcOff.getUuid()); diff --git a/api/src/org/apache/cloudstack/api/response/VpcOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/VpcOfferingResponse.java index 17e4dfdd0b6..27432bc6bd2 100644 --- a/api/src/org/apache/cloudstack/api/response/VpcOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VpcOfferingResponse.java @@ -59,6 +59,10 @@ public class VpcOfferingResponse extends BaseResponse { @Param(description = "the list of supported services", responseObject = ServiceResponse.class) private List services; + @SerializedName((ApiConstants.SUPPORTS_REGION_LEVEL_VPC)) + @Param(description = " indicated if the offering can support region level vpc") + private Boolean supportsRegionLevelVpc; + public void setId(String id) { this.id = id; } @@ -86,4 +90,8 @@ public class VpcOfferingResponse extends BaseResponse { public void setState(String state) { this.state = state; } + + public void setSupportsRegionLevelVpc(Boolean supports) { + this.supportsRegionLevelVpc = supports; + } } diff --git a/engine/schema/src/com/cloud/network/vpc/VpcOfferingVO.java b/engine/schema/src/com/cloud/network/vpc/VpcOfferingVO.java index 3a676e6af5e..43ad5149671 100644 --- a/engine/schema/src/com/cloud/network/vpc/VpcOfferingVO.java +++ b/engine/schema/src/com/cloud/network/vpc/VpcOfferingVO.java @@ -67,6 +67,9 @@ public class VpcOfferingVO implements VpcOffering { @Column(name = "service_offering_id") Long serviceOfferingId; + @Column(name = "supports_region_level_vpc") + boolean offersRegionLevelVPC = false; + public VpcOfferingVO() { this.uuid = UUID.randomUUID().toString(); } @@ -80,9 +83,11 @@ public class VpcOfferingVO implements VpcOffering { this.state = State.Disabled; } - public VpcOfferingVO(String name, String displayText, boolean isDefault, Long serviceOfferingId) { + public VpcOfferingVO(String name, String displayText, boolean isDefault, Long serviceOfferingId, + boolean offersRegionLevelVPC) { this(name, displayText, serviceOfferingId); this.isDefault = isDefault; + this.offersRegionLevelVPC = offersRegionLevelVPC; } @Override @@ -145,4 +150,9 @@ public class VpcOfferingVO implements VpcOffering { public Long getServiceOfferingId() { return serviceOfferingId; } + + @Override + public boolean offersRegionLevelVPC() { + return offersRegionLevelVPC; + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 81bfe21ee81..74e973a061b 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2748,7 +2748,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setDisplayText(offering.getDisplayText()); response.setIsDefault(offering.isDefault()); response.setState(offering.getState().name()); - + response.setSupportsRegionLevelVpc(offering.supportsRegionLevelVpc()); Map> serviceProviderMap = ApiDBUtils.listVpcOffServices(offering.getId()); List serviceResponses = new ArrayList(); for (Service service : serviceProviderMap.keySet()) { diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 762cc6f3993..b8d6478f3cd 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -16,10 +16,13 @@ // under the License. package com.cloud.network.vpc; + import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -231,7 +234,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled, null); + createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, + svcProviderMap, true, State.Enabled, null, false); } //configure default vpc offering with Netscaler as LB Provider @@ -250,7 +254,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis svcProviderMap.put(svc, defaultProviders); } } - createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, svcProviderMap, false, State.Enabled, null); + createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, + svcProviderMap, false, State.Enabled, null, false); } } }); @@ -299,8 +304,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true) - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders, - Long serviceOfferingId) { + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, + Map> serviceProviders, + Map serviceCapabilitystList, + Long serviceOfferingId) { Map> svcProviderMap = new HashMap>(); Set defaultProviders = new HashSet(); defaultProviders.add(Provider.VPCVirtualRouter); @@ -372,7 +379,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null, serviceOfferingId); + boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilitystList); + + VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null, serviceOfferingId, offersRegionLevelVPC); CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); return offering; @@ -380,12 +389,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @DB protected VpcOffering createVpcOffering(final String name, final String displayText, final Map> svcProviderMap, - final boolean isDefault, final State state, final Long serviceOfferingId) { + final boolean isDefault, final State state, final Long serviceOfferingId, final boolean offersRegionLevelVPC) { return Transaction.execute(new TransactionCallback() { @Override public VpcOffering doInTransaction(TransactionStatus status) { // create vpc offering object - VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId); + VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId, offersRegionLevelVPC); if (state != null) { offering.setState(state); @@ -413,6 +422,44 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis }); } + private boolean isVpcOfferingForRegionLevelVpc(Map serviceCapabilitystList) { + boolean offersRegionLevelVPC = false; + if (serviceCapabilitystList != null && !serviceCapabilitystList.isEmpty()) { + Collection serviceCapabilityCollection = serviceCapabilitystList.values(); + Iterator iter = serviceCapabilityCollection.iterator(); + Map capabilityMap = null; + + while (iter.hasNext()) { + HashMap svcCapabilityMap = (HashMap)iter.next(); + Network.Capability capability = null; + String svc = svcCapabilityMap.get("service"); + String capabilityName = svcCapabilityMap.get("capabilitytype"); + String capabilityValue = svcCapabilityMap.get("capabilityvalue"); + if (capabilityName != null) { + capability = Network.Capability.getCapability(capabilityName); + } + + if ((capability == null) || (capabilityName == null) || (capabilityValue == null)) { + throw new InvalidParameterValueException("Invalid capability:" + capabilityName + " capability value:" + capabilityValue); + } + + if (!svc.equalsIgnoreCase(Service.Connectivity.getName())) { + throw new InvalidParameterValueException("Invalid Service:" + svc + " specified. Only for 'Connectivity' service capabilities can be specified"); + } + + if (!capabilityName.equalsIgnoreCase("RegionLevelVpc")) { + throw new InvalidParameterValueException("Invalid Capability:" + capabilityName + " specified. Only 'RegionLevelVpc' capability can be specified."); + } + + if (!capabilityValue.equalsIgnoreCase("true") && capabilityValue.equalsIgnoreCase("false")) { + throw new InvalidParameterValueException("Invalid Capability value:" + capabilityValue + " specified."); + } + offersRegionLevelVPC = capabilityValue.equalsIgnoreCase("true"); + } + } + return offersRegionLevelVPC; + } + @Override public Vpc getActiveVpc(long vpcId) { return _vpcDao.getActiveVpcById(vpcId);