Phase5 - Support for ACLs in Netris (#31)

* Add support for Netris ACLs

* acl support

* Make acl api call to netris to create the rule

* refactor add acl rule to populate the right fields

* support icmp type acl rule

* acl rule creation - move netrisnetworkRule

* Update ACL naming on Netris

* Add support for Deletion of netris acls

* Add support to delete and re-order ACL rules

* support creation of default acl rules and replacing acl rules

* fix NSXNetworkRule
This commit is contained in:
Pearl Dsilva 2025-02-03 21:43:45 -05:00 committed by GitHub
parent 57609c79c4
commit f70cc1c3b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 922 additions and 140 deletions

View File

@ -20,27 +20,27 @@ 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;
protected long domainId;
protected long accountId;
protected long zoneId;
protected Long networkResourceId;
protected String networkResourceName;
protected boolean isVpcResource;
protected long vmId;
protected long ruleId;
protected String publicIp;
protected String vmIp;
protected String publicPort;
protected String privatePort;
protected String protocol;
protected String algorithm;
protected List<String> sourceCidrList;
protected List<String> destinationCidrList;
protected Integer icmpCode;
private Integer icmpType;
private String trafficType;
private Network.Service service;
protected Integer icmpType;
protected String trafficType;
protected Network.Service service;
public long getDomainId() {
return domainId;
@ -201,4 +201,158 @@ public class SDNProviderNetworkRule {
public void setTrafficType(String trafficType) {
this.trafficType = trafficType;
}
public static class Builder {
public long domainId;
public long accountId;
public long zoneId;
public Long networkResourceId;
public String networkResourceName;
public boolean isVpcResource;
public long vmId;
public long ruleId;
public String publicIp;
public String vmIp;
public String publicPort;
public String privatePort;
public String protocol;
public String algorithm;
public List<String> sourceCidrList;
public List<String> destinationCidrList;
public String trafficType;
public Integer icmpType;
public Integer icmpCode;
public 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 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.destinationCidrList = destinationCidrList;
return this;
}
public Builder setService(Network.Service service) {
this.service = service;
return this;
}
public SDNProviderNetworkRule build() {
SDNProviderNetworkRule rule = new SDNProviderNetworkRule();
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.setIcmpType(this.icmpType);
rule.setIcmpCode(this.icmpCode);
rule.setSourceCidrList(this.sourceCidrList);
rule.setDestinationCidrList(this.destinationCidrList);
rule.setTrafficType(this.trafficType);
rule.setService(service);
return rule;
}
}
}

View File

@ -0,0 +1,74 @@
// 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.netris;
import com.cloud.network.SDNProviderNetworkRule;
public class NetrisNetworkRule {
public enum NetrisRuleAction {
PERMIT, DENY
}
private SDNProviderNetworkRule baseRule;
private NetrisRuleAction aclAction;
private String reason;
public NetrisNetworkRule(Builder builder) {
this.baseRule = builder.baseRule;
this.aclAction = builder.aclAction;
this.reason = builder.reason;
}
public NetrisRuleAction getAclAction() {
return aclAction;
}
public String getReason() {
return reason;
}
public SDNProviderNetworkRule getBaseRule() {
return baseRule;
}
// Builder class extending the parent builder
public static class Builder {
private SDNProviderNetworkRule baseRule;
private NetrisRuleAction aclAction;
private String reason;
public Builder baseRule(SDNProviderNetworkRule baseRule) {
this.baseRule = baseRule;
return this;
}
public Builder aclAction(NetrisRuleAction aclAction) {
this.aclAction = aclAction;
return this;
}
public Builder reason(String reason) {
this.reason = reason;
return this;
}
public NetrisNetworkRule build() {
return new NetrisNetworkRule(this);
}
}
}

View File

@ -17,9 +17,12 @@
package com.cloud.network.netris;
import com.cloud.network.IpAddress;
import com.cloud.network.Network;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.vpc.Vpc;
import java.util.List;
public interface NetrisService {
boolean createIPAMAllocationsForZoneLevelPublicRanges(long zoneId);
@ -43,6 +46,9 @@ public interface NetrisService {
boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp);
boolean addFirewallRules(Network network, List<NetrisNetworkRule> firewallRules);
boolean deleteFirewallRules(Network network, List<NetrisNetworkRule> firewallRules);
boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute);
boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId);

View File

