diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index 5c39060f9fa3..d7e605bd38fa 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -16,12 +16,18 @@ // under the License. package org.apache.cloudstack.api.command.admin.network; + +import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse; +import org.apache.cloudstack.api.response.ZoneResponse; + import com.cloud.offering.NetworkOffering; @@ -42,6 +48,124 @@ public class CreateNetworkOfferingCmd extends NetworkOfferingBaseCmd { @Parameter(name = ApiConstants.GUEST_IP_TYPE, type = CommandType.STRING, required = true, description = "Guest type of the network offering: Shared or Isolated") private String guestIptype; + @Parameter(name = ApiConstants.INTERNET_PROTOCOL, + type = CommandType.STRING, + description = "The internet protocol of network offering. Options are IPv4 and dualstack. Default is IPv4. dualstack will create a network offering that supports both IPv4 and IPv6", + since = "4.17.0") + private String internetProtocol; + + @Parameter(name = ApiConstants.SUPPORTED_SERVICES, + type = CommandType.LIST, + collectionType = CommandType.STRING, + description = "Services supported by the network offering") + private List supportedServices; + + @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; + + @Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "Desired service capabilities as part of network offering") + private Map serviceCapabilitystList; + + @Parameter(name = ApiConstants.SPECIFY_IP_RANGES, + type = CommandType.BOOLEAN, + description = "True if network offering supports specifying ip ranges; defaulted to false if not specified") + private Boolean specifyIpRanges; + + @Parameter(name = ApiConstants.IS_PERSISTENT, + type = CommandType.BOOLEAN, + description = "True if network offering supports persistent networks; defaulted to false if not specified") + private Boolean isPersistent; + + @Parameter(name = ApiConstants.FOR_VPC, + type = CommandType.BOOLEAN, + description = "True if network offering is meant to be used for VPC, false otherwise.") + private Boolean forVpc; + + @Parameter(name = ApiConstants.FOR_NSX, + type = CommandType.BOOLEAN, + description = "true if network offering is meant to be used for NSX, false otherwise.", + since = "4.20.0") + private Boolean forNsx; + + @Parameter(name = ApiConstants.NSX_SUPPORT_LB, + type = CommandType.BOOLEAN, + description = "True if network offering for NSX network offering supports Load balancer service.", + since = "4.20.0") + private Boolean nsxSupportsLbService; + + @Parameter(name = ApiConstants.NSX_SUPPORTS_INTERNAL_LB, + type = CommandType.BOOLEAN, + description = "True if network offering for NSX network offering supports Internal Load balancer service.", + since = "4.20.0") + private Boolean nsxSupportsInternalLbService; + + @Parameter( + name = ApiConstants.NETWORK_MODE, + type = CommandType.STRING, + description = "the network mode of the network offering, possible values are NATTED and ROUTED" + ) + private String networkMode; + + @Parameter(name = ApiConstants.FOR_TUNGSTEN, + type = CommandType.BOOLEAN, + description = "True if network offering is meant to be used for Tungsten-Fabric, false otherwise.") + private Boolean forTungsten; + + @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs." + + " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and" + + " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup") + protected Map details; + + @Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY, + type = CommandType.BOOLEAN, + description = "True if guest network default egress policy is allow; false if default egress policy is deny") + private Boolean egressDefaultPolicy; + + @Parameter(name = ApiConstants.KEEPALIVE_ENABLED, + type = CommandType.BOOLEAN, + required = false, + description = "If true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.") + private Boolean keepAliveEnabled; + + @Parameter(name = ApiConstants.MAX_CONNECTIONS, + type = CommandType.INTEGER, + description = "Maximum number of concurrent connections supported by the Network offering") + private Integer maxConnections; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "The ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "The ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; + + @Parameter(name = ApiConstants.ENABLE, + type = CommandType.BOOLEAN, + description = "Set to true if the offering is to be enabled during creation. Default is false", + since = "4.16") + private Boolean enable; + + @Parameter(name = ApiConstants.SPECIFY_AS_NUMBER, type = CommandType.BOOLEAN, since = "4.20.0", + description = "true if network offering supports choosing AS number") + private Boolean specifyAsNumber; + + @Parameter(name = ApiConstants.ROUTING_MODE, + type = CommandType.STRING, + since = "4.20.0", + description = "the routing mode for the network offering. Supported types are: Static or Dynamic.") + private String routingMode; + + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java index 1c832b7217ef..9e5aed091913 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java @@ -153,11 +153,8 @@ public abstract class NetworkOfferingBaseCmd extends BaseCmd { since = "4.20.0") private Boolean nsxSupportsInternalLbService; - @Parameter(name = ApiConstants.NETWORK_MODE, - type = CommandType.STRING, - description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED", - since = "4.20.0") - private String networkMode; + @Parameter(name = ApiConstants.NETWORK_MODE, type = CommandType.STRING, required = true, description = "the network mode for the network offering") + private String networkMode; @Parameter(name = ApiConstants.FOR_TUNGSTEN, type = CommandType.BOOLEAN, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 2b934a60da7a..94809426e705 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -144,10 +144,11 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { since = "4.16") private Boolean enable; - @Parameter(name = ApiConstants.NETWORK_MODE, + @Parameter( + name = ApiConstants.NETWORK_MODE, type = CommandType.STRING, - description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED", - since = "4.20.0") + description = "the network mode of the vpc, possible values are NATTED and ROUTED" + ) private String networkMode; @Parameter(name = ApiConstants.SPECIFY_AS_NUMBER, type = CommandType.BOOLEAN, since = "4.20.0", diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 164193beeda0..48ad3e223c60 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -7181,8 +7181,8 @@ public NetworkOffering createNetworkOffering(final NetworkOfferingBaseCmd cmd) { throw new InvalidParameterValueException("Network Offering cannot be for multiple providers - Tungsten-Fabric, NSX and Netris"); } - NetworkOffering.NetworkMode networkMode = null; - if (networkModeStr != null) { + NetworkOffering.NetworkMode networkMode = NetworkOffering.NetworkMode.NATTED; // Defensive fallback + if (StringUtils.isNotEmpty(networkModeStr)) { if (!EnumUtils.isValidEnum(NetworkOffering.NetworkMode.class, networkModeStr)) { throw new InvalidParameterValueException("Invalid mode passed. Valid values: " + Arrays.toString(NetworkOffering.NetworkMode.values())); } @@ -7248,6 +7248,9 @@ public NetworkOffering createNetworkOffering(final NetworkOfferingBaseCmd cmd) { _networkSvc.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(serviceOfferingId); } + if (StringUtils.isEmpty(routingModeString)) { + routingModeString = NetworkOffering.RoutingMode.Static.toString(); // Defensive fallback + } NetworkOffering.RoutingMode routingMode = verifyRoutingMode(routingModeString); // configure service provider map diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index bcf2c6176efe..dc931f3f0354 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -572,8 +572,8 @@ public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { final String networkModeStr = cmd.getNetworkMode(); final boolean enable = cmd.getEnable(); - NetworkOffering.NetworkMode networkMode = null; - if (networkModeStr != null) { + NetworkOffering.NetworkMode networkMode = NetworkOffering.NetworkMode.NATTED; + if (StringUtils.isNotEmpty(networkModeStr)) { if (!EnumUtils.isValidEnum(NetworkOffering.NetworkMode.class, networkModeStr)) { throw new InvalidParameterValueException("Invalid mode passed. Valid values: " + Arrays.toString(NetworkOffering.NetworkMode.values())); } @@ -616,6 +616,9 @@ public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { _ntwkSvc.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(serviceOfferingId); } + if (StringUtils.isEmpty(routingModeString)) { + routingModeString = NetworkOffering.RoutingMode.Static.toString(); // Defensive fallback for standard routing + } NetworkOffering.RoutingMode routingMode = ConfigurationManagerImpl.verifyRoutingMode(routingModeString); if (specifyAsNumber && !forNsx) { diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 995b81ce68c6..11e9903485e2 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -711,6 +711,7 @@ export default { }) this.rules = reactive({ name: [{ required: true, message: this.$t('message.error.name') }], + networkmode: [{ required: true, message: this.$t('message.error.select') }], networkrate: [{ type: 'number', validator: this.validateNumber }], serviceofferingid: [{ required: true, message: this.$t('message.error.select') }], domainid: [{ type: 'array', required: true, message: this.$t('message.error.select') }], diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue index 780da6638f8e..6c7391169e11 100644 --- a/ui/src/views/offering/AddVpcOffering.vue +++ b/ui/src/views/offering/AddVpcOffering.vue @@ -366,6 +366,7 @@ export default { }) this.rules = reactive({ name: [{ required: true, message: this.$t('message.error.name') }], + networkmode: [{ required: true, message: this.$t('message.error.select') }], domainid: [{ type: 'array', required: true, message: this.$t('message.error.select') }], zoneid: [{ type: 'array',