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 <nicovazquez90@gmail.com>
This commit is contained in:
Pearl Dsilva 2024-12-03 19:35:38 -05:00 committed by GitHub
parent b70f72abec
commit ce9cbb2ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 1432 additions and 508 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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";
/**
*

View File

@ -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";

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,22 @@
// 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.resource;
import com.cloud.network.SDNProviderNetworkRule;
public class NetrisNetworkRule extends SDNProviderNetworkRule {
}

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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");
}
}
}

View File

@ -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;
}
}
}

View File

@ -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()) &&

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
@ -553,26 +553,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);
SDNProviderOpObject nsxObject = getNsxOpObject(network);
String publicPort = PortForwardingServiceProvider.getPublicPortRange(rule);
String privatePort = getPrivatePFPortRange(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));
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();
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"))) {
@ -634,30 +634,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":
@ -671,7 +647,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();
@ -679,7 +655,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)
@ -694,25 +670,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) {
@ -757,7 +732,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));
@ -779,7 +754,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) {
@ -795,18 +770,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 {
@ -817,20 +792,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) {

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}
});

View File

@ -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);
}
});
}