@ -0,0 +1,120 @@
// 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;
import org.apache.cloudstack.resource.NetrisPortGroup;
public class CreateNetrisACLCommand extends NetrisCommand {
private String vpcName;
private Long vpcId;
private String action;
private String destPrefix;
private String sourcePrefix;
private Integer destPortStart;
private Integer destPortEnd;
private Integer icmpType;
private String protocol;
private NetrisPortGroup portGroup;
private String netrisAclName;
private String reason;
public CreateNetrisACLCommand(long zoneId, Long accountId, Long domainId, String name, Long id, String vpcName, Long vpcId, boolean isVpc, String action,
String sourcePrefix, String destPrefix, Integer destPortStart, Integer destPortEnd, String protocol) {
super(zoneId, accountId, domainId, name, id, isVpc);
this.vpcName = vpcName;
this.vpcId = vpcId;
this.action = action;
this.sourcePrefix = sourcePrefix;
this.destPrefix = destPrefix;
this.destPortStart = destPortStart;
this.destPortEnd = destPortEnd;
this.protocol = protocol;
}
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 getAction() {
return action;
}
public String getDestPrefix() {
return destPrefix;
}
public String getSourcePrefix() {
return sourcePrefix;
}
public Integer getDestPortStart() {
return destPortStart;
}
public Integer getDestPortEnd() {
return destPortEnd;
}
public String getProtocol() {
return protocol;
}
public NetrisPortGroup getPortGroup() {
return portGroup;
}
public void setPortGroup(NetrisPortGroup portGroup) {
this.portGroup = portGroup;
}
public Integer getIcmpType() {
return icmpType;
}
public void setIcmpType(Integer icmpType) {
this.icmpType = icmpType;
}
public String getNetrisAclName() {
return netrisAclName;
}
public void setNetrisAclName(String netrisAclName) {
this.netrisAclName = netrisAclName;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}

View File

@ -0,0 +1,46 @@
// 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;
import java.util.List;
public class DeleteNetrisACLCommand extends NetrisCommand {
Long vpcId;
String vpcName;
List<String> aclRuleNames;
public DeleteNetrisACLCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, Long vpcId, String vpcName) {
super(zoneId, accountId, domainId, name, id, isVpc);
this.vpcId = vpcId;
this.vpcName = vpcName;
}
public Long getVpcId() {
return vpcId;
}
public String getVpcName() {
return vpcName;
}
public List<String> getAclRuleNames() {
return aclRuleNames;
}
public void setAclRuleNames(List<String> aclRuleNames) {
this.aclRuleNames = aclRuleNames;
}
}

View File

