This is an automated email from the ASF dual-hosted git repository. pearl11594 pushed a commit to branch netris-integration-upstream in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 1c2c7e3de67b0d74a6f25636389280e5e47424ce Author: Pearl Dsilva <pearl1...@gmail.com> AuthorDate: Tue Dec 3 19:35:38 2024 -0500 Phase4 - Add support for Source NAT, Static NAT and Port Forwarding (#19) * Run moodifyvxlan script if broadcast domain type is Netris * Add Netris NAT offerings * Add support to add Source nat rules for Natted offering * fix api params while creating Netris source NAT rule * Add support to add and delete source nat rule on netris * Add support to create /32 NAT subnet * Add support to add and delete Static NAT rules in Netris (#23) * Add support to add and delete Static NAT rules in Netris * fix static nat creation on netris & removal of subnet on deletion of static nat rule * remove nat subnet after deltion of the static nat rule * add check to see if subnet already exists and add license header * Add port forwarding rules as DNAT rules in Netris (#24) * Add port forwarding rules as DNAT rules in Netris * Fixes * Allow removing DNAT rules * Fixes * Fix subnet search * Fix update SNAT only for SNAT rules * Address comments * Fix * Fix netris pom xml * Fix SNAT rule creation * Fix IP and port placements (#27) * Fix IP and port placements * fix dnat to IP for PF rules * change dnatport --------- Co-authored-by: Nicolas Vazquez <nicovazque...@gmail.com> --- .../com/cloud/network/SDNProviderNetworkRule.java | 204 +++++++++++ .../element/PortForwardingServiceProvider.java | 28 ++ .../com/cloud/network/netris/NetrisService.java | 8 + .../java/com/cloud/network/vpc/VpcOffering.java | 1 + .../java/com/cloud/offering/NetworkOffering.java | 1 + .../engine/orchestration/NetworkOrchestrator.java | 20 +- .../contrail/management/ContrailManagerImpl.java | 4 +- plugins/network-elements/netris/pom.xml | 2 +- .../agent/api/CreateOrUpdateNetrisNatCommand.java | 149 ++++++++ .../agent/api/DeleteNetrisNatRuleCommand.java | 72 ++++ .../apache/cloudstack/agent/api/NetrisCommand.java | 12 +- .../cloudstack/resource/NetrisNetworkRule.java | 18 +- .../apache/cloudstack/resource/NetrisResource.java | 36 ++ .../resource/NetrisResourceObjectUtils.java | 16 +- .../apache/cloudstack/service/NetrisApiClient.java | 16 + .../cloudstack/service/NetrisApiClientImpl.java | 395 ++++++++++++++++++++- .../apache/cloudstack/service/NetrisElement.java | 196 +++++++++- .../cloudstack/service/NetrisGuestNetworkGuru.java | 18 +- .../service/NetrisPublicNetworkGuru.java | 9 + .../cloudstack/service/NetrisServiceImpl.java | 139 ++++++++ .../resource/NetrisResourceObjectUtilsTest.java | 12 + .../apache/cloudstack/resource/NsxNetworkRule.java | 354 +----------------- .../org/apache/cloudstack/service/NsxElement.java | 158 ++++----- .../apache/cloudstack/service/NsxElementTest.java | 42 +-- .../com/cloud/network/SDNProviderOpObject.java | 8 +- .../java/com/cloud/network/vpc/VpcManagerImpl.java | 18 + .../com/cloud/server/ConfigurationServerImpl.java | 4 + 27 files changed, 1415 insertions(+), 525 deletions(-) diff --git a/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java new file mode 100644 index 00000000000..15238f85bb6 --- /dev/null +++ b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java @@ -0,0 +1,204 @@ +// 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 +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network; + +import java.util.List; + +public class SDNProviderNetworkRule { + + private long domainId; + private long accountId; + private long zoneId; + private Long networkResourceId; + private String networkResourceName; + private boolean isVpcResource; + private long vmId; + private long ruleId; + private String publicIp; + private String vmIp; + private String publicPort; + private String privatePort; + private String protocol; + private String algorithm; + private List<String> sourceCidrList; + private List<String> destinationCidrList; + private Integer icmpCode; + + private Integer icmpType; + private String trafficType; + private Network.Service service; + + public long getDomainId() { + return domainId; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public long getAccountId() { + return accountId; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public void setNetworkResourceId(Long networkResourceId) { + this.networkResourceId = networkResourceId; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public void setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + } + + public boolean isVpcResource() { + return isVpcResource; + } + + public void setVpcResource(boolean vpcResource) { + isVpcResource = vpcResource; + } + + public long getVmId() { + return vmId; + } + + public void setVmId(long vmId) { + this.vmId = vmId; + } + + public long getRuleId() { + return ruleId; + } + + public void setRuleId(long ruleId) { + this.ruleId = ruleId; + } + + public String getPublicIp() { + return publicIp; + } + + public void setPublicIp(String publicIp) { + this.publicIp = publicIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + public String getPublicPort() { + return publicPort; + } + + public void setPublicPort(String publicPort) { + this.publicPort = publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public void setPrivatePort(String privatePort) { + this.privatePort = privatePort; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public String getAlgorithm() { + return algorithm; + } + + public Network.Service getService() { + return service; + } + + 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<String> getSourceCidrList() { + return sourceCidrList; + } + + public void setSourceCidrList(List<String> sourceCidrList) { + this.sourceCidrList = sourceCidrList; + } + + public List<String> getDestinationCidrList() { + return destinationCidrList; + } + + public void setDestinationCidrList(List<String> destinationCidrList) { + this.destinationCidrList = destinationCidrList; + } + + public String getTrafficType() { + return trafficType; + } + + public void setTrafficType(String trafficType) { + this.trafficType = trafficType; + } +} diff --git a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java index e99bc2fd416..8dcc8b6d0a4 100644 --- a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java @@ -17,12 +17,40 @@ package com.cloud.network.element; import java.util.List; +import java.util.Objects; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.vpc.NetworkACLItem; public interface PortForwardingServiceProvider extends NetworkElement, IpDeployingRequester { + + 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())); + } + + static String getPrivatePFPortRange(PortForwardingRule rule) { + return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ? + String.valueOf(rule.getDestinationPortStart()) : + String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd())); + } + + 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())); + } + + static String getPrivatePortRangeForACLRule(NetworkACLItem rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + /** * Apply rules * @param network diff --git a/api/src/main/java/com/cloud/network/netris/NetrisService.java b/api/src/main/java/com/cloud/network/netris/NetrisService.java index f6203874c2d..ea2f73383e0 100644 --- a/api/src/main/java/com/cloud/network/netris/NetrisService.java +++ b/api/src/main/java/com/cloud/network/netris/NetrisService.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.network.netris; +import com.cloud.network.IpAddress; +import com.cloud.network.SDNProviderNetworkRule; import com.cloud.network.vpc.Vpc; public interface NetrisService { @@ -23,4 +25,10 @@ public interface NetrisService { boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc); boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr); boolean deleteVnetResource(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr); + boolean createSnatRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, String vpcCidr, String sourceNatIp); + boolean createPortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule); + boolean deletePortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule); + boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address); + boolean createStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String vpcCidr, String staticNatIp, String vmIp); + boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp); } diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java index 77d52991130..17f49bb3652 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -33,6 +33,7 @@ public interface VpcOffering extends InternalIdentity, Identity { public static final String DEFAULT_VPC_NAT_NSX_OFFERING_NAME = "VPC offering with NSX - NAT Mode"; public static final String DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME = "VPC offering with NSX - Route Mode"; public static final String DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME = "VPC offering with Netris - Route Mode"; + public static final String DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME = "VPC offering with Netris - NAT Mode"; /** * diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 4df01bd8986..5000a4f8c62 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -65,6 +65,7 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, public static final String DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB = "DefaultNATNSXNetworkOfferingForVpcWithInternalLB"; public static final String DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC = "DefaultRoutedNSXNetworkOfferingForVpc"; public static final String DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC = "DefaultRoutedNetrisNetworkOfferingForVpc"; + public static final String DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC = "DefaultNATNetrisNetworkOfferingForVpc"; public static final String DEFAULT_NAT_NSX_OFFERING = "DefaultNATNSXNetworkOffering"; public static final String DEFAULT_ROUTED_NSX_OFFERING = "DefaultRoutedNSXNetworkOffering"; public final static String QuickCloudNoServices = "QuickCloudNoServices"; 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 c80c4769573..47aab7ebbf0 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 @@ -561,27 +561,27 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap<Network.Service, Set<Network.Provider>>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + false, null, false, null, true, false, false, false, false,null, null, null, true, null, null, false); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + null, true, false, null, false, null, true, false, false, false, false,null, null, null, true, null, null, false); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, false, false, null,null, null, true, null, null, false); + null, true, false, false, false, false,null,null, null, true, null, null, false); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE, "Offering for Tungsten Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultTungstenSharedSGEnabledNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, true, false, null, null,null, true, null, null, false); + null, true, false, null, false, null, true, false, true, false, false,null, null,null, true, null, null, false); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -591,14 +591,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, false, false, null, null,null, true, null, null, false); + true, false, false, false, false,null, null,null, true, null, null, false); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null, null, false); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null,true, null, null, false); } //#6 - default vpc offering with no LB service @@ -607,14 +607,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null, null, false); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null,true, null, null, false); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + true, null, true, false, null, false, null, true, false, false, false, false,null, null, null, true, null, null, false); } //#8 - network offering with internal lb service @@ -636,7 +636,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, true, null, null, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, true, null, null, false); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -667,7 +667,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false,false, null, null, null, true, null, null, false); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 6da2e216ff8..622886e6d83 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -217,7 +217,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, null, null, null, true, null, null, false); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, false,null, null, null, true, null, null, false); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -252,7 +252,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, null, null, null, true, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, false,null, null, null, true, null, null, false); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } diff --git a/plugins/network-elements/netris/pom.xml b/plugins/network-elements/netris/pom.xml index 21aeadec935..a50013ee351 100644 --- a/plugins/network-elements/netris/pom.xml +++ b/plugins/network-elements/netris/pom.xml @@ -26,7 +26,7 @@ <parent> <groupId>org.apache.cloudstack</groupId> <artifactId>cloudstack-plugins</artifactId> - <version>4.20.0.0-SNAPSHOT</version> + <version>4.20.0.0</version> <relativePath>../../pom.xml</relativePath> </parent> <dependencies> diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java new file mode 100644 index 00000000000..5e0546a8256 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java @@ -0,0 +1,149 @@ +// 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 +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.agent.api; + +public class CreateOrUpdateNetrisNatCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String vpcCidr; + private String natRuleName; + private String natIp; + private String natRuleType; + + // Parameters for DNAT + private String protocol; + private String sourceAddress; + private String sourcePort; + private String destinationAddress; + private String destinationPort; + private String state; + + // Parameters for SNAT (Static NAT) + private String vmIp; + + + public CreateOrUpdateNetrisNatCommand(long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean isVpc, String vpcCidr) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + this.vpcCidr = vpcCidr; + } + + public String getVpcName() { + return vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getNatIp() { + return natIp; + } + + public void setNatRuleName(String natRuleName) { + this.natRuleName = natRuleName; + } + + public String getNatRuleName() { + return natRuleName; + } + + public String getVpcCidr() { + return vpcCidr; + } + + public void setNatIp(String natIp) { + this.natIp = natIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + public String getNatRuleType() { + return natRuleType; + } + + public void setNatRuleType(String natRuleType) { + this.natRuleType = natRuleType; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public void setVpcCidr(String vpcCidr) { + this.vpcCidr = vpcCidr; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getSourceAddress() { + return sourceAddress; + } + + public void setSourceAddress(String sourceAddress) { + this.sourceAddress = sourceAddress; + } + + public String getSourcePort() { + return sourcePort; + } + + public void setSourcePort(String sourcePort) { + this.sourcePort = sourcePort; + } + + public String getDestinationAddress() { + return destinationAddress; + } + + public void setDestinationAddress(String destinationAddress) { + this.destinationAddress = destinationAddress; + } + + public String getDestinationPort() { + return destinationPort; + } + + public void setDestinationPort(String destinationPort) { + this.destinationPort = destinationPort; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java new file mode 100644 index 00000000000..b01b2f45192 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java @@ -0,0 +1,72 @@ +// 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 +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.agent.api; + +public class DeleteNetrisNatRuleCommand extends NetrisCommand { + + private String vpcName; + private Long vpcId; + private String natRuleType; + private String natRuleName; + private String natIp; + + public DeleteNetrisNatRuleCommand(long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean isVpc) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public String getNatRuleType() { + return natRuleType; + } + + public void setNatRuleType(String natRuleType) { + this.natRuleType = natRuleType; + } + + public String getNatRuleName() { + return natRuleName; + } + + public void setNatRuleName(String natRuleName) { + this.natRuleName = natRuleName; + } + + public String getNatIp() { + return natIp; + } + + public void setNatIp(String natIp) { + this.natIp = natIp; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java index 463001452c1..ceb33ea24ed 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java @@ -22,11 +22,11 @@ public class NetrisCommand extends Command { private final long zoneId; private final Long accountId; private final Long domainId; - private final String name; - private final long id; + private String name; + private final Long id; private final boolean isVpc; - public NetrisCommand(long zoneId, Long accountId, Long domainId, String name, long id, boolean isVpc) { + public NetrisCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc) { this.zoneId = zoneId; this.accountId = accountId; this.domainId = domainId; @@ -40,7 +40,11 @@ public class NetrisCommand extends Command { return name; } - public long getId() { + public void setName(String name) { + this.name = name; + } + + public Long getId() { return id; } diff --git a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java similarity index 59% copy from api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java copy to plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java index e99bc2fd416..2f4eadd443d 100644 --- a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java @@ -14,21 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.element; +package org.apache.cloudstack.resource; -import java.util.List; +import com.cloud.network.SDNProviderNetworkRule; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.Network; -import com.cloud.network.rules.PortForwardingRule; - -public interface PortForwardingServiceProvider extends NetworkElement, IpDeployingRequester { - /** - * Apply rules - * @param network - * @param rules - * @return - * @throws ResourceUnavailableException - */ - boolean applyPFRules(Network network, List<PortForwardingRule> rules) throws ResourceUnavailableException; +public class NetrisNetworkRule extends SDNProviderNetworkRule { } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java index dc922aef963..6f5e01b6392 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java @@ -30,6 +30,8 @@ import com.cloud.resource.ServerResource; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.NetrisAnswer; @@ -97,6 +99,10 @@ public class NetrisResource implements ServerResource { return executeRequest((DeleteNetrisVnetCommand) cmd); } else if (cmd instanceof SetupNetrisPublicRangeCommand) { return executeRequest((SetupNetrisPublicRangeCommand) cmd); + } else if (cmd instanceof DeleteNetrisNatRuleCommand) { + return executeRequest((DeleteNetrisNatRuleCommand) cmd); + } else if (cmd instanceof CreateOrUpdateNetrisNatCommand) { + return executeRequest((CreateOrUpdateNetrisNatCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -261,6 +267,36 @@ public class NetrisResource implements ServerResource { return new NetrisAnswer(cmd, true, "OK"); } + private Answer executeRequest(CreateOrUpdateNetrisNatCommand cmd) { + String natRuleType = cmd.getNatRuleType(); + if ("SNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createOrUpdateSNATRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create SNAT rule on Netris for network %s", cmd.getName())); + } + } else if ("DNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createOrUpdateDNATRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create DNAT rule on Netris for network %s", cmd.getName())); + } + } else if ("STATICNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createStaticNatRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create SNAT rule on Netris for network %s", cmd.getName())); + } + } + + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(DeleteNetrisNatRuleCommand cmd) { + boolean result = netrisApiClient.deleteNatRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris NAT rule: %s deletion failed", cmd.getNatRuleName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + @Override public boolean start() { return true; diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java index 5b19aa43199..fd6851696c8 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java @@ -22,14 +22,14 @@ import org.apache.commons.lang3.ArrayUtils; public class NetrisResourceObjectUtils { public enum NetrisObjectType { - VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET + VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET, SNAT, STATICNAT, DNAT } public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisObjectType netrisObjectType, String... suffixes) { long zoneId = cmd.getZoneId(); Long accountId = cmd.getAccountId(); Long domainId = cmd.getDomainId(); - long objectId = cmd.getId(); + Long objectId = cmd.getId(); String objectName = cmd.getName(); boolean isVpc = cmd.isVpc(); boolean isZoneLevel = accountId == null && domainId == null; @@ -60,6 +60,18 @@ public class NetrisResourceObjectUtils { stringBuilder.append(String.format("-N%s", objectId)); } break; + case SNAT: + stringBuilder.append(String.format("%s%s-%s", prefix, suffixes[0], "SNAT")); + suffixes = new String[0]; + break; + case STATICNAT: + stringBuilder.append(String.format("%s%s-%s", prefix, suffixes[0], "STATICNAT")); + suffixes = new String[0]; + break; + case DNAT: + stringBuilder.append(String.format("%s%s-%s", prefix, suffixes[0], "DNAT")); + suffixes = ArrayUtils.subarray(suffixes, 1, suffixes.length); + break; case VNET: break; default: diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java index 0a00583df52..cf214bb4664 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java @@ -22,6 +22,8 @@ import io.netris.model.VPCListing; import io.netris.model.response.TenantResponse; import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; @@ -48,8 +50,18 @@ public interface NetrisApiClient { */ boolean deleteVpc(DeleteNetrisVpcCommand cmd); + /** + * Creation of a VPC network tier creates the following Netris resources: + * - Creates a Netris IPAM Subnet for the specified network tier's CIDR + * - Creates a Netris vNet + */ boolean createVnet(CreateNetrisVnetCommand cmd); + /** + * Deletion of a VPC network tier deletes the following Netris resources: + * - Deletes the Netris IPAM Subnet for the specified network tier's CIDR + * - Deletes the Netris vNet + */ boolean deleteVnet(DeleteNetrisVnetCommand cmd); /** @@ -58,4 +70,8 @@ public interface NetrisApiClient { * - Check the IPAM subnet for NAT purpose for the range start-end. In case it doesn't exist, create it */ boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd); + boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd); + boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd); + boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd); + boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd); } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java index 2bf9b172608..51de34552a5 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java @@ -25,6 +25,7 @@ import io.netris.api.v1.AuthenticationApi; import io.netris.api.v1.SitesApi; import io.netris.api.v1.TenantsApi; import io.netris.api.v2.IpamApi; +import io.netris.api.v2.NatApi; import io.netris.api.v2.VNetApi; import io.netris.api.v2.VpcApi; import io.netris.model.AllocationBody; @@ -32,6 +33,8 @@ import io.netris.model.AllocationBodyVpc; import io.netris.model.FilterBySites; import io.netris.model.FilterByVpc; import io.netris.model.GetSiteBody; +import io.netris.model.InlineResponse20015; +import io.netris.model.InlineResponse20016; import io.netris.model.InlineResponse2004; import io.netris.model.InlineResponse2004Data; import io.netris.model.IpTree; @@ -39,6 +42,12 @@ import io.netris.model.IpTreeAllocation; import io.netris.model.IpTreeAllocationTenant; import io.netris.model.IpTreeSubnet; import io.netris.model.IpTreeSubnetSites; +import io.netris.model.NatBodySiteSite; +import io.netris.model.NatBodyVpcVpc; +import io.netris.model.NatGetBody; +import io.netris.model.NatPostBody; +import io.netris.model.NatPutBody; +import io.netris.model.NatResponseGetOk; import io.netris.model.SitesResponseOK; import io.netris.model.SubnetBody; import io.netris.model.SubnetResBody; @@ -62,13 +71,16 @@ import io.netris.model.VnetsBody; import io.netris.model.response.AuthResponse; import io.netris.model.response.TenantResponse; import io.netris.model.response.TenantsResponse; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; import org.apache.cloudstack.resource.NetrisResourceObjectUtils; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -245,8 +257,50 @@ public class NetrisApiClientImpl implements NetrisApiClient { return createdIpamAllocation != null; } + @Override + public boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd) { + try { + String suffix = getNetrisVpcNameSuffix(cmd.getVpcId(), cmd.getVpcName(), cmd.getId(), cmd.getName(), cmd.isVpc()); + String vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return false; + } + String natRuleName = cmd.getNatRuleName(); + NatGetBody existingNatRule = netrisNatRuleExists(natRuleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (ruleExists) { + deleteNatRule(natRuleName, existingNatRule.getId(), vpcResource.getName()); + if (cmd.getNatRuleType().equals("STATICNAT")) { + deleteNatSubnet(vpcResource.getId(), cmd.getNatIp()); + } + } + } catch (Exception e) { + throw new CloudRuntimeException("Error deleting Netris NAT Rule", e); + } + return true; + } + + private void deleteNatSubnet(Integer netrisVpcId, String natIp) { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + String netrisSubnetName = natIp + "/32"; + deleteSubnetInternal(vpcFilter, null, netrisSubnetName); + } + + public void deleteNatRule(String natRuleName, Integer snatRuleId, String netrisVpcName) { + logger.debug("Deleting NAT rule on Netris: {} for VPC {}", natRuleName, netrisVpcName); + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + natApi.apiV2NatIdDelete(snatRuleId); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to delete NAT rule: %s for VPC: %s", natRuleName, netrisVpcName), e); + } + } + private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String vpcCidr) { - logger.debug(String.format("Deleting Netris VPC IPAM Allocation %s for VPC %s", vpcCidr, vpcResource.getName())); + logger.debug("Deleting Netris VPC IPAM Allocation {} for VPC {}", vpcCidr, vpcResource.getName()); try { VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); VPCResponseResourceOK vpcResourcesResponse = vpcApi.apiV2VpcVpcIdResourcesGet(vpcResource.getId()); @@ -300,12 +354,20 @@ public class NetrisApiClientImpl implements NetrisApiClient { @Override public boolean deleteVpc(DeleteNetrisVpcCommand cmd) { + String suffix = String.valueOf(cmd.getId()); String vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); VPCListing vpcResource = getVpcByNameAndTenant(vpcName); if (vpcResource == null) { - logger.error(String.format("Could not find the Netris VPC resource with name %s and tenant ID %s", vpcName, tenantId)); + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); return false; } + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix); + NatGetBody existingNatRule = netrisNatRuleExists(snatRuleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (ruleExists) { + deleteNatRule(snatRuleName, existingNatRule.getId(), vpcResource.getName()); + } + String vpcCidr = cmd.getCidr(); deleteVpcIpamAllocationInternal(vpcResource, vpcCidr); VPCResponseObjectOK response = deleteVpcInternal(vpcResource); @@ -424,7 +486,9 @@ public class NetrisApiClientImpl implements NetrisApiClient { filterByVpc.add(vpc.getId()); SubnetResBody subnetResBody = ipamApi.apiV2IpamSubnetsGet(filterByVpc); List<IpTreeSubnet> exactSubnetList = subnetResBody.getData().stream() - .filter(x -> x.getAllocationID().equals(ipamAllocationId) && x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose) + .filter(x -> ipamAllocationId != null ? + x.getAllocationID().equals(ipamAllocationId) && x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose : + x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose) .collect(Collectors.toList()); return CollectionUtils.isEmpty(exactSubnetList) ? null : exactSubnetList.get(0); } @@ -460,6 +524,288 @@ public class NetrisApiClientImpl implements NetrisApiClient { return true; } + private boolean createOrUpdateNatRuleInternal(CreateOrUpdateNetrisNatCommand cmd) { + String ruleName = cmd.getNatRuleName(); + long vpcId = cmd.getVpcId(); + Long networkId = cmd.getId(); + String networkName = cmd.getName(); + String vpcName = cmd.getVpcName(); + String vpcCidr = cmd.getVpcCidr(); + boolean isVpc = cmd.isVpc(); + NatPostBody.ActionEnum action = getNatActionFromRuleType(cmd.getNatRuleType()); + NatPostBody.ProtocolEnum protocol = getProtocolFromString(cmd.getProtocol()); + NatPostBody.StateEnum state = getStateFromString(cmd.getState()); + + String vNetName = isVpc ? + String.format("V%s-N%s-%s", vpcId, networkId, networkName) : + String.format("N%s-%s", networkId, networkName); + String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + + String targetIpSubnet = null; + if (NatPostBody.ActionEnum.SNAT == action) { + targetIpSubnet = cmd.getNatIp() + "/32"; + } else if (NatPostBody.ActionEnum.DNAT == action) { + targetIpSubnet = cmd.getDestinationAddress() + "/32"; + } + + if (StringUtils.isNotBlank(targetIpSubnet) && existsDestinationSubnet(targetIpSubnet)) { + logger.debug(String.format("Creating subnet with NAT purpose for %s", targetIpSubnet)); + createNatSubnet(targetIpSubnet, vpcResource.getId()); + } + + NatGetBody existingNatRule = netrisNatRuleExists(ruleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (!ruleExists) { + String destinationAddress = action == NatPostBody.ActionEnum.SNAT ? "0.0.0.0/0" : cmd.getDestinationAddress() + "/32"; + String destinationPort = cmd.getDestinationPort(); + String sourceAddress = action == NatPostBody.ActionEnum.SNAT ? vpcCidr : "0.0.0.0/0"; + String sourcePort = "1-65535"; + String snatToIp = action == NatPostBody.ActionEnum.SNAT ? targetIpSubnet : null; + String dnatToIp = action == NatPostBody.ActionEnum.DNAT ? cmd.getSourceAddress() + "/32" : null; + String dnatToPort = action == NatPostBody.ActionEnum.DNAT ? cmd.getSourcePort() : null; + return createNatRuleInternal(ruleName, action, protocol, state, destinationAddress, destinationPort, + sourceAddress, sourcePort, snatToIp, dnatToIp, dnatToPort, netrisVpcName, networkName, vNetName); + } else if (NatPostBody.ActionEnum.SNAT == action) { + return updateSnatRuleInternal(ruleName, targetIpSubnet, netrisVpcName, networkName, vNetName, existingNatRule.getId(), vpcCidr); + } + return true; + } + + private NatPostBody.StateEnum getStateFromString(String state) { + return NatPostBody.StateEnum.fromValue(state); + } + + private NatPostBody.ActionEnum getNatActionFromRuleType(String natRuleType) { + return NatPostBody.ActionEnum.fromValue(natRuleType); + } + + @Override + public boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd) { + return createOrUpdateNatRuleInternal(cmd); + } + + private boolean existsDestinationSubnet(String destinationSubnet) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(getSystemVpc().getId()); + List<IpTreeSubnet> targetSubnetList = getSubnet(vpcFilter, destinationSubnet); + return targetSubnetList != null; + } catch (ApiException e) { + logAndThrowException(String.format("Error checking if subnet %s exists: %s", destinationSubnet, e.getMessage()), e); + return false; + } + } + + @Override + public boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd) { + String staticNatRuleName = cmd.getNatRuleName(); + String natIP = cmd.getNatIp() + "/32"; + String vmIp = cmd.getVmIp() + "/32"; + String vpcName = cmd.getVpcName(); + String vpcCidr = cmd.getVpcCidr(); + Long vpcId = cmd.getVpcId(); + Long networkId = cmd.getId(); + String networkName = cmd.getName(); + boolean isVpc = cmd.isVpc(); + + try { + String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + // Create a /32 subnet for the DNAT IP + createNatSubnet(natIP, vpcResource.getId()); + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + NatPostBody natBody = new NatPostBody(); + natBody.setAction(NatPostBody.ActionEnum.DNAT); + natBody.setDestinationAddress(natIP); + natBody.setName(staticNatRuleName); + natBody.setProtocol(NatPostBody.ProtocolEnum.ALL); + natBody.setState(NatPostBody.StateEnum.ENABLED); + natBody.setComment(String.format("Static NAT rule for %s", netrisVpcName)); + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + natBody.setSourceAddress("0.0.0.0/0"); + natBody.setDnatToIP(vmIp); + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + + InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody); + if (natResponse == null || !natResponse.isIsSuccess()) { + String reason = natResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris static NAT (DNAT) rule creation failed for netris VPC - {}: {}", netrisVpcName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create Static NAT (DNAT) rule for network : %s", Objects.nonNull(vpcName) ? vpcName : networkName), e); + } + return true; + } + + private void createNatSubnet(String natIp, Integer netrisVpcId) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + String netrisSubnetName = natIp; + List<IpTreeSubnet> matchedSubnets = getSubnet(vpcFilter, netrisSubnetName); + if (matchedSubnets.isEmpty()) { + VPCListing systemVpc = getSystemVpc(); + createIpamSubnetInternal(natIp, natIp, SubnetBody.PurposeEnum.NAT, systemVpc); + return; + } + logger.debug("NAT subnet: {} already exists", natIp); + } catch (ApiException e) { + throw new CloudRuntimeException(String.format("Failed to create subnet for %s with NAT purpose", natIp)); + } + } + + private NatPostBody.ProtocolEnum getProtocolFromString(String protocol) { + return NatPostBody.ProtocolEnum.fromValue(protocol); + } + + private NatPostBody createNatRulePostBody(String ruleName, NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, NatPostBody.StateEnum state, + String destinationAddress, String destinationPort, + String sourceAddress, String sourcePort, + String dnatToIp, String dnatToPort, + String netrisVpcName, String snatIP, String comment) { + NatPostBody natBody = new NatPostBody(); + natBody.setAction(action); + natBody.setName(ruleName); + natBody.setProtocol(protocol); + natBody.setState(state); + if (StringUtils.isNotBlank(comment)) { + natBody.setComment(comment); + } + + natBody.setDestinationAddress(destinationAddress); + if (StringUtils.isNotBlank(destinationPort)) { + natBody.setDestinationPort(destinationPort); + } + + if (StringUtils.isNotBlank(sourceAddress)) { + natBody.setSourceAddress(sourceAddress); + } + if (StringUtils.isNotBlank(sourcePort)) { + natBody.setSourcePort(sourcePort); + } + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + + if (StringUtils.isNotBlank(snatIP)) { + natBody.setSourceAddress(snatIP); + natBody.setSnatToIP(snatIP); + } + + if (StringUtils.isNotBlank(dnatToIp)) { + natBody.setDnatToIP(dnatToIp); + } + if (StringUtils.isNotBlank(dnatToPort)) { + natBody.setDnatToPort(Integer.valueOf(dnatToPort)); + } + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return null; + } + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + return natBody; + } + + @Override + public boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd) { + return createOrUpdateNatRuleInternal(cmd); + } + + private boolean createNatRuleInternal(String ruleName, NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, NatPostBody.StateEnum state, + String destinationAddress, String destinationPort, String sourceAddress, String sourcePort, + String sNatToIp, String dNatToIp, String dNatToPort, + String netrisVpcName, String networkName, String vNetName) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + String comment = String.format("NAT rule for %s with action %s", netrisVpcName, action.name()); + NatPostBody natBody = createNatRulePostBody(ruleName, action, protocol, state, + destinationAddress, destinationPort, sourceAddress, sourcePort, + dNatToIp, dNatToPort, netrisVpcName, sNatToIp, comment); + if (natBody == null) { + return false; + } + InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody); + if (natResponse == null || !natResponse.isIsSuccess()) { + String reason = natResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris NAT rule {} creation failed for network(vNet) - {}({}): {}", action.name(), networkName, vNetName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create NAT rule %s for network(vNet): %s(%s)", action.name(), networkName, vNetName), e); + } + return true; + } + + private void updateNatRequest(NatPostBody natBody) { + + } + + private boolean updateSnatRuleInternal(String snatRuleName, String snatIP, String netrisVpcName, String networkName, + String vNetName, Integer netisSnatId, String vpcCidr) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + NatPutBody natBody = new NatPutBody(); + natBody.setAction(NatPutBody.ActionEnum.SNAT); + natBody.setDestinationAddress("0.0.0.0/0"); + natBody.setName(snatRuleName); + natBody.setProtocol(NatPutBody.ProtocolEnum.ALL); + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + natBody.setSourceAddress(vpcCidr); + natBody.setSnatToIP(snatIP); + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + + InlineResponse20016 natUpdateResponse = natApi.apiV2NatIdPut(natBody, netisSnatId); + if (natUpdateResponse == null || !natUpdateResponse.isIsSuccess()) { + String reason = natUpdateResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Update of Netris SNAT rule failed for network(vNet) - {}({}): {}", networkName, vNetName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create SNAT rule for network(vNet): %s(%s)", networkName, vNetName), e); + } + return true; + } + private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) { try { VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class); @@ -483,21 +829,35 @@ public class NetrisApiClientImpl implements NetrisApiClient { } } - private void deleteSubnetInternal(FilterByVpc vpcFilter, String netrisVnetName, String netrisSubnetName) { + private List<IpTreeSubnet> getSubnet(FilterByVpc vpcFilter, String netrisSubnetName) { try { - logger.debug("Deleting Netris VPC IPAM Subnet {} for vNet: {}", netrisSubnetName, netrisVnetName); IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); SubnetResBody subnetsResponse = ipamApi.apiV2IpamSubnetsGet(vpcFilter); List<IpTreeSubnet> subnets = subnetsResponse.getData(); - List<IpTreeSubnet> matchedSubnets = subnets.stream().filter(subnet -> subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList()); + return subnets.stream().filter(subnet -> subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList()); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to get IPAM subnet: %s", netrisSubnetName), e); + } + return new ArrayList<>(); + } + + private void deleteSubnetInternal(FilterByVpc vpcFilter, String netrisVnetName, String netrisSubnetName) { + try { + String logString = ""; + if (Objects.nonNull(netrisVnetName)) { + logString = String.format("for vNet: %s ", netrisVnetName); + } + logger.debug("Deleting Netris VPC IPAM Subnet {} {}", netrisSubnetName, logString); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + List<IpTreeSubnet> matchedSubnets = getSubnet(vpcFilter, netrisSubnetName); if (CollectionUtils.isEmpty(matchedSubnets)) { - logger.debug("IPAM subnet: {} for the given vNet: {} appears to already be deleted on Netris", netrisSubnetName, netrisVnetName); + logger.debug("IPAM subnet: {} {} appears to already be deleted on Netris", netrisSubnetName, logString); return; } ipamApi.apiV2IpamTypeIdDelete("subnet", matchedSubnets.get(0).getId().intValue()); } catch (ApiException e) { - logAndThrowException(String.format("Failed to delete vNet: %s", netrisVnetName), e); + logAndThrowException(String.format("Failed to delete subnet: %s", netrisSubnetName), e); } } @@ -607,4 +967,23 @@ public class NetrisApiClientImpl implements NetrisApiClient { } return suffix; } + + private NatGetBody netrisNatRuleExists(String netrisNatRule) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + //NatResponseGetOk response = natApi.apiV2NatGet(null, Arrays.asList(new BigDecimal(vpcId))); + NatResponseGetOk response = natApi.apiV2NatGet(null, null); + if (Objects.isNull(response) || !response.isIsSuccess()) { + throw new CloudRuntimeException("Failed to list Netris NAT rules"); + } + List<NatGetBody> data = response.getData().stream().filter(natData -> natData.getName().equals(netrisNatRule)).collect(Collectors.toList()); + if (data.isEmpty()) { + return null; + } + return data.get(0); + + } catch (ApiException e) { + throw new CloudRuntimeException("Failed to list Netris NAT rules"); + } + } } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java index 9a29a410862..eb74e6f7080 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java @@ -23,6 +23,7 @@ import com.cloud.agent.api.AgentControlCommand; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; +import com.cloud.api.ApiDBUtils; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; @@ -39,15 +40,25 @@ import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.SDNProviderOpObject; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.IpDeployer; import com.cloud.network.element.NetworkACLServiceProvider; +import com.cloud.network.element.PortForwardingServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VpcProvider; import com.cloud.network.netris.NetrisService; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpc.NetworkACLItem; import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.StaticRouteProfile; @@ -61,27 +72,39 @@ import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.VMInstanceDao; import org.apache.cloudstack.StartupNetrisCommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.resource.NetrisNetworkRule; +import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO; +import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Component; import javax.inject.Inject; import javax.naming.ConfigurationException; +import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @Component public class NetrisElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider, - NetworkACLServiceProvider, ResourceStateAdapter, Listener { + StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, NetworkACLServiceProvider, ResourceStateAdapter, Listener { @Inject NetworkModel networkModel; @@ -101,6 +124,12 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D private DomainDao domainDao; @Inject private VpcDao vpcDao; + @Inject + private FirewallRuleDetailsDao firewallRuleDetailsDao; + @Inject + private IPAddressDao ipAddressDao; + @Inject + private VMInstanceDao vmInstanceDao; protected Logger logger = LogManager.getLogger(getClass()); @@ -257,6 +286,11 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D return capabilities; } + @Override + public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Network.Service> services) throws ResourceUnavailableException { + return true; + } + @Override public Network.Provider getProvider() { return Network.Provider.Netris; @@ -398,4 +432,164 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) { return false; } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + @Override + public boolean applyPFRules(Network network, List<PortForwardingRule> rules) throws ResourceUnavailableException { + if (!canHandle(network, Network.Service.PortForwarding)) { + return false; + } + return applyPFRulesInternal(network, rules); + } + + private boolean addOrRemovePFRuleOnNetris(UserVm vm, PortForwardingRule rule, NetrisNetworkRule networkRule, SDNProviderOpObject netrisObject, boolean create) { + logger.debug("{} port forwarding rule on Netris for VM {} to ports {} - {}", + create ? "Creating" : "Deleting", vm.getUuid(), rule.getDestinationPortStart(), rule.getDestinationPortEnd()); + Long vpcId = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getId() : null; + String vpcName = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getName() : null; + Long networkId = netrisObject.getNetworkVO() != null ? netrisObject.getNetworkVO().getId() : null; + String networkName = netrisObject.getNetworkVO() != null ? netrisObject.getNetworkVO().getName() : null; + String vpcCidr = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getCidr() : null; + + return create ? + netrisService.createPortForwardingRule(networkRule.getZoneId(), networkRule.getAccountId(), networkRule.getDomainId(), + vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, networkRule) : + netrisService.deletePortForwardingRule(networkRule.getZoneId(), networkRule.getAccountId(), networkRule.getDomainId(), + vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, networkRule); + } + + private boolean applyPFRulesInternal(Network network, List<PortForwardingRule> rules) { + return Transaction.execute((TransactionCallback<Boolean>) status -> { + boolean result = true; + for (PortForwardingRule rule : rules) { + IPAddressVO publicIp = ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId()); + UserVm vm = ApiDBUtils.findUserVmById(rule.getVirtualMachineId()); + if (vm == null && rule.getState() != FirewallRule.State.Revoke) { + continue; + } + SDNProviderOpObject netrisObject = getNetrisOpObject(network); + String publicPort = PortForwardingServiceProvider.getPublicPortRange(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePFPortRange(rule); + FirewallRuleDetailVO ruleDetail = firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.NETRIS_DETAIL_KEY); + + NetrisNetworkRule networkRule = new NetrisNetworkRule(); + networkRule.setDomainId(netrisObject.getDomainId()); + networkRule.setAccountId(netrisObject.getAccountId()); + networkRule.setZoneId(netrisObject.getZoneId()); + networkRule.setNetworkResourceId(netrisObject.getNetworkResourceId()); + networkRule.setNetworkResourceName(netrisObject.getNetworkResourceName()); + networkRule.setVpcResource(netrisObject.isVpcResource()); + networkRule.setVmId(Objects.nonNull(vm) ? vm.getId() : 0); + networkRule.setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : null); + networkRule.setPublicIp(publicIp.getAddress().addr()); + networkRule.setPrivatePort(privatePort); + networkRule.setPublicPort(publicPort); + networkRule.setRuleId(rule.getId()); + networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)); + + if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) { + boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, networkRule, netrisObject, true); + if (pfRuleResult) { + logger.debug("Port forwarding rule {} created on Netris, adding detail on firewall rules details", rule.getId()); + if (ruleDetail == null && FirewallRule.State.Add == rule.getState()) { + logger.debug("Adding new firewall detail for rule {}", rule.getId()); + firewallRuleDetailsDao.addDetail(rule.getId(), ApiConstants.NETRIS_DETAIL_KEY, "true", false); + } else if (ruleDetail != null) { + logger.debug("Updating firewall detail for rule {}", rule.getId()); + ruleDetail.setValue("true"); + firewallRuleDetailsDao.update(ruleDetail.getId(), ruleDetail); + } + } + result &= pfRuleResult; + } else if (rule.getState() == FirewallRule.State.Revoke) { + boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, networkRule, netrisObject, false); + if (pfRuleResult && ruleDetail != null) { + logger.debug("Updating firewall rule detail {} for rule {}, set to false", ruleDetail.getId(), rule.getId()); + ruleDetail.setValue("false"); + firewallRuleDetailsDao.update(ruleDetail.getId(), ruleDetail); + } + result &= pfRuleResult; + } + } + return result; + }); + } + + private SDNProviderOpObject getNetrisOpObject(Network network) { + Pair<VpcVO, NetworkVO> vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO networkVO = vpcOrNetwork.second(); + long domainId = getResourceId("domain", vpc, networkVO); + long accountId = getResourceId("account", vpc, networkVO); + long zoneId = getResourceId("zone", vpc, networkVO); + + return new SDNProviderOpObject.Builder() + .vpcVO(vpc) + .networkVO(networkVO) + .domainId(domainId) + .accountId(accountId) + .zoneId(zoneId) + .build(); + } + + public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException { + for(StaticNat staticNat : rules) { + long sourceIpAddressId = staticNat.getSourceIpAddressId(); + IPAddressVO ipAddressVO = ipAddressDao.findByIdIncludingRemoved(sourceIpAddressId); + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(ipAddressVO.getAssociatedWithVmId()); + // floating ip is released when nic was deleted + if (vm == null || networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()) == null) { + continue; + } + Pair<VpcVO, NetworkVO> vpcOrNetwork = getVpcOrNetwork(config.getVpcId(), config.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO network = vpcOrNetwork.second(); + Long networkResourceId = Objects.nonNull(vpc) ? vpc.getId() : network.getId(); + String networkResourceName = Objects.nonNull(vpc) ? vpc.getName() : network.getName(); + boolean isVpcResource = Objects.nonNull(vpc); + if (!staticNat.isForRevoke()) { + return netrisService.createStaticNatRule(config.getDataCenterId(), config.getAccountId(), config.getDomainId(), + networkResourceName, networkResourceId, isVpcResource, vpc.getCidr(), + ipAddressVO.getAddress().addr(), staticNat.getDestIpAddress()); + } else { + return netrisService.deleteStaticNatRule(config.getDataCenterId(), config.getAccountId(), config.getDomainId(), + networkResourceName, networkResourceId, isVpcResource, ipAddressVO.getAddress().addr()); + } + } + return false; + } + + public Pair<VpcVO, NetworkVO> getVpcOrNetwork(Long vpcId, long networkId) { + VpcVO vpc = null; + NetworkVO network = null; + if (Objects.nonNull(vpcId)) { + vpc = vpcDao.findById(vpcId); + if (Objects.isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC with id: %s", vpcId)); + } + } else { + network = networkDao.findById(networkId); + if (Objects.isNull(network)) { + throw new CloudRuntimeException(String.format("Failed to find network with id: %s", networkId)); + } + } + return new Pair<>(vpc, network); + } + + private long getResourceId(String resource, VpcVO vpc, NetworkVO network) { + switch (resource) { + case "domain": + return Objects.nonNull(vpc) ? vpc.getDomainId() : network.getDomainId(); + case "account": + return Objects.nonNull(vpc) ? vpc.getAccountId() : network.getAccountId(); + case "zone": + return Objects.nonNull(vpc) ? vpc.getZoneId() : network.getDataCenterId(); + default: + return 0; + } + } } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java index 2a4891eb28c..8fa07f17d40 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java @@ -28,8 +28,10 @@ import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.NetworkMigrationResponder; +import com.cloud.network.NetworkModel; 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; @@ -57,6 +59,8 @@ public class NetrisGuestNetworkGuru extends GuestNetworkGuru implements Network @Inject private NetrisService netrisService; + @Inject + NetworkModel networkModel; public NetrisGuestNetworkGuru() { super(); @@ -236,6 +240,18 @@ public class NetrisGuestNetworkGuru extends GuestNetworkGuru implements Network if (isNull(network.getVpcId()) && networkOfferingVO.getNetworkMode().equals(NetworkOffering.NetworkMode.NATTED)) { // Netris Natted mode + long domainId = domain.getId(); + long accountId = account.getId(); + long dataCenterId = zone.getId(); + long resourceId = network.getId(); + PublicIpAddress ipAddress = networkModel.getSourceNatIpAddressForGuestNetwork(account, network); + String snatIP = ipAddress.getAddress().addr(); + boolean result = netrisService.createSnatRule(dataCenterId, accountId, domainId, vpc.getName(), vpc.getId(), network.getName(), resourceId, nonNull(network.getVpcId()), vpc.getCidr(), snatIP); + if (!result) { + String msg = String.format("Could not create Netris Nat Rule for IP %s", snatIP); + logger.error(msg); + throw new CloudRuntimeException(msg); + } } return nicProfile; @@ -277,7 +293,7 @@ public class NetrisGuestNetworkGuru extends GuestNetworkGuru implements Network vpcName = vpc.getName(); vpcId = vpc.getId(); } else { - logger.debug(String.format("Creating a Tier 1 Gateway for the network %s before creating the NSX segment", networkVO.getName())); + logger.debug(String.format("Creating IPAM Allocation before creating IPAM Subnet", networkVO.getName())); long networkOfferingId = networkVO.getNetworkOfferingId(); NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(networkOfferingId); boolean isSourceNatSupported = !NetworkOffering.NetworkMode.ROUTED.equals(networkOfferingVO.getNetworkMode()) && diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java index 11db60a5aca..f1cc49b7125 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java @@ -128,6 +128,15 @@ public class NetrisPublicNetworkGuru extends PublicNetworkGuru { if (!hasNatSupport) { return nic; } + + String snatIP = ipAddress.getAddress().addr(); + result = netrisService.createSnatRule(dataCenterId, accountId, domainId, vpc.getName(), vpc.getId(), network.getName(), network.getId(), isForVpc, vpc.getCidr(), snatIP); + if (!result) { + String msg = String.format("Could not create Netris Nat Rule for IP %s", snatIP); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } } return nic; diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java index d679eae258d..b1e00f771cd 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java @@ -19,25 +19,32 @@ package org.apache.cloudstack.service; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.IpAddress; import com.cloud.network.Networks; +import com.cloud.network.SDNProviderNetworkRule; import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.netris.NetrisService; import com.cloud.network.vpc.Vpc; +import io.netris.model.NatPostBody; import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.NetrisAnswer; import org.apache.cloudstack.agent.api.NetrisCommand; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.resource.NetrisResourceObjectUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.inject.Inject; +import java.util.Locale; import java.util.Objects; public class NetrisServiceImpl implements NetrisService, Configurable { @@ -110,4 +117,136 @@ public class NetrisServiceImpl implements NetrisService, Configurable { NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); return answer.getResult(); } + + @Override + public boolean createSnatRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, String vpcCidr, String snatIP) { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc, vpcCidr); + cmd.setNatIp(snatIP); + cmd.setNatRuleType("SNAT"); + String suffix; + if (isForVpc) { + suffix = String.valueOf(vpcId); // D1-A1-Z1-V25-SNAT + } else { + suffix = String.valueOf(networkId); // D1-A1-Z1-N25-SNAT + } + cmd.setProtocol(NatPostBody.ProtocolEnum.ALL.getValue()); + cmd.setState(NatPostBody.StateEnum.ENABLED.getValue()); + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix); + cmd.setNatRuleName(snatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean createPortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, + Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, + networkName, networkId, isForVpc, vpcCidr); + cmd.setProtocol(networkRule.getProtocol().toLowerCase(Locale.ROOT)); + cmd.setDestinationAddress(networkRule.getPublicIp()); + cmd.setDestinationPort(networkRule.getPublicPort()); + cmd.setSourceAddress(networkRule.getVmIp()); + cmd.setSourcePort(networkRule.getPrivatePort()); + cmd.setState(NatPostBody.StateEnum.ENABLED.getValue()); + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", networkRule.getRuleId())); + cmd.setNatRuleName(ruleName); + cmd.setNatRuleType("DNAT"); + + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deletePortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + DeleteNetrisNatRuleCommand cmd = new DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc); + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", networkRule.getRuleId())); + cmd.setNatRuleType("DNAT"); + cmd.setNatRuleName(ruleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + if (vpc == null || address == null) { + return false; + } + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + long zoneId = vpc.getZoneId(); + long vpcId = vpc.getId(); + String vpcName = vpc.getName(); + + logger.debug("Updating the source NAT IP for Netris VPC {} to IP: {}", vpc.getName(), address.getAddress().addr()); + + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, null, null, true, address.getAddress().addr()); + cmd.setNatRuleType("SNAT"); + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, String.valueOf(vpcId)); + cmd.setNatRuleName(snatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + if (!answer.getResult()) { + logger.error("Could not update the source NAT IP address for VPC {}: {}", vpc.getName(), answer.getDetails()); + return false; + } + return answer.getResult(); + } + + @Override + public boolean createStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String vpcCidr, String staticNatIp, String vmIp) { + String vpcName = null; + String networkName = null; + Long vpcId = null; + Long networkId = null; + if (isForVpc) { + vpcName = networkResourceName; + vpcId = networkResourceId; + } else { + networkName = networkResourceName; + networkId = networkResourceId; + } + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc, vpcCidr); + cmd.setNatRuleType("STATICNAT"); + cmd.setNatIp(staticNatIp); + cmd.setVmIp(vmIp); + String suffix = getResourceSuffix(vpcId, networkId, isForVpc); + String dnatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffix); + cmd.setNatRuleName(dnatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp) { + String vpcName = null; + String networkName = null; + Long vpcId = null; + Long networkId = null; + if (isForVpc) { + vpcName = networkResourceName; + vpcId = networkResourceId; + } else { + networkName = networkResourceName; + networkId = networkResourceId; + } + DeleteNetrisNatRuleCommand cmd = new DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc); + String suffix = getResourceSuffix(vpcId, networkId, isForVpc); + String dnatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffix); + cmd.setNatRuleName(dnatRuleName); + cmd.setNatRuleType("STATICNAT"); + cmd.setNatIp(staticNatIp); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + private String getResourceSuffix(Long vpcId, Long networkId, boolean isForVpc) { + String suffix; + if (isForVpc) { + suffix = String.valueOf(vpcId); // D1-A1-Z1-V25-STATICNAT or D1-A1-Z1-V25-SNAT + } else { + suffix = String.valueOf(networkId); // D1-A1-Z1-N25-STATICNAT or D1-A1-Z1-N25-SNAT + } + return suffix; + } } diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java index 11b4af48fed..e7d223672e4 100644 --- a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.resource; import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.junit.Assert; import org.junit.Test; @@ -54,4 +55,15 @@ public class NetrisResourceObjectUtilsTest { String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, vpcName); Assert.assertEquals(expectedNetrisVpcName, netrisVpcName); } + + @Test + public void testSuffixesForDNAT() { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, vpcName, null, true, vpcCidr); + cmd.setNatRuleType("DNAT"); + long ruleId = 23L; + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", ruleId)); + String expectedNetrisRuleName = String.format("D%s-A%s-Z%s-V%s-DNAT-R%s", domainId, accountId, zoneId, vpcId, ruleId); + Assert.assertEquals(expectedNetrisRuleName, ruleName); + } } 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 c11141db9d4..153143b6d18 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 @@ -16,151 +16,18 @@ // under the License. package org.apache.cloudstack.resource; -import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; import java.util.List; -public class NsxNetworkRule { +public class NsxNetworkRule extends SDNProviderNetworkRule { public enum NsxRuleAction { ALLOW, DROP } - private long domainId; - private long accountId; - private long zoneId; - private Long networkResourceId; - private String networkResourceName; - private boolean isVpcResource; - private long vmId; - private long ruleId; - private String publicIp; - private String vmIp; - private String publicPort; - private String privatePort; - private String protocol; - private String algorithm; private List<NsxLoadBalancerMember> memberList; private NsxRuleAction aclAction; - private List<String> sourceCidrList; - private List<String> destinationCidrList; - private Integer icmpCode; - - private Integer icmpType; - private String trafficType; - private Network.Service service; - - public long getDomainId() { - return domainId; - } - - public void setDomainId(long domainId) { - this.domainId = domainId; - } - - public long getAccountId() { - return accountId; - } - - public void setAccountId(long accountId) { - this.accountId = accountId; - } - - public long getZoneId() { - return zoneId; - } - - public void setZoneId(long zoneId) { - this.zoneId = zoneId; - } - - public Long getNetworkResourceId() { - return networkResourceId; - } - - public void setNetworkResourceId(Long networkResourceId) { - this.networkResourceId = networkResourceId; - } - - public String getNetworkResourceName() { - return networkResourceName; - } - - public void setNetworkResourceName(String networkResourceName) { - this.networkResourceName = networkResourceName; - } - - public boolean isVpcResource() { - return isVpcResource; - } - - public void setVpcResource(boolean vpcResource) { - isVpcResource = vpcResource; - } - - public long getVmId() { - return vmId; - } - - public void setVmId(long vmId) { - this.vmId = vmId; - } - - public long getRuleId() { - return ruleId; - } - - public void setRuleId(long ruleId) { - this.ruleId = ruleId; - } - - public String getPublicIp() { - return publicIp; - } - - public void setPublicIp(String publicIp) { - this.publicIp = publicIp; - } - - public String getVmIp() { - return vmIp; - } - - public void setVmIp(String vmIp) { - this.vmIp = vmIp; - } - - public String getPublicPort() { - return publicPort; - } - - public void setPublicPort(String publicPort) { - this.publicPort = publicPort; - } - - public String getPrivatePort() { - return privatePort; - } - - public void setPrivatePort(String privatePort) { - this.privatePort = privatePort; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public void setAlgorithm(String algorithm) { - this.algorithm = algorithm; - } - - public String getAlgorithm() { - return algorithm; - } public List<NsxLoadBalancerMember> getMemberList() { return memberList; @@ -177,221 +44,4 @@ public class NsxNetworkRule { public void setAclAction(NsxRuleAction aclAction) { this.aclAction = aclAction; } - - public Network.Service getService() { - return service; - } - - 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<String> getSourceCidrList() { - return sourceCidrList; - } - - public void setSourceCidrList(List<String> sourceCidrList) { - this.sourceCidrList = sourceCidrList; - } - - public List<String> getDestinationCidrList() { - return destinationCidrList; - } - - public void setDestinationCidrList(List<String> destinationCidrList) { - this.destinationCidrList = destinationCidrList; - } - - public String getTrafficType() { - return trafficType; - } - - public void setTrafficType(String trafficType) { - this.trafficType = trafficType; - } - - public static final class Builder { - private long domainId; - private long accountId; - private long zoneId; - private Long networkResourceId; - private String networkResourceName; - private boolean isVpcResource; - private long vmId; - - private long ruleId; - private String publicIp; - private String vmIp; - private String publicPort; - private String privatePort; - private String protocol; - private String algorithm; - private List<NsxLoadBalancerMember> memberList; - private NsxRuleAction aclAction; - private List<String> sourceCidrList; - private List<String> destinationidrList; - private String trafficType; - private Integer icmpType; - private Integer icmpCode; - private Network.Service service; - - public Builder() { - // Default constructor - } - - public Builder setDomainId(long domainId) { - this.domainId = domainId; - return this; - } - - public Builder setAccountId(long accountId) { - this.accountId = accountId; - return this; - } - - public Builder setZoneId(long zoneId) { - this.zoneId = zoneId; - return this; - } - - public Builder setNetworkResourceId(Long networkResourceId) { - this.networkResourceId = networkResourceId; - return this; - } - - public Builder setNetworkResourceName(String networkResourceName) { - this.networkResourceName = networkResourceName; - return this; - } - - public Builder setVpcResource(boolean isVpcResource) { - this.isVpcResource = isVpcResource; - return this; - } - - - public Builder setVmId(long vmId) { - this.vmId = vmId; - return this; - } - - public Builder setRuleId(long ruleId) { - this.ruleId = ruleId; - return this; - } - - public Builder setPublicIp(String publicIp) { - this.publicIp = publicIp; - return this; - } - - public Builder setVmIp(String vmIp) { - this.vmIp = vmIp; - return this; - } - - public Builder setPublicPort(String publicPort) { - this.publicPort = publicPort; - return this; - } - - public Builder setPrivatePort(String privatePort) { - this.privatePort = privatePort; - return this; - } - - public Builder setProtocol(String protocol) { - this.protocol = protocol; - return this; - } - - public Builder setAlgorithm(String algorithm) { - this.algorithm = algorithm; - return this; - } - - public Builder setMemberList(List<NsxLoadBalancerMember> memberList) { - this.memberList = memberList; - return this; - } - - - public Builder setAclAction(NsxRuleAction aclAction) { - this.aclAction = aclAction; - return this; - } - - public Builder setTrafficType(String trafficType) { - this.trafficType = trafficType; - return this; - } - - public Builder setIcmpType(Integer icmpType) { - this.icmpType = icmpType; - return this; - } - - public Builder setIcmpCode(Integer icmpCode) { - this.icmpCode = icmpCode; - return this; - } - - public Builder setSourceCidrList(List<String> sourceCidrList) { - this.sourceCidrList = sourceCidrList; - return this; - } - - public Builder setDestinationCidrList(List<String> destinationCidrList) { - this.destinationidrList = destinationCidrList; - return this; - } - - public Builder setService(Network.Service service) { - this.service = service; - return this; - } - - public NsxNetworkRule build() { - NsxNetworkRule rule = new NsxNetworkRule(); - rule.setDomainId(this.domainId); - rule.setAccountId(this.accountId); - rule.setZoneId(this.zoneId); - rule.setNetworkResourceId(this.networkResourceId); - rule.setNetworkResourceName(this.networkResourceName); - rule.setVpcResource(this.isVpcResource); - rule.setVmId(this.vmId); - rule.setVmIp(this.vmIp); - rule.setPublicIp(this.publicIp); - rule.setPublicPort(this.publicPort); - rule.setPrivatePort(this.privatePort); - rule.setProtocol(this.protocol); - rule.setRuleId(this.ruleId); - rule.setAlgorithm(this.algorithm); - rule.setMemberList(this.memberList); - rule.setAclAction(this.aclAction); - rule.setIcmpType(this.icmpType); - rule.setIcmpCode(this.icmpCode); - 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/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index e1b37a8d653..95cd948358a 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 @@ -109,7 +109,7 @@ import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalanc import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.cloudstack.resource.NsxLoadBalancerMember; import org.apache.cloudstack.resource.NsxNetworkRule; -import org.apache.cloudstack.resource.NsxOpObject; +import com.cloud.network.SDNProviderOpObject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO; @@ -552,26 +552,26 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns if (vm == null && rule.getState() != FirewallRule.State.Revoke) { continue; } - NsxOpObject nsxObject = getNsxOpObject(network); - String publicPort = getPublicPortRange(rule); - - String privatePort = getPrivatePFPortRange(rule); - - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() - .setDomainId(nsxObject.getDomainId()) - .setAccountId(nsxObject.getAccountId()) - .setZoneId(nsxObject.getZoneId()) - .setNetworkResourceId(nsxObject.getNetworkResourceId()) - .setNetworkResourceName(nsxObject.getNetworkResourceName()) - .setVpcResource(nsxObject.isVpcResource()) - .setVmId(Objects.nonNull(vm) ? vm.getId() : 0) - .setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : null) - .setPublicIp(publicIp.getAddress().addr()) - .setPrivatePort(privatePort) - .setPublicPort(publicPort) - .setRuleId(rule.getId()) - .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) - .build(); + SDNProviderOpObject nsxObject = getNsxOpObject(network); + String publicPort = PortForwardingServiceProvider.getPublicPortRange(rule); + + String privatePort = PortForwardingServiceProvider.getPrivatePFPortRange(rule); + + NsxNetworkRule networkRule = new NsxNetworkRule(); + networkRule.setDomainId(nsxObject.getDomainId()); + networkRule.setAccountId(nsxObject.getAccountId()); + networkRule.setZoneId(nsxObject.getZoneId()); + networkRule.setNetworkResourceId(nsxObject.getNetworkResourceId()); + networkRule.setNetworkResourceName(nsxObject.getNetworkResourceName()); + networkRule.setVpcResource(nsxObject.isVpcResource()); + networkRule.setVmId(Objects.nonNull(vm) ? vm.getId() : 0); + networkRule.setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : null); + networkRule.setPublicIp(publicIp.getAddress().addr()); + networkRule.setPrivatePort(privatePort); + networkRule.setPublicPort(publicPort); + networkRule.setRuleId(rule.getId()); + networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)); + FirewallRuleDetailVO ruleDetail = firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.FOR_NSX); if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) { if ((ruleDetail == null && FirewallRule.State.Add == rule.getState()) || (ruleDetail != null && !ruleDetail.getValue().equalsIgnoreCase("true"))) { @@ -633,30 +633,6 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns return new Pair<>(vpc, network); } - 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(FirewallRule 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 getPrivatePortRangeForACLRule(NetworkACLItem rule) { - return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? - String.valueOf(rule.getSourcePortStart()) : - String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); - } - private long getResourceId(String resource, VpcVO vpc, NetworkVO network) { switch (resource) { case "domain": @@ -670,7 +646,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns } } - private NsxOpObject getNsxOpObject(Network network) { + private SDNProviderOpObject getNsxOpObject(Network network) { Pair<VpcVO, NetworkVO> vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); VpcVO vpc = vpcOrNetwork.first(); NetworkVO networkVO = vpcOrNetwork.second(); @@ -678,7 +654,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns long accountId = getResourceId("account", vpc, networkVO); long zoneId = getResourceId("zone", vpc, networkVO); - return new NsxOpObject.Builder() + return new SDNProviderOpObject.Builder() .vpcVO(vpc) .networkVO(networkVO) .domainId(domainId) @@ -693,25 +669,24 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns for (LoadBalancingRule loadBalancingRule : rules) { IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), loadBalancingRule.getSourceIp().addr()); - NsxOpObject nsxObject = getNsxOpObject(network); + SDNProviderOpObject nsxObject = getNsxOpObject(network); List<NsxLoadBalancerMember> lbMembers = getLoadBalancerMembers(loadBalancingRule); - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() - .setDomainId(nsxObject.getDomainId()) - .setAccountId(nsxObject.getAccountId()) - .setZoneId(nsxObject.getZoneId()) - .setNetworkResourceId(nsxObject.getNetworkResourceId()) - .setNetworkResourceName(nsxObject.getNetworkResourceName()) - .setVpcResource(nsxObject.isVpcResource()) - .setMemberList(lbMembers) - .setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? - publicIp.getAddress().addr() : loadBalancingRule.getSourceIp().addr()) - .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) - .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) - .setRuleId(loadBalancingRule.getId()) - .setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT)) - .setAlgorithm(loadBalancingRule.getAlgorithm()) - .build(); + NsxNetworkRule networkRule = new NsxNetworkRule(); + networkRule.setDomainId(nsxObject.getDomainId()); + networkRule.setAccountId(nsxObject.getAccountId()); + networkRule.setZoneId(nsxObject.getZoneId()); + networkRule.setNetworkResourceId(nsxObject.getNetworkResourceId()); + networkRule.setNetworkResourceName(nsxObject.getNetworkResourceName()); + networkRule.setVpcResource(nsxObject.isVpcResource()); + networkRule.setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? + publicIp.getAddress().addr() : loadBalancingRule.getSourceIp().addr()); + networkRule.setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())); + networkRule.setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())); + networkRule.setRuleId(loadBalancingRule.getId()); + networkRule.setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT)); + networkRule.setAlgorithm(loadBalancingRule.getAlgorithm()); + networkRule.setMemberList(lbMembers); if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(loadBalancingRule.getState())) { result &= nsxService.createLbRule(networkRule); } else if (loadBalancingRule.getState() == FirewallRule.State.Revoke) { @@ -756,7 +731,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns List<NsxNetworkRule> nsxDelNetworkRules = new ArrayList<>(); boolean success = true; for (NetworkACLItem rule : rules) { - String privatePort = getPrivatePortRangeForACLRule(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); NsxNetworkRule networkRule = getNsxNetworkRuleForAcl(rule, privatePort); if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) { success = success && nsxService.addFirewallRules(network, List.of(networkRule)); @@ -778,7 +753,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) { List<NsxNetworkRule> aclRulesList = new ArrayList<>(); for (NetworkACLItem rule : networkACLItems) { - String privatePort = getPrivatePortRangeForACLRule(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); aclRulesList.add(getNsxNetworkRuleForAcl(rule, privatePort)); } for (Network network: networks) { @@ -794,18 +769,18 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns } private NsxNetworkRule getNsxNetworkRuleForAcl(NetworkACLItem rule, String privatePort) { - return new NsxNetworkRule.Builder() - .setRuleId(rule.getId()) - .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) - .setAclAction(transformActionValue(rule.getAction())) - .setTrafficType(rule.getTrafficType().toString()) - .setProtocol(rule.getProtocol().toUpperCase()) - .setPublicPort(String.valueOf(rule.getSourcePortStart())) - .setPrivatePort(privatePort) - .setIcmpCode(rule.getIcmpCode()) - .setIcmpType(rule.getIcmpType()) - .setService(Network.Service.NetworkACL) - .build(); + NsxNetworkRule nsxNetworkRule = new NsxNetworkRule(); + nsxNetworkRule.setRuleId(rule.getId()); + nsxNetworkRule.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")); + nsxNetworkRule.setTrafficType(rule.getTrafficType().toString()); + nsxNetworkRule.setProtocol(rule.getProtocol().toUpperCase()); + nsxNetworkRule.setPublicPort(String.valueOf(rule.getSourcePortStart())); + nsxNetworkRule.setPrivatePort(privatePort); + nsxNetworkRule.setIcmpCode(rule.getIcmpCode()); + nsxNetworkRule.setIcmpType(rule.getIcmpType()); + nsxNetworkRule.setService(Network.Service.NetworkACL); + nsxNetworkRule.setAclAction(transformActionValue(rule.getAction())); + return nsxNetworkRule; } @Override public boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException { @@ -816,20 +791,19 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns List<NsxNetworkRule> nsxAddNetworkRules = new ArrayList<>(); List<NsxNetworkRule> nsxDelNetworkRules = new ArrayList<>(); for (FirewallRule rule : rules) { - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() - .setRuleId(rule.getId()) - .setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW) - .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(); + NsxNetworkRule networkRule = new NsxNetworkRule(); + networkRule.setRuleId(rule.getId()); + networkRule.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? + transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")); + networkRule.setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ? + transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY")); + networkRule.setIcmpCode(rule.getIcmpCode()); + networkRule.setIcmpType(rule.getIcmpType()); + networkRule.setPrivatePort(PortForwardingServiceProvider.getPrivatePortRange(rule)); + networkRule.setTrafficType(rule.getTrafficType().toString()); + networkRule.setService(Network.Service.Firewall); + networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)); + networkRule.setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW); if (rule.getState() == FirewallRule.State.Add) { nsxAddNetworkRules.add(networkRule); } else if (rule.getState() == FirewallRule.State.Revoke) { diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java index 7c44a7324fb..a807155a2dc 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java @@ -36,6 +36,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; @@ -72,7 +73,6 @@ import org.mockito.junit.MockitoJUnitRunner; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.List; import static org.junit.Assert.assertTrue; @@ -307,84 +307,60 @@ public class NsxElementTest { assertNotNull(vpcNetworkPair.second()); } - private Method getPublicPortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPublicPortRange", PortForwardingRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePFPortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePFPortRange", PortForwardingRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRange", FirewallRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePortRangeForACLRuleMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRangeForACLRule", NetworkACLItem.class); - method.setAccessible(true); - return method; - } - @Test public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, 5L, 2L, 15L); - assertEquals("80-90", getPublicPortRangeMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPublicPortRange(rule)); } @Test public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, 5L, 2L, 15L); - assertEquals("80", getPublicPortRangeMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPublicPortRange(rule)); } @Test public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, 5L, 2L, 15L); - assertEquals("8080-8090", getPrivatePFPortRangeMethod().invoke(null, rule)); + assertEquals("8080-8090", PortForwardingServiceProvider.getPrivatePFPortRange(rule)); } @Test public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, 5L, 2L, 15L); - assertEquals("8080", getPrivatePFPortRangeMethod().invoke(null, rule)); + assertEquals("8080", PortForwardingServiceProvider.getPrivatePFPortRange(rule)); } @Test public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 5L, 2L, FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); - assertEquals("80", getPrivatePortRangeMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPrivatePortRange(rule)); } @Test public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 90, "tcp", 23L, 5L, 2L, FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); - assertEquals("80-90", getPrivatePortRangeMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPrivatePortRange(rule)); } @Test public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { NetworkACLItem rule = new NetworkACLItemVO(80, 80, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, 2, null); - assertEquals("80", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule)); } @Test public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { NetworkACLItem rule = new NetworkACLItemVO(80, 90, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, 2, null); - assertEquals("80-90", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule)); } @Test diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java similarity index 94% rename from plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java rename to server/src/main/java/com/cloud/network/SDNProviderOpObject.java index bb411249b88..902e47545e9 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java +++ b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java @@ -14,14 +14,14 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.resource; +package com.cloud.network; import com.cloud.network.dao.NetworkVO; import com.cloud.network.vpc.VpcVO; import java.util.Objects; -public class NsxOpObject { +public class SDNProviderOpObject { VpcVO vpcVO; NetworkVO networkVO; long accountId; @@ -116,8 +116,8 @@ public class NsxOpObject { return this; } - public NsxOpObject build() { - NsxOpObject object = new NsxOpObject(); + public SDNProviderOpObject build() { + SDNProviderOpObject object = new SDNProviderOpObject(); object.setVpcVO(this.vpcVO); object.setNetworkVO(this.networkVO); object.setDomainId(this.domainId); 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 64abcff84ef..2012f77e338 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -454,6 +454,24 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false); } + + // configure default vpc offering with Netris as network service provider in NAT mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME) == null) { + logger.debug(String.format("Creating default VPC offering for Netris network service provider %s in NAT mode", VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME)); + final Map<Service, Set<Provider>> svcProviderMap = new HashMap<>(); + final Set<Provider> defaultProviders = Set.of(Provider.Netris); + for (final Service svc : getSupportedServices()) { + if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) { + final Set<Provider> userDataProvider = Set.of(Provider.VPCVirtualRouter); + svcProviderMap.put(svc, userDataProvider); + } else { + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, svcProviderMap, false, + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false); + + } } }); diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index 67a9b61c214..8ff0e70ec72 100644 --- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java @@ -1220,6 +1220,10 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio // Offering #14 - network offering for Netris provider for VPCs - ROUTED mode createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC, "Offering for Netris enabled networks on VPCs - ROUTED mode", NetworkOffering.NetworkMode.ROUTED, true, true, Provider.Netris); + + // Offering #15 - network offering for Netris provider for VPCs - NATTED mode + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC, "Offering for Netris enabled networks on VPCs - NAT mode", + NetworkOffering.NetworkMode.NATTED, true, true, Provider.Netris); } }); }