diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 9de104126d6e..82273cfdd0c9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -298,6 +298,7 @@ public class ApiConstants { public static final String MEMORY = "memory"; public static final String MODE = "mode"; public static final String NSX_MODE = "nsxmode"; + public static final String NSX_ENABLED = "isnsxenabled"; public static final String NAME = "name"; public static final String METHOD_NAME = "methodname"; public static final String NETWORK_DOMAIN = "networkdomain"; 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 3873b4415a83..80bd7d4dfef5 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 @@ -59,6 +59,7 @@ import static com.cloud.network.Network.Service.PortForwarding; import static com.cloud.network.Network.Service.NetworkACL; import static com.cloud.network.Network.Service.UserData; +import static com.cloud.network.Network.Service.Firewall; @APICommand(name = "createNetworkOffering", description = "Creates a network offering.", responseObject = NetworkOfferingResponse.class, since = "3.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -251,7 +252,8 @@ public List getSupportedServices() { )); if (Boolean.TRUE.equals(forVpc)) { services.add(NetworkACL.getName()); - return services; + } else { + services.add(Firewall.getName()); } return services; } @@ -338,10 +340,15 @@ public Map> getServiceProviders() { private void getServiceProviderMapForNsx(Map> serviceProviderMap) { String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() : VirtualRouterProvider.Type.VirtualRouter.name(); - List unsupportedServices = List.of("Vpn", "SecurityGroup", "Connectivity", - "Gateway", "Firewall", "BaremetalPxeService"); + List unsupportedServices = new ArrayList<>(List.of("Vpn", "SecurityGroup", "Connectivity", + "Gateway", "BaremetalPxeService")); List routerSupported = List.of("Dhcp", "Dns", "UserData"); List allServices = Service.listAllServices().stream().map(Service::getName).collect(Collectors.toList()); + if (routerProvider.equals(VirtualRouterProvider.Type.VPCVirtualRouter.name())) { + unsupportedServices.add("Firewall"); + } else { + unsupportedServices.add("NetworkACL"); + } for (String service : allServices) { if (unsupportedServices.contains(service)) continue; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java index 4e8e665836c3..a898cd9d5774 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java @@ -145,6 +145,10 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso @Param(description = "the type of the zone - core or edge", since = "4.18.0") String type; + @SerializedName(ApiConstants.NSX_ENABLED) + @Param(description = "true, if zone is NSX enabled", since = "4.20.0") + private boolean nsxEnabled = false; + public ZoneResponse() { tags = new LinkedHashSet(); } @@ -368,4 +372,8 @@ public void setType(String type) { public String getType() { return type; } + + public void setNsxEnabled(boolean nsxEnabled) { + this.nsxEnabled = nsxEnabled; + } } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 6fb7c4e0d0ad..c975e8f351f9 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -63,6 +63,9 @@ public interface ConfigurationManager { static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length"; static final ConfigKey VM_USERDATA_MAX_LENGTH = new ConfigKey<>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768", "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true); + public static final ConfigKey AllowNonRFC1918CompliantIPs = new ConfigKey(Boolean.class, + "allow.non.rfc1918.compliant.ips", "Advanced", "false", + "Allows non-compliant RFC 1918 IPs for Shared, Isolated networks and VPCs", true); /** * @param offering diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 204efdf1a1db..eb54923d130e 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2862,7 +2862,7 @@ private Network createGuestNetwork(final long networkOfferingId, final String na // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4 if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) { - if (!NetUtils.validateGuestCidr(cidr)) { + if (!NetUtils.validateGuestCidr(cidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC 1918 or 6598 compliant"); } } diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql index 0a573a5b6b97..556aeef2bded 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql @@ -58,4 +58,4 @@ FROM LEFT JOIN `cloud`.`vpc_offering_details` AS `offering_details` ON `offering_details`.`offering_id` = `vpc_offerings`.`id` AND `offering_details`.`name`='internetprotocol' GROUP BY - `vpc_offerings`.`id`; \ No newline at end of file + `vpc_offerings`.`id`; diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index 20a32126992b..4daf07b4610f 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -184,6 +184,11 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne private static final Logger LOGGER = Logger.getLogger(KubernetesClusterManagerImpl.class); private static final String DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering used for CloudStack Kubernetes service"; + private static final String DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNSXNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NSX_VPC_TIER_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME = "DefaultNSXVPCNetworkOfferingforKubernetesService"; + private static final String DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering for NSX CloudStack Kubernetes Service"; + private static final String DEFAULT_NSX_VPC_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT = "Network Offering for NSX CloudStack Kubernetes service on VPC"; protected StateMachine2 _stateMachine = KubernetesCluster.State.getStateMachine(); @@ -1885,26 +1890,54 @@ boolean isClusterVMsInDesiredState(KubernetesCluster kubernetesCluster, VirtualM @Override public boolean start() { + createNetworkOfferingForKubernetes(DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT, false, false); + + createNetworkOfferingForKubernetes(DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NSX_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT, true, false); + + createNetworkOfferingForKubernetes(DEFAULT_NSX_VPC_TIER_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, + DEFAULT_NSX_VPC_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_DISPLAY_TEXT , true, true); + + _gcExecutor.scheduleWithFixedDelay(new KubernetesClusterGarbageCollector(), 300, 300, TimeUnit.SECONDS); + _stateScanner.scheduleWithFixedDelay(new KubernetesClusterStatusScanner(), 300, 30, TimeUnit.SECONDS); + + return true; + } + + private void createNetworkOfferingForKubernetes(String offeringName, String offeringDesc, boolean forNsx, boolean forVpc) { final Map defaultKubernetesServiceNetworkOfferingProviders = new HashMap(); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dhcp, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dns, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Gateway, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.PortForwarding, Network.Provider.VirtualRouter); - defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, Network.Provider.VirtualRouter); + Network.Provider provider = forVpc ? Network.Provider.VPCVirtualRouter : Network.Provider.VirtualRouter; + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dhcp, provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Dns, provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, provider); + if (forVpc) { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.NetworkACL, forNsx ? Network.Provider.Nsx : provider); + } else { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider); + } + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : provider); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.PortForwarding, forNsx ? Network.Provider.Nsx : provider); + + if (!forNsx) { + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Gateway, Network.Provider.VirtualRouter); + defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, Network.Provider.VirtualRouter); + } NetworkOfferingVO defaultKubernetesServiceNetworkOffering = - new NetworkOfferingVO(DEFAULT_NETWORK_OFFERING_FOR_KUBERNETES_SERVICE_NAME, - "Network Offering used for CloudStack Kubernetes service", Networks.TrafficType.Guest, + new NetworkOfferingVO(offeringName, + offeringDesc, Networks.TrafficType.Guest, false, false, null, null, true, NetworkOffering.Availability.Required, null, Network.GuestType.Isolated, true, true, false, false, false, false, false, false, false, true, true, false, - false, true, false, false); + forVpc, true, false, false); + if (forNsx) { + defaultKubernetesServiceNetworkOffering.setNsxMode(NetworkOffering.NsxMode.NATTED.name()); + defaultKubernetesServiceNetworkOffering.setForNsx(true); + } defaultKubernetesServiceNetworkOffering.setSupportsVmAutoScaling(true); defaultKubernetesServiceNetworkOffering.setState(NetworkOffering.State.Enabled); defaultKubernetesServiceNetworkOffering = networkOfferingDao.persistDefaultNetworkOffering(defaultKubernetesServiceNetworkOffering); @@ -1916,11 +1949,6 @@ public boolean start() { networkOfferingServiceMapDao.persist(offService); LOGGER.trace("Added service for the network offering: " + offService); } - - _gcExecutor.scheduleWithFixedDelay(new KubernetesClusterGarbageCollector(), 300, 300, TimeUnit.SECONDS); - _stateScanner.scheduleWithFixedDelay(new KubernetesClusterStatusScanner(), 300, 30, TimeUnit.SECONDS); - - return true; } @Override diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java index 726aadff4d06..dd494f1dc5fb 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java @@ -31,6 +31,8 @@ import javax.inject.Inject; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd; @@ -149,6 +151,8 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu protected VolumeApiService volumeService; @Inject protected VolumeDao volumeDao; + @Inject + protected NetworkOfferingDao networkOfferingDao; protected String kubernetesClusterNodeNamePrefix; @@ -738,12 +742,24 @@ protected void removeVpcTierAclRules(Network network) throws ManagementServerExc protected void setupKubernetesClusterVpcTierRules(IpAddress publicIp, Network network, List clusterVMIds) throws ManagementServerException { // Create ACL rules createVpcTierAclRules(network); - // Add port forwarding for API access - try { - provisionPublicIpPortForwardingRule(publicIp, network, owner, clusterVMIds.get(0), CLUSTER_API_PORT, CLUSTER_API_PORT); - } catch (ResourceUnavailableException | NetworkRuleConflictException e) { - throw new ManagementServerException(String.format("Failed to activate API port forwarding rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + + NetworkOffering offering = networkOfferingDao.findById(network.getNetworkOfferingId()); + if (offering.isConserveMode()) { + // Add load balancing for API access + try { + provisionLoadBalancerRule(publicIp, network, owner, clusterVMIds, CLUSTER_API_PORT); + } catch (InsufficientAddressCapacityException e) { + throw new ManagementServerException(String.format("Failed to activate API load balancing rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + } + } else { + // Add port forwarding for API access + try { + provisionPublicIpPortForwardingRule(publicIp, network, owner, clusterVMIds.get(0), CLUSTER_API_PORT, CLUSTER_API_PORT); + } catch (ResourceUnavailableException | NetworkRuleConflictException e) { + throw new ManagementServerException(String.format("Failed to activate API port forwarding rules for the Kubernetes cluster : %s", kubernetesCluster.getName()), e); + } } + // Add port forwarding rule for SSH access on each node VM try { provisionSshPortForwardingRules(publicIp, network, owner, clusterVMIds); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java index 861fa34de50b..b35bda26c195 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxLoadBalancerRuleCommand.java @@ -23,6 +23,7 @@ public class CreateNsxLoadBalancerRuleCommand extends NsxNetworkCommand { private final String publicPort; + private final String privatePort; private final String algorithm; private final String protocol; List memberList; @@ -31,11 +32,12 @@ public class CreateNsxLoadBalancerRuleCommand extends NsxNetworkCommand { public CreateNsxLoadBalancerRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId, String networkResourceName, boolean isResourceVpc, List memberList, long lbId, String publicPort, - String algorithm, String protocol) { + String privatePort, String algorithm, String protocol) { super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc); this.lbId = lbId; this.memberList = memberList; this.publicPort = publicPort; + this.privatePort = privatePort; this.algorithm = algorithm; this.protocol = protocol; } @@ -49,6 +51,10 @@ public String getPublicPort() { return publicPort; } + public String getPrivatePort() { + return privatePort; + } + public List getMemberList() { return memberList; } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeletedNsxDistributedFirewallRulesCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java similarity index 79% rename from plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeletedNsxDistributedFirewallRulesCommand.java rename to plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java index 11ae52439f3d..ad88f23b3b18 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeletedNsxDistributedFirewallRulesCommand.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/DeleteNsxDistributedFirewallRulesCommand.java @@ -1,4 +1,3 @@ - // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -21,8 +20,8 @@ import java.util.List; -public class DeletedNsxDistributedFirewallRulesCommand extends CreateNsxDistributedFirewallRulesCommand { - public DeletedNsxDistributedFirewallRulesCommand(long domainId, long accountId, long zoneId, Long vpcId, long networkId, List rules) { +public class DeleteNsxDistributedFirewallRulesCommand extends CreateNsxDistributedFirewallRulesCommand { + public DeleteNsxDistributedFirewallRulesCommand(long domainId, long accountId, long zoneId, Long vpcId, long networkId, List rules) { super(domainId, accountId, zoneId, vpcId, networkId, rules); } -} \ No newline at end of file +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java index fccbe3b55d8e..bceee68389c3 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java @@ -42,36 +42,14 @@ public enum NsxRuleAction { private String algorithm; private List memberList; private NsxRuleAction aclAction; - private List cidrList; - private String trafficType; + private List sourceCidrList; + private List destinationCidrList; private Integer icmpCode; + private Integer icmpType; + private String trafficType; private Network.Service service; - public Integer getIcmpCode() { - return icmpCode; - } - - public void setIcmpCode(Integer icmpCode) { - this.icmpCode = icmpCode; - } - - public Integer getIcmpType() { - return icmpType; - } - - public void setIcmpType(Integer icmpType) { - this.icmpType = icmpType; - } - - public Network.Service getService() { - return service; - } - - public void setService(Network.Service service) { - this.service = service; - } - public long getDomainId() { return domainId; } @@ -200,12 +178,44 @@ public void setAclAction(NsxRuleAction aclAction) { this.aclAction = aclAction; } - public List getCidrList() { - return cidrList; + public Network.Service getService() { + return service; } - public void setCidrList(List cidrList) { - this.cidrList = cidrList; + public void setService(Network.Service service) { + this.service = service; + } + + public Integer getIcmpCode() { + return icmpCode; + } + + public void setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + } + + public Integer getIcmpType() { + return icmpType; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public List getSourceCidrList() { + return sourceCidrList; + } + + public void setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + } + + public List getDestinationCidrList() { + return destinationCidrList; + } + + public void setDestinationCidrList(List destinationCidrList) { + this.destinationCidrList = destinationCidrList; } public String getTrafficType() { @@ -234,7 +244,8 @@ public static final class Builder { private String algorithm; private List memberList; private NsxRuleAction aclAction; - private List cidrList; + private List sourceCidrList; + private List destinationidrList; private String trafficType; private Integer icmpType; private Integer icmpCode; @@ -319,16 +330,12 @@ public Builder setMemberList(List memberList) { return this; } + public Builder setAclAction(NsxRuleAction aclAction) { this.aclAction = aclAction; return this; } - public Builder setCidrList(List cidrList) { - this.cidrList = cidrList; - return this; - } - public Builder setTrafficType(String trafficType) { this.trafficType = trafficType; return this; @@ -344,6 +351,16 @@ public Builder setIcmpCode(Integer icmpCode) { return this; } + public Builder setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + return this; + } + + public Builder setDestinationCidrList(List destinationCidrList) { + this.destinationidrList = destinationCidrList; + return this; + } + public Builder setService(Network.Service service) { this.service = service; return this; @@ -367,11 +384,12 @@ public NsxNetworkRule build() { rule.setAlgorithm(this.algorithm); rule.setMemberList(this.memberList); rule.setAclAction(this.aclAction); - rule.setCidrList(this.cidrList); - rule.setTrafficType(this.trafficType); rule.setIcmpType(this.icmpType); rule.setIcmpCode(this.icmpCode); - rule.setService(this.service); + rule.setSourceCidrList(this.sourceCidrList); + rule.setDestinationCidrList(this.destinationidrList); + rule.setTrafficType(this.trafficType); + rule.setService(service); return rule; } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java index 04035a545dfc..35017ed27ba1 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java @@ -43,11 +43,11 @@ import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxDistributedFirewallRulesCommand; import org.apache.cloudstack.agent.api.DeleteNsxLoadBalancerRuleCommand; import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; -import org.apache.cloudstack.agent.api.DeletedNsxDistributedFirewallRulesCommand; import org.apache.cloudstack.service.NsxApiClient; import org.apache.cloudstack.utils.NsxControllerUtils; import org.apache.commons.collections.CollectionUtils; @@ -125,8 +125,8 @@ public Answer executeRequest(Command cmd) { return executeRequest((CreateNsxLoadBalancerRuleCommand) cmd); } else if (cmd instanceof DeleteNsxLoadBalancerRuleCommand) { return executeRequest((DeleteNsxLoadBalancerRuleCommand) cmd); - } else if (cmd instanceof DeletedNsxDistributedFirewallRulesCommand) { - return executeRequest((DeletedNsxDistributedFirewallRulesCommand) cmd); + } else if (cmd instanceof DeleteNsxDistributedFirewallRulesCommand) { + return executeRequest((DeleteNsxDistributedFirewallRulesCommand) cmd); } else if (cmd instanceof CreateNsxDistributedFirewallRulesCommand) { return executeRequest((CreateNsxDistributedFirewallRulesCommand) cmd); } else { @@ -474,7 +474,7 @@ private NsxAnswer executeRequest(CreateNsxDistributedFirewallRulesCommand cmd) { return new NsxAnswer(cmd, true, null); } - private NsxAnswer executeRequest(DeletedNsxDistributedFirewallRulesCommand cmd) { + private NsxAnswer executeRequest(DeleteNsxDistributedFirewallRulesCommand cmd) { String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getVpcId(), cmd.getNetworkId()); List rules = cmd.getRules(); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java index e60a7373aacc..24ef915d1017 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java @@ -81,6 +81,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; @@ -146,6 +147,17 @@ private enum LBSize { XLARGE } + private enum FirewallActions { + ALLOW, + DROP, + REJECT, + JUMP_TO_APPLICATION + } + + private Map actionMap = Map.of( + "Allow", FirewallActions.ALLOW.name(), + "Deny", FirewallActions.DROP.name()); + public enum RouteAdvertisementType { TIER1_STATIC_ROUTES, TIER1_CONNECTED, TIER1_NAT, TIER1_LB_VIP, TIER1_LB_SNAT, TIER1_DNS_FORWARDER_IP, TIER1_IPSEC_LOCAL_ENDPOINT } @@ -358,7 +370,7 @@ public EnforcementPointListResult getEnforcementPoints(String siteId) { public TransportZoneListResult getTransportZones() { try { com.vmware.nsx.TransportZones transportZones = (com.vmware.nsx.TransportZones) nsxService.apply(com.vmware.nsx.TransportZones.class); - return transportZones.list(null, null, true, null, true, null, null, null, TransportType.OVERLAY.name(), null); + return transportZones.list(null, null, true, null, null, null, null, null, TransportType.OVERLAY.name(), null); } catch (Exception e) { throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage())); } @@ -687,6 +699,7 @@ public String getNsxInfraServices(String ruleName, String port, String protocol, } } + private com.vmware.nsx_policy.model.Service getInfraService(String ruleName, String port, String protocol, Integer icmpType, Integer icmpCode) { Services service = (Services) nsxService.apply(Services.class); String serviceName = getServiceName(ruleName, port, protocol, icmpType, icmpCode); @@ -816,7 +829,7 @@ public void createSegmentDistributedFirewall(String segmentName, List nsxRules) { for(NsxNetworkRule rule : nsxRules) { String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId()); - String svcName = getServiceName(ruleId, rule.getPrivatePort(), rule.getProtocol(), rule.getIcmpType(), rule.getIcmpCode()); + String svcName = getServiceName(ruleId, rule.getPrivatePort(), rule.getProtocol(), rule.getIcmpType(), rule.getIcmpCode()); // delete rules Rules rules = (Rules) nsxService.apply(Rules.class); rules.delete(DEFAULT_DOMAIN, segmentName, ruleId); @@ -863,19 +876,21 @@ private List getServicesListForDistributedFirewallRule(NsxNetworkRule ru protected List getGroupsForTraffic(NsxNetworkRule rule, String segmentName, boolean source) { List segmentGroup = List.of(String.format("%s/%s", GROUPS_PATH_PREFIX, segmentName)); - List ruleCidrList = rule.getCidrList(); + List sourceCidrList = rule.getSourceCidrList(); + List destCidrList = rule.getDestinationCidrList(); String trafficType = rule.getTrafficType(); if (trafficType.equalsIgnoreCase("ingress")) { - return source ? ruleCidrList : segmentGroup; + return source ? sourceCidrList : (rule.getService() == Network.Service.NetworkACL ? segmentGroup : destCidrList); } else if (trafficType.equalsIgnoreCase("egress")) { - return source ? segmentGroup : ruleCidrList; - } + return source ? segmentGroup : (rule.getService() == Network.Service.NetworkACL ? sourceCidrList : destCidrList); + } String err = String.format("Unsupported traffic type %s", trafficType); LOGGER.error(err); throw new CloudRuntimeException(err); } + private List listNsxGroups() { try { Groups groups = (Groups) nsxService.apply(Groups.class); @@ -895,5 +910,4 @@ private String getGroupPath(String segmentName) { return matchingGroup.map(Group::getPath).orElse(null); } - } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index 7abf1fa83b47..c398312563db 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -54,6 +54,7 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.FirewallServiceProvider; import com.cloud.network.element.IpDeployer; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkACLServiceProvider; @@ -110,7 +111,7 @@ @Component public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider, StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, NetworkACLServiceProvider, - LoadBalancingServiceProvider, ResourceStateAdapter, Listener { + LoadBalancingServiceProvider, FirewallServiceProvider, ResourceStateAdapter, Listener { @Inject @@ -526,7 +527,7 @@ public boolean applyPFRules(Network network, List rules) thr long zoneId = Objects.nonNull(vpc) ? vpc.getZoneId() : networkVO.getDataCenterId(); String publicPort = getPublicPortRange(rule); - String privatePort = getPrivatePortRange(rule); + String privatePort = getPrivatePFPortRange(rule); NsxNetworkRule networkRule = new NsxNetworkRule.Builder() .setDomainId(domainId) @@ -574,12 +575,18 @@ public Pair getVpcOrNetwork(Long vpcId, long networkId) { } private static String getPublicPortRange(PortForwardingRule rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + private static String getPrivatePFPortRange(PortForwardingRule rule) { return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ? String.valueOf(rule.getDestinationPortStart()) : String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd())); } - private static String getPrivatePortRange(PortForwardingRule rule) { + private static String getPrivatePortRange(FirewallRule rule) { return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? String.valueOf(rule.getSourcePortStart()) : String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); @@ -620,6 +627,7 @@ public boolean applyLBRules(Network network, List rules) thro .setMemberList(lbMembers) .setPublicIp(publicIp.getAddress().addr()) .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) + .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) .setRuleId(loadBalancingRule.getId()) .setProtocol(loadBalancingRule.getProtocol().toUpperCase(Locale.ROOT)) .setAlgorithm(loadBalancingRule.getAlgorithm()) @@ -672,10 +680,9 @@ public boolean applyNetworkACLs(Network network, List List nsxDelNetworkRules = new ArrayList<>(); for (NetworkACLItem rule : rules) { String privatePort = getPrivatePortRangeForACLRule(rule); - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() .setRuleId(rule.getId()) - .setCidrList(transformCidrListValues(rule.getSourceCidrList())) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) .setAclAction(transformActionValue(rule.getAction())) .setTrafficType(rule.getTrafficType().toString()) .setProtocol(rule.getProtocol().toUpperCase()) @@ -701,6 +708,44 @@ public boolean applyNetworkACLs(Network network, List return success && nsxService.addFirewallRules(network, nsxAddNetworkRules); } + @Override + public boolean applyFWRules(Network network, List rules) throws ResourceUnavailableException { + + if (!canHandle(network, Network.Service.Firewall)) { + return false; + } + List nsxAddNetworkRules = new ArrayList<>(); + List nsxDelNetworkRules = new ArrayList<>(); + for (FirewallRule rule : rules) { + NsxNetworkRule networkRule = new NsxNetworkRule.Builder() + .setRuleId(rule.getId()) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? + transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ? + transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY")) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setPrivatePort(getPrivatePortRange(rule)) + .setTrafficType(rule.getTrafficType().toString()) + .setService(Network.Service.Firewall) + .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) + .build(); + if (rule.getState() == FirewallRule.State.Add) { + nsxAddNetworkRules.add(networkRule); + } else if (rule.getState() == FirewallRule.State.Revoke) { + nsxDelNetworkRules.add(networkRule); + } + } + boolean success = true; + if (!nsxDelNetworkRules.isEmpty()) { + success = nsxService.deleteFirewallRules(network, nsxDelNetworkRules); + if (!success) { + LOGGER.warn("Not all firewall rules were successfully deleted"); + } + } + return success && nsxService.addFirewallRules(network, nsxAddNetworkRules); + } + protected NsxNetworkRule.NsxRuleAction transformActionValue(NetworkACLItem.Action action) { if (action == NetworkACLItem.Action.Allow) { return NsxNetworkRule.NsxRuleAction.ALLOW; diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java index d507d9199a71..b38ca453ff4a 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java @@ -28,15 +28,18 @@ import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.NetworkMigrationResponder; +import com.cloud.network.NetworkModel; import com.cloud.network.NetworkProfile; import com.cloud.network.Network; import com.cloud.network.Networks; import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.guru.GuestNetworkGuru; import com.cloud.network.vpc.VpcVO; import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; import com.cloud.user.dao.AccountDao; @@ -50,6 +53,7 @@ import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand; import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand; import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; import org.apache.cloudstack.utils.NsxControllerUtils; import org.apache.cloudstack.utils.NsxHelper; @@ -70,6 +74,10 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr AccountDao accountDao; @Inject DomainDao domainDao; + @Inject + NetworkModel networkModel; + @Inject + NetworkOfferingDao networkOfferingDao; public NsxGuestNetworkGuru() { super(); @@ -80,8 +88,9 @@ public NsxGuestNetworkGuru() { public boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, PhysicalNetwork physicalNetwork) { return networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) - && isMyIsolationMethod(physicalNetwork) && networkOfferingServiceMapDao.isProviderForNetworkOffering( - offering.getId(), Network.Provider.Nsx); + && isMyIsolationMethod(physicalNetwork) && (NetworkOffering.NsxMode.ROUTED.name().equals(offering.getNsxMode()) + || (networkOfferingServiceMapDao.isProviderForNetworkOffering( + offering.getId(), Network.Provider.Nsx) && NetworkOffering.NsxMode.NATTED.name().equals(offering.getNsxMode()))); } @Override @@ -218,6 +227,25 @@ public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfil throw new CloudRuntimeException(msg); } + if (isNull(network.getVpcId())) { + long domainId = domain.getId(); + long accountId = account.getId(); + long dataCenterId = zone.getId(); + long resourceId = network.getId(); + PublicIpAddress ipAddress = networkModel.getSourceNatIpAddressForGuestNetwork(account, network); + String translatedIp = ipAddress.getAddress().addr(); + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, false); + LOGGER.debug(String.format("Creating NSX NAT Rule for Tier1 GW %s for translated IP %s for Isolated network %s", tier1GatewayName, translatedIp, network.getName())); + String natRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, dataCenterId, resourceId, false); + CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, dataCenterId, tier1GatewayName, "SNAT", translatedIp, natRuleId); + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, dataCenterId); + if (!nsxAnswer.getResult()) { + String msg = String.format("Could not create NSX NAT Rule on Tier1 Gateway %s for IP %s for Isolated network %s", tier1GatewayName, translatedIp, network.getName()); + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } + // Create the DHCP relay config for the segment String iPv4Address = nicProfile.getIPv4Address(); List addresses = List.of(iPv4Address); @@ -289,7 +317,9 @@ private void createNsxSegment(NetworkVO networkVO, DataCenter zone) { vpcName = vpc.getName(); } else { LOGGER.debug(String.format("Creating a Tier 1 Gateway for the network %s before creating the NSX segment", networkVO.getName())); - CreateNsxTier1GatewayCommand nsxTier1GatewayCommand = NsxHelper.createNsxTier1GatewayCommand(domain, account, zone, networkVO.getId(), networkVO.getName(), false); + boolean isSourceNatSupported = networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(networkVO.getNetworkOfferingId(), Network.Service.SourceNat); + CreateNsxTier1GatewayCommand nsxTier1GatewayCommand = new CreateNsxTier1GatewayCommand(domain.getId(), account.getId(), zone.getId(), networkVO.getId(), networkVO.getName(), false, isSourceNatSupported); + NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(nsxTier1GatewayCommand, zone.getId()); if (!nsxAnswer.getResult()) { String msg = String.format("Could not create a Tier 1 Gateway for network %s: %s", networkVO.getName(), nsxAnswer.getDetails()); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java index b9fcb53883a8..8de268521615 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java @@ -28,10 +28,13 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; import com.cloud.network.guru.PublicNetworkGuru; +import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; @@ -60,6 +63,10 @@ public class NsxPublicNetworkGuru extends PublicNetworkGuru { private NsxControllerUtils nsxControllerUtils; @Inject private NsxService nsxService; + @Inject + private VpcOfferingDao vpcOfferingDao; + @Inject + private NetworkOfferingDao offeringDao; private static final Logger s_logger = Logger.getLogger(NsxPublicNetworkGuru.class); @@ -139,6 +146,19 @@ public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfil throw new CloudRuntimeException(msg); } + boolean hasNatSupport = false; + if (vpc == null) { + NetworkOffering offering = offeringDao.findById(network.getNetworkOfferingId()); + hasNatSupport = NetworkOffering.NsxMode.NATTED.name().equals(offering.getNsxMode()); + } else { + VpcOffering vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId()); + hasNatSupport = NetworkOffering.NsxMode.NATTED.name().equals(vpcOffering.getNsxMode()); + } + + if (!hasNatSupport) { + return nic; + } + String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, isForVpc); String translatedIp = ipAddress.getAddress().addr(); s_logger.debug(String.format("Creating NSX Nat Rule for Tier1 GW %s for translated IP %s", tier1GatewayName, translatedIp)); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java index 233f7b9e7bc9..481b68f98405 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java @@ -32,11 +32,11 @@ import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand; import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; import org.apache.cloudstack.agent.api.CreateOrUpdateNsxTier1NatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNsxDistributedFirewallRulesCommand; import org.apache.cloudstack.agent.api.DeleteNsxLoadBalancerRuleCommand; import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand; import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand; -import org.apache.cloudstack.agent.api.DeletedNsxDistributedFirewallRulesCommand; import org.apache.cloudstack.resource.NsxNetworkRule; import org.apache.cloudstack.utils.NsxControllerUtils; import org.apache.cloudstack.utils.NsxHelper; @@ -161,7 +161,7 @@ public boolean createLbRule(NsxNetworkRule netRule) { CreateNsxLoadBalancerRuleCommand command = new CreateNsxLoadBalancerRuleCommand(netRule.getDomainId(), netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(), - netRule.getPublicPort(), netRule.getAlgorithm(), netRule.getProtocol()); + netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getAlgorithm(), netRule.getProtocol()); command.setPublicIp(netRule.getPublicIp()); NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId()); return result.getResult(); @@ -184,7 +184,7 @@ public boolean addFirewallRules(Network network, List netRules) } public boolean deleteFirewallRules(Network network, List netRules) { - DeletedNsxDistributedFirewallRulesCommand command = new DeletedNsxDistributedFirewallRulesCommand(network.getDomainId(), + DeleteNsxDistributedFirewallRulesCommand command = new DeleteNsxDistributedFirewallRulesCommand(network.getDomainId(), network.getAccountId(), network.getDataCenterId(), network.getVpcId(), network.getId(), netRules); NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, network.getDataCenterId()); return result.getResult(); diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java index 2408b6f1e43e..603f5fd628d1 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.service; +import com.cloud.network.Network; import com.vmware.nsx_policy.infra.domains.Groups; import com.vmware.nsx_policy.model.Group; import com.vmware.nsx_policy.model.PathExpression; @@ -70,8 +71,9 @@ public void testCreateGroupForSegment() { @Test public void testGetGroupsForTrafficIngress() { NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); - Mockito.when(rule.getCidrList()).thenReturn(List.of("ANY")); + Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); Mockito.when(rule.getTrafficType()).thenReturn("Ingress"); + Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); String segmentName = "segment"; List sourceGroups = client.getGroupsForTraffic(rule, segmentName, true); List destinationGroups = client.getGroupsForTraffic(rule, segmentName, false); @@ -82,8 +84,9 @@ public void testGetGroupsForTrafficIngress() { @Test public void testGetGroupsForTrafficEgress() { NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); - Mockito.when(rule.getCidrList()).thenReturn(List.of("ANY")); + Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); Mockito.when(rule.getTrafficType()).thenReturn("Egress"); + Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); String segmentName = "segment"; List sourceGroups = client.getGroupsForTraffic(rule, segmentName, true); List destinationGroups = client.getGroupsForTraffic(rule, segmentName, false); diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java index c70945aaa5e2..06eef2ae8704 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxGuestNetworkGuruTest.java @@ -128,6 +128,7 @@ public void setUp() { when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); when(offering.getGuestType()).thenReturn(Network.GuestType.Isolated); + when(offering.getNsxMode()).thenReturn(NetworkOffering.NsxMode.NATTED.name()); when(offering.getId()).thenReturn(1L); when(plan.getDataCenterId()).thenReturn(1L); diff --git a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java index 50c5275390ed..a90b40a29087 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java @@ -17,9 +17,12 @@ package com.cloud.api.query.dao; import java.util.List; +import java.util.Objects; import javax.inject.Inject; +import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NsxProviderVO; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ResponseObject.ResponseView; @@ -53,6 +56,8 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase[] getConfigKeys() { return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, VM_SERVICE_OFFERING_MAX_CPU_CORES, - VM_SERVICE_OFFERING_MAX_RAM_SIZE, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS, - ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS + VM_SERVICE_OFFERING_MAX_RAM_SIZE, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS, ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, + ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, AllowNonRFC1918CompliantIPs }; } diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 86000205bec0..325cd42ca3f0 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -491,7 +491,7 @@ Map> getProviderServicesMap(long networkId) { @Override public Map> getProviderToIpList(Network network, Map> ipToServices) { NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - if (!offering.isConserveMode()) { + if (!offering.isConserveMode() && !offering.isForNsx()) { for (PublicIpAddress ip : ipToServices.keySet()) { Set services = new HashSet(); services.addAll(ipToServices.get(ip)); @@ -1617,7 +1617,7 @@ public boolean checkIpForService(IpAddress userIp, Service service, Long network if (!canIpUsedForService(publicIp, service, networkId)) { return false; } - if (!offering.isConserveMode()) { + if (!offering.isConserveMode() && !offering.isForNsx()) { return canIpUsedForNonConserveService(publicIp, service); } return true; diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index b9ef27e04e43..1b634d5b904b 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -3132,7 +3132,7 @@ public Network updateGuestNetwork(final UpdateNetworkCmd cmd) { if (!NetUtils.isValidIp4Cidr(guestVmCidr)) { throw new InvalidParameterValueException("Invalid format of Guest VM CIDR."); } - if (!NetUtils.validateGuestCidr(guestVmCidr)) { + if (!NetUtils.validateGuestCidr(guestVmCidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. "); } 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 1d62805d15f4..4b507c5273df 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -41,6 +41,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.configuration.ConfigurationManager; import com.cloud.network.nsx.NsxService; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.alert.AlertService; @@ -1158,8 +1159,8 @@ public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwner final boolean useDistributedRouter = vpcOff.isSupportsDistributedRouter(); final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff, vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); - vpc.setPublicMtu(publicMtu); - vpc.setDisplay(Boolean.TRUE.equals(displayVpc)); + vpc.setPublicMtu(publicMtu); + vpc.setDisplay(Boolean.TRUE.equals(displayVpc)); return createVpc(displayVpc, vpc); } @@ -1220,7 +1221,7 @@ protected Vpc createVpc(final Boolean displayVpc, final VpcVO vpc) { } // cidr has to be RFC 1918 complient - if (!NetUtils.validateGuestCidr(cidr)) { + if (!NetUtils.validateGuestCidr(cidr, !ConfigurationManager.AllowNonRFC1918CompliantIPs.value())) { throw new InvalidParameterValueException("Guest Cidr " + cidr + " is not RFC1918 compliant"); } @@ -1889,7 +1890,7 @@ public void validateNtwkOffForVpc(final NetworkOffering guestNtwkOff, final List // 2) Only Isolated networks with Source nat service enabled can be // added to vpc - if (!(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) { + if (!guestNtwkOff.isForNsx() && !(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) { throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " are valid for vpc "); @@ -1900,12 +1901,12 @@ public void validateNtwkOffForVpc(final NetworkOffering guestNtwkOff, final List * TODO This should have never been hardcoded like this in the first * place if (guestNtwkOff.getRedundantRouter()) { throw new * InvalidParameterValueException - * ("No redunant router support when network belnogs to VPC"); } + * ("No redundant router support when network belongs to VPC"); } */ - // 4) Conserve mode should be off + // 4) Conserve mode should be off in older versions ( < 4.19.0.0) if (guestNtwkOff.isConserveMode()) { - throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC"); + s_logger.info("Creating a network with conserve mode in VPC"); } // 5) If Netscaler is LB provider make sure it is in dedicated mode diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 638b73cb7226..d54d1bba75dc 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -891,6 +891,7 @@ "label.forgedtransmits": "Forged transmits", "label.format": "Format", "label.fornsx": "NSX", +"label.forvpc": "VPC", "label.free": "Free", "label.french.azerty.keyboard": "French AZERTY keyboard", "label.friday": "Friday", @@ -1409,7 +1410,7 @@ "label.not.suitable": "Not suitable", "label.notifications": "Notifications", "label.nsx": "NSX", -"label.nsx.mode": "NSX Mode", +"label.nsxmode": "NSX Mode", "label.nsx.provider": "NSX Provider", "label.nsx.provider.name": "NSX provider name", "label.nsx.provider.hostname": "NSX provider hostname", @@ -2471,11 +2472,11 @@ "message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...", "message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule", "message.add.nsx.controller": "Add NSX Provider", -"message.add.network": "Add a new Network for zone: ", -"message.add.network.acl.failed": "Adding Network ACL list failed.", -"message.add.network.acl.processing": "Adding Network ACL list...", -"message.add.network.failed": "Adding Network failed.", -"message.add.network.processing": "Adding Network...", +"message.add.network": "Add a new network for zone: ", +"message.add.network.acl.failed": "Adding network ACL list failed.", +"message.add.network.acl.processing": "Adding network ACL list...", +"message.add.network.failed": "Adding network failed.", +"message.add.network.processing": "Adding network...", "message.add.new.gateway.to.vpc": "Please specify the information to add a new gateway to this VPC.", "message.add.physical.network.failed": "Adding physical network failed", "message.add.physical.network.processing": "Adding a new physical network...", diff --git a/ui/src/components/view/ResourceView.vue b/ui/src/components/view/ResourceView.vue index 440b45e640ab..da6e04319c09 100644 --- a/ui/src/components/view/ResourceView.vue +++ b/ui/src/components/view/ResourceView.vue @@ -114,15 +114,7 @@ export default { handler (newItem, oldItem) { if (newItem.id === oldItem.id) return - if (this.resource.associatednetworkid) { - api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => { - if (response && response.listnetworksresponse && response.listnetworksresponse.network) { - this.networkService = response.listnetworksresponse.network[0] - } else { - this.networkService = {} - } - }) - } + this.fetchData() } }, '$route.fullPath': function () { @@ -140,8 +132,20 @@ export default { window.addEventListener('popstate', function () { self.setActiveTab() }) + this.fetchData() }, methods: { + fetchData () { + if (this.resource.associatednetworkid) { + api('listNetworks', { id: this.resource.associatednetworkid, listall: true }).then(response => { + if (response && response.listnetworksresponse && response.listnetworksresponse.network) { + this.networkService = response.listnetworksresponse.network[0] + } else { + this.networkService = {} + } + }) + } + }, onTabChange (key) { this.activeTab = key const query = Object.assign({}, this.$route.query) diff --git a/ui/src/views/network/PublicIpResource.vue b/ui/src/views/network/PublicIpResource.vue index fdbd96a761a0..16ed1ecbc54a 100644 --- a/ui/src/views/network/PublicIpResource.vue +++ b/ui/src/views/network/PublicIpResource.vue @@ -70,6 +70,16 @@ export default { defaultTabs: [{ name: 'details', component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue'))) + }, + { + name: 'events', + resourceType: 'IpAddress', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/EventsTab.vue'))), + show: () => { return 'listEvents' in this.$store.getters.apis } + }, + { + name: 'comments', + component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue'))) }], activeTab: '' } @@ -134,19 +144,25 @@ export default { } if (this.resource && this.resource.vpcid) { // VPC IPs don't have firewall - let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall') + const tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall') + + const network = await this.fetchNetwork() + if (network && network.networkofferingconservemode) { + this.tabs = tabs + return + } this.portFWRuleCount = await this.fetchPortFWRule() this.loadBalancerRuleCount = await this.fetchLoadBalancerRule() // VPC IPs with PF only have PF if (this.portFWRuleCount > 0) { - tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'portforwarding')) + tabs = tabs.filter(tab => tab.name !== 'loadbalancing') } // VPC IPs with LB rules only have LB if (this.loadBalancerRuleCount > 0) { - tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'loadbalancing')) + tabs = tabs.filter(tab => tab.name !== 'portforwarding') } this.tabs = tabs return @@ -171,6 +187,20 @@ export default { fetchAction () { this.actions = this.$route.meta.actions || [] }, + fetchNetwork () { + return new Promise((resolve, reject) => { + api('listNetworks', { + listAll: true, + projectid: this.resource.projectid, + id: this.resource.associatednetworkid + }).then(json => { + const network = json.listnetworksresponse?.network?.[0] || null + resolve(network) + }).catch(e => { + reject(e) + }) + }) + }, fetchPortFWRule () { return new Promise((resolve, reject) => { api('listPortForwardingRules', { @@ -202,6 +232,7 @@ export default { }) }, changeResource (resource) { + console.log(resource) this.resource = resource }, toggleLoading () { diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 5af0c0001654..85f88f5b4705 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -131,7 +131,7 @@ { + self.supportedSvcs = self.supportedServices self.supportedServices = supportedServices self.supportedServiceLoading = false }, 50) } else { + supportedServices = this.supportedSvcs supportedServices = supportedServices.filter(svc => { return Object.keys(this.nsxSupportedServicesMap).includes(svc.name) }) - supportedServices.forEach(function (svc, index) { - svc.provider = [self.nsxSupportedServicesMap[svc.name]] - supportedServices[index] = svc - }) + self.supportedSvcs = self.supportedServices self.supportedServices = supportedServices self.supportedServiceLoading = false } @@ -863,19 +863,29 @@ export default { Dhcp: this.forVpc ? this.VPCVR : this.VR, Dns: this.forVpc ? this.VPCVR : this.VR, UserData: this.forVpc ? this.VPCVR : this.VR, - SourceNat: this.NSX + SourceNat: this.NSX, + StaticNat: this.NSX, + PortForwarding: this.NSX, + Lb: this.NSX, + ...(forVpc && { NetworkACL: this.NSX }), + ...(!forVpc && { Firewall: this.NSX }) } } this.updateSupportedServices() }, - async handleForNsxChange (forNsx) { + handleForNsxChange (forNsx) { this.forNsx = forNsx this.showMode = forNsx this.nsxSupportedServicesMap = { Dhcp: this.forVpc ? this.VPCVR : this.VR, Dns: this.forVpc ? this.VPCVR : this.VR, UserData: this.forVpc ? this.VPCVR : this.VR, - SourceNat: this.NSX + SourceNat: this.NSX, + StaticNat: this.NSX, + PortForwarding: this.NSX, + Lb: this.NSX, + ...(this.forVpc && { NetworkACL: this.NSX }), + ...(!this.forVpc && { Firewall: this.NSX }) } this.fetchSupportedServiceData() }, diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java b/utils/src/main/java/com/cloud/utils/net/NetUtils.java index 018912a2140d..7c94691170b4 100644 --- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java +++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java @@ -1117,7 +1117,7 @@ public static boolean isSameIpRange(final String cidrA, final String cidrB) { return false; } - public static boolean validateGuestCidr(final String cidr) { + public static boolean validateGuestCidr(final String cidr, boolean checkCompliance) { // RFC 1918 - The Internet Assigned Numbers Authority (IANA) has reserved the // following three blocks of the IP address space for private internets: // 10.0.0.0 - 10.255.255.255 (10/8 prefix) @@ -1134,6 +1134,9 @@ public static boolean validateGuestCidr(final String cidr) { return false; } + if (!checkCompliance) { + return true; + } for (String block: allowedNetBlocks) { if (isNetworkAWithinNetworkB(cidr, block)) { return true; @@ -1236,9 +1239,9 @@ public static boolean isValidCidrList(final String cidrList) { return true; } - public static boolean validateGuestCidrList(final String guestCidrList) { + public static boolean validateGuestCidrList(final String guestCidrList, boolean checkCompliance) { for (final String guestCidr : guestCidrList.split(",")) { - if (!validateGuestCidr(guestCidr)) { + if (!validateGuestCidr(guestCidr, checkCompliance)) { return false; } } diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java index defb440c2a51..a54f413f61f7 100644 --- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java @@ -354,10 +354,10 @@ public void testValidateGuestCidr() throws Exception { final String[] invalidCidrs = {"172.33.1.0/16", "100.128.1.0/10"}; for (String cidr: validCidrs) { - assertTrue(NetUtils.validateGuestCidr(cidr)); + assertTrue(NetUtils.validateGuestCidr(cidr, true)); } for (String cidr: invalidCidrs) { - assertFalse(NetUtils.validateGuestCidr(cidr)); + assertFalse(NetUtils.validateGuestCidr(cidr, true)); } }