@ -16,7 +16,12 @@
// under the License.
package org.apache.cloudstack.resource;
import com.cloud.network.SDNProviderNetworkRule;
public class NetrisPortGroup {
private String ports;
public class NetrisNetworkRule extends SDNProviderNetworkRule {
public NetrisPortGroup(String ports) {
this.ports = ports;
}
public String getPorts() { return ports; }
}

View File

@ -28,10 +28,12 @@ import com.cloud.agent.api.StartupCommand;
import com.cloud.host.Host;
import com.cloud.resource.ServerResource;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.agent.api.CreateNetrisACLCommand;
import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand;
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.DeleteNetrisACLCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
@ -105,7 +107,11 @@ public class NetrisResource implements ServerResource {
} else if (cmd instanceof DeleteNetrisNatRuleCommand) {
return executeRequest((DeleteNetrisNatRuleCommand) cmd);
} else if (cmd instanceof CreateOrUpdateNetrisNatCommand) {
return executeRequest((CreateOrUpdateNetrisNatCommand) cmd);
return executeRequest((CreateOrUpdateNetrisNatCommand) cmd);
} else if (cmd instanceof CreateNetrisACLCommand) {
return executeRequest((CreateNetrisACLCommand) cmd);
} else if (cmd instanceof DeleteNetrisACLCommand) {
return executeRequest((DeleteNetrisACLCommand) cmd);
} else if (cmd instanceof DeleteNetrisStaticRouteCommand) {
return executeRequest((DeleteNetrisStaticRouteCommand) cmd);
} else if (cmd instanceof AddOrUpdateNetrisStaticRouteCommand) {
@ -306,6 +312,22 @@ public class NetrisResource implements ServerResource {
return new NetrisAnswer(cmd, true, "OK");
}
private Answer executeRequest(CreateNetrisACLCommand cmd) {
boolean result = netrisApiClient.addAclRule(cmd);
if (!result) {
return new NetrisAnswer(cmd, false, String.format("Creation of Netris ACL rule: %s failed", cmd.getNetrisAclName()));
}
return new NetrisAnswer(cmd, true, "OK");
}
private Answer executeRequest(DeleteNetrisACLCommand cmd) {
boolean result = netrisApiClient.deleteAclRule(cmd);
if (!result) {
return new NetrisAnswer(cmd, false, String.format("Failed to delete Netris ACLs: %s", String.join("'", cmd.getAclRuleNames())));
}
return new NetrisAnswer(cmd, true, "OK");
}
private Answer executeRequest(AddOrUpdateNetrisStaticRouteCommand cmd) {
boolean result = netrisApiClient.addOrUpdateStaticRoute(cmd);
if (!result) {

View File

@ -22,7 +22,7 @@ import org.apache.commons.lang3.ArrayUtils;
public class NetrisResourceObjectUtils {
public enum NetrisObjectType {
VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET, SNAT, STATICNAT, DNAT, STATICROUTE
VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET, SNAT, STATICNAT, DNAT, STATICROUTE, ACL
}
public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisObjectType netrisObjectType, String... suffixes) {
@ -77,6 +77,7 @@ public class NetrisResourceObjectUtils {
suffixes = new String[0];
break;
case VNET:
case ACL:
break;
default:
stringBuilder.append(String.format("-%s", objectName));

View File

@ -20,10 +20,12 @@ import io.netris.ApiException;
import io.netris.model.GetSiteBody;
import io.netris.model.VPCListing;
import io.netris.model.response.TenantResponse;
import org.apache.cloudstack.agent.api.CreateNetrisACLCommand;
import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand;
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.DeleteNetrisACLCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
@ -77,6 +79,8 @@ public interface NetrisApiClient {
boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd);
boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd);
boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd);
boolean addAclRule(CreateNetrisACLCommand cmd);
boolean deleteAclRule(DeleteNetrisACLCommand cmd);
boolean addOrUpdateStaticRoute(AddOrUpdateNetrisStaticRouteCommand cmd);
boolean deleteStaticRoute(DeleteNetrisStaticRouteCommand cmd);
boolean releaseNatIp(ReleaseNatIpCommand cmd);

View File

@ -21,6 +21,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
import io.netris.ApiClient;
import io.netris.ApiException;
import io.netris.ApiResponse;
import io.netris.api.v1.AclApi;
import io.netris.api.v1.AuthenticationApi;
import io.netris.api.v1.RoutesApi;
import io.netris.api.v1.SitesApi;
@ -29,6 +30,11 @@ 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.AclAddItem;
import io.netris.model.AclBodyVpc;
import io.netris.model.AclDeleteItem;
import io.netris.model.AclGetBody;
import io.netris.model.AclResponseGetOk;
import io.netris.model.AllocationBody;
import io.netris.model.AllocationBodyVpc;
import io.netris.model.FilterBySites;
@ -80,14 +86,17 @@ 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.CreateNetrisACLCommand;
import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand;
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.DeleteNetrisACLCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
import org.apache.cloudstack.agent.api.NetrisCommand;
import org.apache.cloudstack.agent.api.ReleaseNatIpCommand;
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
@ -98,14 +107,18 @@ import org.apache.logging.log4j.Logger;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
public class NetrisApiClientImpl implements NetrisApiClient {
private final Logger logger = LogManager.getLogger(getClass());
private static final String ANY_IP = "0.0.0.0/0";
private static final String[] PROTOCOL_LIST = new String[]{"TCP", "UDP", "ICMP", "ALL"};
private static ApiClient apiClient;
@ -296,6 +309,120 @@ public class NetrisApiClientImpl implements NetrisApiClient {
}
@Override
public boolean addAclRule(CreateNetrisACLCommand cmd) {
String aclName = cmd.getNetrisAclName();
try {
AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class);
AclAddItem aclAddItem = new AclAddItem();
aclAddItem.setAction(cmd.getAction());
aclAddItem.setComment(String.format("ACL rule: %s. %s", cmd.getNetrisAclName(), cmd.getReason()));
aclAddItem.setName(aclName);
String protocol = cmd.getProtocol();
if ("TCP".equals(protocol)) {
aclAddItem.setEstablished(new BigDecimal(1));
} else {
aclAddItem.setReverse("yes");
}
if (!Arrays.asList(PROTOCOL_LIST).contains(protocol)) {
aclAddItem.setProto("ip");
aclAddItem.setSrcPortTo(cmd.getIcmpType());
// TODO: set proto number: where should the protocol number be set - API sets the protocol number to Src-from & to and Dest-from & to fields
} else if ("ICMP".equals(protocol)) {
aclAddItem.setProto("icmp");
if (cmd.getIcmpType() != -1) {
aclAddItem.setIcmpType(cmd.getIcmpType());
}
} else {
aclAddItem.setProto(protocol.toLowerCase(Locale.ROOT));
}
aclAddItem.setDstPortFrom(cmd.getDestPortStart());
aclAddItem.setDstPortTo(cmd.getDestPortEnd());
aclAddItem.setDstPrefix(cmd.getDestPrefix());
aclAddItem.setSrcPrefix(cmd.getSourcePrefix());
aclAddItem.setSrcPortFrom(1);
aclAddItem.setSrcPortTo(65535);
if (NatPutBody.ProtocolEnum.ICMP.name().equalsIgnoreCase(protocol)) {
aclAddItem.setIcmpType(cmd.getIcmpType());
}
String netrisVpcName = getNetrisVpcName(cmd, cmd.getVpcId(), cmd.getVpcName());
VPCListing vpcResource = getNetrisVpcResource(netrisVpcName);
if (Objects.isNull(vpcResource)) {
return false;
}
AclBodyVpc vpc = new AclBodyVpc().id(vpcResource.getId());
aclAddItem.setVpc(vpc);
List<String> aclNames = List.of(aclName);
Pair<Boolean, List<BigDecimal>> resultAndMatchingAclIds = getMatchingAclIds(aclNames, netrisVpcName);
if (!resultAndMatchingAclIds.second().isEmpty()) {
logger.debug("Netris ACL rule: {} already exists", aclName);
return true;
}
aclApi.apiAclPost(aclAddItem);
} catch (ApiException e) {
logAndThrowException(String.format("Failed to create Netris ACL: %s", cmd.getNetrisAclName()), e);
}
return true;
}
@Override
public boolean deleteAclRule(DeleteNetrisACLCommand cmd) {
List<String> aclNames = cmd.getAclRuleNames();
try {
AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class);
String suffix = getNetrisVpcNameSuffix(cmd.getVpcId(), cmd.getVpcName(), cmd.getId(), cmd.getName(), cmd.isVpc());
String vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
Pair<Boolean, List<BigDecimal>> resultAndMatchingAclIds = getMatchingAclIds(aclNames, vpcName);
Boolean result = resultAndMatchingAclIds.first();
List<BigDecimal> matchingAclIds = resultAndMatchingAclIds.second();
if (!result) {
logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId);
return false;
}
if (matchingAclIds.isEmpty()) {
logger.warn("There doesn't seem to be any ACLs on Netris matching {}", aclNames.size() > 1 ? String.join(",", aclNames) : aclNames);
return true;
}
AclDeleteItem aclDeleteItem = new AclDeleteItem();
aclDeleteItem.setId(matchingAclIds);
aclDeleteItem.setTenantsID(String.valueOf(tenantId));
aclApi.apiAclDelete(aclDeleteItem);
} catch (ApiException e) {
logAndThrowException(String.format("Failed to delete Netris ACLs: %s", String.join(",", cmd.getAclRuleNames())), e);
}
return true;
}
Pair<Boolean, List<BigDecimal>> getMatchingAclIds(List<String> aclNames, String vpcName) {
try {
AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class);
VPCListing vpcResource = getVpcByNameAndTenant(vpcName);
if (vpcResource == null) {
logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId);
return new Pair<>(false, Collections.emptyList());
}
FilterByVpc vpcFilter = new FilterByVpc();
vpcFilter.add(vpcResource.getId());
FilterBySites siteFilter = new FilterBySites();
siteFilter.add(siteId);
AclResponseGetOk aclGetResponse = aclApi.apiAclGet(siteFilter, vpcFilter);
if (aclGetResponse == null || !aclGetResponse.isIsSuccess()) {
logger.warn("No ACLs were found to be present for the specific Netris VPC resource {}." +
" Netris ACLs may have been deleted out of band.", vpcName);
return new Pair<>(true, Collections.emptyList());
}
List<AclGetBody> aclList = aclGetResponse.getData();
return new Pair<>(true, aclList.stream()
.filter(acl -> aclNames.contains(acl.getName()))
.map(acl -> BigDecimal.valueOf(acl.getId()))
.collect(Collectors.toList()));
} catch (ApiException e) {
logAndThrowException("Failed to retrieve Netris ACLs", e);
}
return new Pair<>(true, Collections.emptyList());
}
public boolean addOrUpdateStaticRoute(AddOrUpdateNetrisStaticRouteCommand cmd) {
String prefix = cmd.getPrefix();
String nextHop = cmd.getNextHop();
@ -491,13 +618,6 @@ public class NetrisApiClientImpl implements NetrisApiClient {
return new Pair<>(false, null);
}
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 {
@ -597,9 +717,8 @@ public class NetrisApiClientImpl implements NetrisApiClient {
String netrisV6Cidr = cmd.getIpv6Cidr();
boolean isVpc = cmd.isVpc();
String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc);
String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
VPCListing associatedVpc = getVpcByNameAndTenant(netrisVpcName);
String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName);
VPCListing associatedVpc = getNetrisVpcResource(netrisVpcName);
if (associatedVpc == null) {
logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName);
return false;
@ -644,9 +763,8 @@ public class NetrisApiClientImpl implements NetrisApiClient {
boolean isVpc = cmd.isVpc();
String vnetCidr = cmd.getVNetCidr();
try {
String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc);
String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
VPCListing associatedVpc = getVpcByNameAndTenant(netrisVpcName);
String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName);
VPCListing associatedVpc = getNetrisVpcResource(netrisVpcName);
if (associatedVpc == null) {
logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName);
return false;
@ -758,9 +876,8 @@ public class NetrisApiClientImpl implements NetrisApiClient {
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);
String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName);
VPCListing vpcResource = getNetrisVpcResource(netrisVpcName);
if (vpcResource == null) {
logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId);
return false;
@ -781,9 +898,9 @@ public class NetrisApiClientImpl implements NetrisApiClient {
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 destinationAddress = action == NatPostBody.ActionEnum.SNAT ? ANY_IP : cmd.getDestinationAddress() + "/32";
String destinationPort = cmd.getDestinationPort();
String sourceAddress = action == NatPostBody.ActionEnum.SNAT ? vpcCidr : "0.0.0.0/0";
String sourceAddress = action == NatPostBody.ActionEnum.SNAT ? vpcCidr : ANY_IP;
String sourcePort = "1-65535";
String snatToIp = action == NatPostBody.ActionEnum.SNAT ? targetIpSubnet : null;
String dnatToIp = action == NatPostBody.ActionEnum.DNAT ? cmd.getSourceAddress() + "/32" : null;
@ -834,9 +951,8 @@ public class NetrisApiClientImpl implements NetrisApiClient {
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);
String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName);
VPCListing vpcResource = getNetrisVpcResource(netrisVpcName);
if (vpcResource == null) {
logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId);
return false;
@ -856,7 +972,7 @@ public class NetrisApiClientImpl implements NetrisApiClient {
site.setId(siteId);
site.setName(siteName);
natBody.setSite(site);
natBody.setSourceAddress("0.0.0.0/0");
natBody.setSourceAddress(ANY_IP);
natBody.setDnatToIP(vmIp);
NatBodyVpcVpc vpc = new NatBodyVpcVpc();
@ -981,17 +1097,13 @@ public class NetrisApiClientImpl implements NetrisApiClient {
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.setDestinationAddress(ANY_IP);
natBody.setName(snatRuleName);
natBody.setProtocol(NatPutBody.ProtocolEnum.ALL);
@ -1214,4 +1326,24 @@ public class NetrisApiClientImpl implements NetrisApiClient {
throw new CloudRuntimeException("Failed to list Netris NAT rules");
}
}
private VPCListing getNetrisVpcResource(String netrisVpcName) {
VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
if (vpcResource == null) {
logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId);
}
return vpcResource;
}
private String getNetrisVpcName(NetrisCommand cmd, Long vpcId, String vpcName) {
String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, cmd.getId(), cmd.getName(), cmd.isVpc());
return NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
}
private void deleteNatSubnet(Integer netrisVpcId, String natIp) {
FilterByVpc vpcFilter = new FilterByVpc();
vpcFilter.add(netrisVpcId);
String netrisSubnetName = natIp + "/32";
deleteSubnetInternal(vpcFilter, null, netrisSubnetName);
}
}

View File

@ -41,6 +41,7 @@ import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.SDNProviderOpObject;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
@ -86,7 +87,7 @@ 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 com.cloud.network.netris.NetrisNetworkRule;
import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO;
import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao;
import org.apache.logging.log4j.LogManager;
@ -95,6 +96,7 @@ import org.springframework.stereotype.Component;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -440,13 +442,93 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D
}
@Override
public boolean applyNetworkACLs(Network config, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
return true;
public boolean applyNetworkACLs(Network network, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
if (!canHandle(network, Network.Service.NetworkACL)) {
return false;
}
List<NetrisNetworkRule> nsxDelNetworkRules = new ArrayList<>();
boolean success = true;
for (NetworkACLItem rule : rules) {
String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule);
NetrisNetworkRule networkRule = getNetrisNetworkRuleForAcl(rule, privatePort);
if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) {
success = success && netrisService.addFirewallRules(network, List.of(networkRule));
} else if (NetworkACLItem.State.Revoke == rule.getState()) {
nsxDelNetworkRules.add(networkRule);
}
}
if (!nsxDelNetworkRules.isEmpty()) {
success = netrisService.deleteFirewallRules(network, nsxDelNetworkRules);
if (!success) {
logger.warn("Not all firewall rules were successfully deleted");
}
}
return success;
}
private NetrisNetworkRule getNetrisNetworkRuleForAcl(NetworkACLItem rule, String privatePort) {
SDNProviderNetworkRule baseNetworkRule = new SDNProviderNetworkRule.Builder()
.setRuleId(rule.getId())
.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY"))
.setTrafficType(rule.getTrafficType().toString())
.setProtocol(rule.getProtocol().toUpperCase())
.setPublicPort(String.valueOf(rule.getSourcePortStart()))
.setPrivatePort(String.valueOf(privatePort))
.setIcmpCode(rule.getIcmpCode())
.setIcmpType(rule.getIcmpType())
.setService(Network.Service.NetworkACL)
.build();
return new NetrisNetworkRule.Builder()
.baseRule(baseNetworkRule)
.aclAction(transformActionValue(rule.getAction()))
.reason(rule.getReason())
.build();
}
protected List<String> transformCidrListValues(List<String> sourceCidrList) {
List<String> list = new ArrayList<>();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(sourceCidrList)) {
for (String cidr : sourceCidrList) {
if (cidr.equals("0.0.0.0/0")) {
list.add("ANY");
} else {
list.add(cidr);
}
}
}
return list;
}
protected NetrisNetworkRule.NetrisRuleAction transformActionValue(NetworkACLItem.Action action) {
if (action == NetworkACLItem.Action.Allow) {
return NetrisNetworkRule.NetrisRuleAction.PERMIT;
} else if (action == NetworkACLItem.Action.Deny) {
return NetrisNetworkRule.NetrisRuleAction.DENY;
}
String err = String.format("Unsupported action %s", action.toString());
logger.error(err);
throw new CloudRuntimeException(err);
}
@Override
public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
return false;
List<NetrisNetworkRule> aclRulesList = new ArrayList<>();
for (NetworkACLItem rule : networkACLItems) {
String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule);
aclRulesList.add(getNetrisNetworkRuleForAcl(rule, privatePort));
}
for (Network network: networks) {
netrisService.deleteFirewallRules(network, aclRulesList);
}
boolean success = true;
for (Network network : networks) {
for (NetrisNetworkRule aclRule : aclRulesList) {
success = success && netrisService.addFirewallRules(network, List.of(aclRule));
}
}
return success;
}
@Override
@ -470,12 +552,12 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D
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;
SDNProviderNetworkRule baseNetRule = networkRule.getBaseRule();
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);
netrisService.createPortForwardingRule(baseNetRule.getZoneId(), baseNetRule.getAccountId(), baseNetRule.getDomainId(),
vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, baseNetRule) :
netrisService.deletePortForwardingRule(baseNetRule.getZoneId(), baseNetRule.getAccountId(), baseNetRule.getDomainId(),
vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, baseNetRule);
}
private boolean applyPFRulesInternal(Network network, List<PortForwardingRule> rules) {
@ -492,20 +574,23 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D
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));
SDNProviderNetworkRule baseNetworkRule = new SDNProviderNetworkRule.Builder()
.setDomainId(netrisObject.getDomainId())
.setAccountId(netrisObject.getAccountId())
.setZoneId(netrisObject.getZoneId())
.setNetworkResourceId(netrisObject.getNetworkResourceId())
.setNetworkResourceName(netrisObject.getNetworkResourceName())
.setVpcResource(netrisObject.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();
NetrisNetworkRule networkRule = new NetrisNetworkRule.Builder().baseRule(baseNetworkRule).build();
if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) {
boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, networkRule, netrisObject, true);

View File

@ -35,16 +35,19 @@ import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.network.element.NetrisProviderVO;
import com.cloud.network.netris.NetrisService;
import com.cloud.network.vpc.Vpc;
import com.cloud.network.vpc.dao.VpcDao;
import io.netris.model.NatPostBody;
import org.apache.cloudstack.agent.api.CreateNetrisACLCommand;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressString;
import io.netris.model.NatPostBody;
import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand;
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.DeleteNetrisACLCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
@ -56,6 +59,7 @@ import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import com.cloud.network.netris.NetrisNetworkRule;
import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -77,6 +81,8 @@ public class NetrisServiceImpl implements NetrisService, Configurable {
@Inject
private NetworkDao networkDao;
@Inject
private VpcDao vpcDao;
@Inject
private AgentManager agentMgr;
@Inject
private PhysicalNetworkDao physicalNetworkDao;
@ -207,7 +213,9 @@ public class NetrisServiceImpl implements NetrisService, Configurable {
cmd.setNetrisTag(netrisProvider.getNetrisTag());
if (Objects.nonNull(networkId)) {
Ipv6GuestPrefixSubnetNetworkMapVO ipv6PrefixNetworkMapVO = ipv6PrefixNetworkMapDao.findByNetworkId(networkId);
cmd.setIpv6Cidr(ipv6PrefixNetworkMapVO.getSubnet());
if (Objects.nonNull(ipv6PrefixNetworkMapVO)) {
cmd.setIpv6Cidr(ipv6PrefixNetworkMapVO.getSubnet());
}
}
NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
return answer.getResult();
@ -343,6 +351,88 @@ public class NetrisServiceImpl implements NetrisService, Configurable {
}
@Override
public boolean addFirewallRules(Network network, List<NetrisNetworkRule> firewallRules) {
Long zoneId = network.getDataCenterId();
Long accountId = network.getAccountId();
Long domainId = network.getDomainId();
Long vpcId = network.getVpcId();
Long networkId = network.getId();
String vpcName = null;
Vpc vpc = null;
if (Objects.nonNull(vpcId)) {
vpc = vpcDao.findById(vpcId);
if (Objects.nonNull(vpc)) {
vpcName = vpc.getName();
}
}
String networkName = network.getName();
NetrisNetworkRule rule = firewallRules.get(0);
SDNProviderNetworkRule baseNetworkRule = rule.getBaseRule();
String trafficType = baseNetworkRule.getTrafficType().toUpperCase(Locale.ROOT);
String sourcePrefix;
String destinationPrefix;
if ("INGRESS".equals(trafficType)) {
sourcePrefix = baseNetworkRule.getSourceCidrList().get(0);
destinationPrefix = network.getCidr();
} else {
sourcePrefix = network.getCidr();
destinationPrefix = baseNetworkRule.getSourceCidrList().get(0);
}
String srcPort;
String dstPort;
if (baseNetworkRule.getPrivatePort().contains("-")) {
srcPort = baseNetworkRule.getPrivatePort().split("-")[0];
dstPort = baseNetworkRule.getPrivatePort().split("-")[1];
} else {
srcPort = dstPort = baseNetworkRule.getPrivatePort();
}
CreateNetrisACLCommand cmd = new CreateNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId,
vpcName, vpcId, Objects.nonNull(vpcId), rule.getAclAction().name().toLowerCase(Locale.ROOT), getPrefix(sourcePrefix), getPrefix(destinationPrefix),
"null".equals(srcPort) ? 1 : Integer.parseInt(srcPort),
"null".equals(dstPort) ? 65535 : Integer.parseInt(dstPort), baseNetworkRule.getProtocol());
String aclName = String.format("V%s-N%s-ACL%s", vpcId, networkId, rule.getBaseRule().getRuleId());
String netrisAclName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName);
cmd.setNetrisAclName(netrisAclName);
cmd.setReason(rule.getReason());
if ("ICMP".equals(baseNetworkRule.getProtocol())) {
cmd.setIcmpType(baseNetworkRule.getIcmpType());
}
NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
return answer.getResult();
}
private String getPrefix(String prefix) {
if ("ANY".equals(prefix)) {
return NetUtils.ALL_IP4_CIDRS;
}
return prefix;
}
@Override
public boolean deleteFirewallRules(Network network, List<NetrisNetworkRule> firewallRules) {
long zoneId = network.getDataCenterId();
Long accountId = network.getAccountId();
Long domainId = network.getDomainId();
String networkName = network.getName();
Long networkId = network.getId();
String vpcName = null;
Long vpcId = network.getVpcId();
if (Objects.nonNull(vpcId)) {
vpcName = vpcDao.findById(vpcId).getName();
}
DeleteNetrisACLCommand cmd = new DeleteNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId, Objects.nonNull(network.getVpcId()), vpcId, vpcName);
List<String> aclRuleNames = firewallRules.stream()
.map(rule -> {
String aclName = String.format("V%s-N%s-ACL%s", vpcId, networkId, rule.getBaseRule().getRuleId());
return NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName);
})
.collect(Collectors.toList());
cmd.setAclRuleNames(aclRuleNames);
NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
return answer.getResult();
}
public boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute) {
AddOrUpdateNetrisStaticRouteCommand cmd = new AddOrUpdateNetrisStaticRouteCommand(zoneId, accountId, domainId, networkResourceName, networkResourceId, isForVpc, prefix, nextHop, routeId, updateRoute);
NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);

View File

@ -20,15 +20,24 @@ import com.cloud.network.SDNProviderNetworkRule;
import java.util.List;
public class NsxNetworkRule extends SDNProviderNetworkRule {
public class NsxNetworkRule {
public enum NsxRuleAction {
ALLOW, DROP
}
private SDNProviderNetworkRule baseRule;
private List<NsxLoadBalancerMember> memberList;
private NsxRuleAction aclAction;
public SDNProviderNetworkRule getBaseRule() {
return baseRule;
}
public void setBaseRule(SDNProviderNetworkRule baseRule) {
this.baseRule = baseRule;
}
public List<NsxLoadBalancerMember> getMemberList() {
return memberList;
}

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.service;
import com.cloud.network.Network;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.nsx.NsxService;
import com.cloud.utils.exception.CloudRuntimeException;
import com.vmware.nsx.cluster.Status;
@ -1025,7 +1026,8 @@ public class NsxApiClient {
}
public void deleteDistributedFirewallRules(String segmentName, List<NsxNetworkRule> nsxRules) {
for(NsxNetworkRule rule : nsxRules) {
for(NsxNetworkRule nsxRule : nsxRules) {
SDNProviderNetworkRule rule = nsxRule.getBaseRule();
String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId());
String svcName = getServiceName(ruleId, rule.getPrivatePort(), rule.getProtocol(), rule.getIcmpType(), rule.getIcmpCode());
// delete rules
@ -1043,10 +1045,11 @@ public class NsxApiClient {
if (Objects.isNull(groupPath)) {
throw new CloudRuntimeException(String.format("Failed to find group for segment %s", segmentName));
}
for (NsxNetworkRule rule : nsxRules) {
for (NsxNetworkRule nsxRule : nsxRules) {
SDNProviderNetworkRule rule = nsxRule.getBaseRule();
String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId());
Rule ruleToAdd = new Rule.Builder()
.setAction(rule.getAclAction().toString())
.setAction(nsxRule.getAclAction().toString())
.setId(ruleId)
.setDisplayName(ruleId)
.setResourceType("SecurityPolicy")
@ -1060,7 +1063,7 @@ public class NsxApiClient {
return rules;
}
private List<String> getServicesListForDistributedFirewallRule(NsxNetworkRule rule, String segmentName) {
private List<String> getServicesListForDistributedFirewallRule(SDNProviderNetworkRule rule, String segmentName) {
List<String> services = List.of("ANY");
if (!rule.getProtocol().equalsIgnoreCase("all")) {
String ruleName = String.format("%s-R%s", segmentName, rule.getRuleId());
@ -1071,7 +1074,7 @@ public class NsxApiClient {
return services;
}
protected List<String> getGroupsForTraffic(NsxNetworkRule rule,
protected List<String> getGroupsForTraffic(SDNProviderNetworkRule rule,
String segmentName, boolean source) {
List<String> segmentGroup = List.of(String.format("%s/%s", GROUPS_PATH_PREFIX, segmentName));
List<String> sourceCidrList = rule.getSourceCidrList();

View File

@ -45,6 +45,7 @@ import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.VirtualRouterProvider;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
@ -563,27 +564,31 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
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));
SDNProviderNetworkRule networkRule = new SDNProviderNetworkRule.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();
NsxNetworkRule nsxNetworkRule = new NsxNetworkRule();
nsxNetworkRule.setBaseRule(networkRule);
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"))) {
logger.debug("Creating port forwarding rule on NSX for VM {} to ports {} - {}",
vm.getUuid(), rule.getDestinationPortStart(), rule.getDestinationPortEnd());
NsxAnswer answer = nsxService.createPortForwardRule(networkRule);
NsxAnswer answer = nsxService.createPortForwardRule(nsxNetworkRule);
boolean pfRuleResult = answer.getResult();
if (pfRuleResult && !answer.isObjectExistent()) {
logger.debug("Port forwarding rule {} created on NSX, adding detail on firewall rules details", rule.getId());
@ -600,7 +605,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
}
} else if (rule.getState() == FirewallRule.State.Revoke) {
if (ruleDetail == null || (ruleDetail != null && ruleDetail.getValue().equalsIgnoreCase("true"))) {
boolean pfRuleResult = nsxService.deletePortForwardRule(networkRule);
boolean pfRuleResult = nsxService.deletePortForwardRule(nsxNetworkRule);
if (pfRuleResult && ruleDetail != null) {
logger.debug("Updating firewall rule detail {} for rule {}, set to false", ruleDetail.getId(), rule.getId());
ruleDetail.setValue("false");
@ -678,20 +683,23 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
SDNProviderOpObject nsxObject = getNsxOpObject(network);
List<NsxLoadBalancerMember> lbMembers = getLoadBalancerMembers(loadBalancingRule);
SDNProviderNetworkRule baseNetRule = new SDNProviderNetworkRule.Builder()
.setDomainId(nsxObject.getDomainId())
.setAccountId(nsxObject.getAccountId())
.setZoneId(nsxObject.getZoneId())
.setNetworkResourceId(nsxObject.getNetworkResourceId())
.setNetworkResourceName(nsxObject.getNetworkResourceName())
.setVpcResource(nsxObject.isVpcResource())
.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.setBaseRule(baseNetRule);
networkRule.setMemberList(lbMembers);
if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(loadBalancingRule.getState())) {
result &= nsxService.createLbRule(networkRule);
@ -776,15 +784,17 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
private NsxNetworkRule getNsxNetworkRuleForAcl(NetworkACLItem rule, String privatePort) {
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);
SDNProviderNetworkRule networkRule = new SDNProviderNetworkRule.Builder()
.setRuleId(rule.getId())
.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY"))
.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.setBaseRule(networkRule);
nsxNetworkRule.setAclAction(transformActionValue(rule.getAction()));
return nsxNetworkRule;
}
@ -798,17 +808,19 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
List<NsxNetworkRule> nsxDelNetworkRules = new ArrayList<>();
for (FirewallRule rule : rules) {
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));
SDNProviderNetworkRule baseNetRule = new SDNProviderNetworkRule.Builder()
.setRuleId(rule.getId())
.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ?
transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY"))
.setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ?
transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY"))
.setIcmpCode(rule.getIcmpCode())
.setIcmpType(rule.getIcmpType())
.setPrivatePort(PortForwardingServiceProvider.getPrivatePortRange(rule))
.setTrafficType(rule.getTrafficType().toString())
.setService(Network.Service.Firewall)
.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)).build();
networkRule.setBaseRule(baseNetRule);
networkRule.setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW);
if (rule.getState() == FirewallRule.State.Add) {
nsxAddNetworkRules.add(networkRule);

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.service;
import com.cloud.network.IpAddress;
import com.cloud.network.Network;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.nsx.NsxService;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.Vpc;
@ -138,7 +139,8 @@ public class NsxServiceImpl implements NsxService, Configurable {
return result.getResult();
}
public NsxAnswer createPortForwardRule(NsxNetworkRule netRule) {
public NsxAnswer createPortForwardRule(NsxNetworkRule nsxNetRule) {
SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule();
// TODO: if port doesn't exist in default list of services, create a service entry
CreateNsxPortForwardRuleCommand createPortForwardCmd = new CreateNsxPortForwardRuleCommand(netRule.getDomainId(),
netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(),
@ -147,7 +149,8 @@ public class NsxServiceImpl implements NsxService, Configurable {
return nsxControllerUtils.sendNsxCommand(createPortForwardCmd, netRule.getZoneId());
}
public boolean deletePortForwardRule(NsxNetworkRule netRule) {
public boolean deletePortForwardRule(NsxNetworkRule nsxNetRule) {
SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule();
DeleteNsxNatRuleCommand deleteCmd = new DeleteNsxNatRuleCommand(netRule.getDomainId(),
netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(),
netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getVmId(), netRule.getRuleId(), netRule.getPrivatePort(), netRule.getProtocol());
@ -156,20 +159,22 @@ public class NsxServiceImpl implements NsxService, Configurable {
return result.getResult();
}
public boolean createLbRule(NsxNetworkRule netRule) {
public boolean createLbRule(NsxNetworkRule nsxNetRule) {
SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule();
CreateNsxLoadBalancerRuleCommand command = new CreateNsxLoadBalancerRuleCommand(netRule.getDomainId(),
netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(),
netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(),
netRule.getNetworkResourceName(), netRule.isVpcResource(), nsxNetRule.getMemberList(), netRule.getRuleId(),
netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getAlgorithm(), netRule.getProtocol());
command.setPublicIp(netRule.getPublicIp());
NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId());
return result.getResult();
}
public boolean deleteLbRule(NsxNetworkRule netRule) {
public boolean deleteLbRule(NsxNetworkRule nsxNetRule) {
SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule();
DeleteNsxLoadBalancerRuleCommand command = new DeleteNsxLoadBalancerRuleCommand(netRule.getDomainId(),
netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(),
netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(),
netRule.getNetworkResourceName(), netRule.isVpcResource(), nsxNetRule.getMemberList(), netRule.getRuleId(),
netRule.getVmId());
NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId());
return result.getResult();

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.service;
import com.cloud.network.Network;
import com.cloud.network.SDNProviderNetworkRule;
import com.vmware.nsx.cluster.Status;
import com.vmware.nsx.model.ClusterStatus;
import com.vmware.nsx.model.ControllerClusterStatus;
@ -24,7 +25,6 @@ import com.vmware.nsx_policy.infra.domains.Groups;
import com.vmware.nsx_policy.model.Group;
import com.vmware.nsx_policy.model.PathExpression;
import com.vmware.vapi.bindings.Service;
import org.apache.cloudstack.resource.NsxNetworkRule;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -73,7 +73,7 @@ public class NsxApiClientTest {
@Test
public void testGetGroupsForTrafficIngress() {
NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class);
SDNProviderNetworkRule rule = Mockito.mock(SDNProviderNetworkRule.class);
Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY"));
Mockito.when(rule.getTrafficType()).thenReturn("Ingress");
Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL);
@ -86,7 +86,7 @@ public class NsxApiClientTest {
@Test
public void testGetGroupsForTrafficEgress() {
NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class);
SDNProviderNetworkRule rule = Mockito.mock(SDNProviderNetworkRule.class);
Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY"));
Mockito.when(rule.getTrafficType()).thenReturn("Egress");
Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL);

View File

@ -17,10 +17,14 @@
package org.apache.cloudstack.service;
import com.cloud.network.IpAddress;
import com.cloud.network.Network;
import com.cloud.network.SDNProviderNetworkRule;
import com.cloud.network.netris.NetrisNetworkRule;
import com.cloud.network.netris.NetrisService;
import com.cloud.network.vpc.Vpc;
import java.util.List;
public class NetrisServiceMockTest implements NetrisService {
@Override
public boolean createIPAMAllocationsForZoneLevelPublicRanges(long zoneId) {
@ -77,6 +81,16 @@ public class NetrisServiceMockTest implements NetrisService {
return true;
}
@Override
public boolean addFirewallRules(Network network, List<NetrisNetworkRule> firewallRules) {
return true;
}
@Override
public boolean deleteFirewallRules(Network network, List<NetrisNetworkRule> firewallRules) {
return true;
}
@Override
public boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute) {
return true;