NSX: Add support to re-order ACL rules (NSX FW rules) (#14)

* [WIP] NSX: Add support to re-order ACL rules (NSX FW rules)

* fix reordering of acl rules on all networks that it is associated to

* clean up and attempt test fix

* Fix tests

* Remove unused import

* tweak reorder logic

---------

Co-authored-by: nvazquez <nicovazquez90@gmail.com>
This commit is contained in:
Pearl Dsilva 2024-02-06 14:50:11 -05:00 committed by nvazquez
parent 09636cfcc8
commit 8e3bb7e612
No known key found for this signature in database
GPG Key ID: 656E1BCC8CB54F84
9 changed files with 84 additions and 23 deletions

View File

@ -21,6 +21,7 @@ import java.util.List;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.network.vpc.NetworkACLItem;
import com.cloud.network.vpc.Vpc;
public interface NetworkACLServiceProvider extends NetworkElement {
@ -32,4 +33,6 @@ public interface NetworkACLServiceProvider extends NetworkElement {
*/
boolean applyNetworkACLs(Network config, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException;
boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems);
}

View File

@ -19,6 +19,7 @@ package com.cloud.network.vpc;
import java.util.List;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.network.dao.NetworkVO;
public interface NetworkACLManager {
@ -91,4 +92,6 @@ public interface NetworkACLManager {
boolean revokeACLItemsForPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException;
boolean applyACLToPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException;
boolean reorderAclRules(VpcVO vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems);
}

View File

@ -700,6 +700,11 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter {
return true;
}
@Override
public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
return true;
}
@Override
public boolean applyFWRules(Network network,
List<? extends FirewallRule> rules)

View File

@ -185,6 +185,11 @@ public class ContrailVpcElementImpl extends ContrailElementImpl implements Netwo
return true;
}
@Override
public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
return true;
}
@Override
public boolean applyACLItemsToPrivateGw(PrivateGateway privateGateway,
List<? extends NetworkACLItem> rules)

View File

@ -112,7 +112,6 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -712,18 +711,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
boolean success = true;
for (NetworkACLItem rule : rules) {
String privatePort = getPrivatePortRangeForACLRule(rule);
NsxNetworkRule networkRule = 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 networkRule = getNsxNetworkRuleForAcl(rule, privatePort);
if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) {
success = success && nsxService.addFirewallRules(network, List.of(networkRule));
} else if (NetworkACLItem.State.Revoke == rule.getState()) {
@ -740,9 +728,38 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns
return success;
}
private void reorderRules(List<? extends NetworkACLItem> rules) {
rules.sort((Comparator) (r1, r2) -> ((NetworkACLItem) r2).getNumber() - ((NetworkACLItem) r1).getNumber());
@Override
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);
aclRulesList.add(getNsxNetworkRuleForAcl(rule, privatePort));
}
for (Network network: networks) {
nsxService.deleteFirewallRules(network, aclRulesList);
}
boolean success = true;
for (Network network : networks) {
for (NsxNetworkRule aclRule : aclRulesList) {
success = success && nsxService.addFirewallRules(network, List.of(aclRule));
}
}
return success;
}
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();
}
@Override
public boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException {

View File

@ -531,6 +531,11 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc
return result;
}
@Override
public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
return true;
}
@Override
protected Type getVirtualRouterProvider() {
return Type.VPCVirtualRouter;

View File

@ -370,6 +370,20 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana
return applyACLToPrivateGw(gateway, rules);
}
@Override
public boolean reorderAclRules(VpcVO vpc, List<? extends Network> networks, List<? extends NetworkACLItem> networkACLItems) {
List<NetworkACLServiceProvider> nsxElements = new ArrayList<>();
nsxElements.add((NetworkACLServiceProvider) _ntwkModel.getElementImplementingProvider(Network.Provider.Nsx.getName()));
try {
for (final NetworkACLServiceProvider provider : nsxElements) {
return provider.reorderAclRules(vpc, networks, networkACLItems);
}
} catch (final Exception ex) {
s_logger.debug("Failed to reorder ACLs on NSX due to: " + ex.getLocalizedMessage());
}
return false;
}
private boolean applyACLToPrivateGw(final PrivateGateway gateway, final List<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
List<VpcProvider> vpcElements = new ArrayList<VpcProvider>();
vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Network.Provider.VPCVirtualRouter.getName()));

View File

@ -993,14 +993,26 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
NetworkACLVO lockedAcl = _networkACLDao.acquireInLockTable(ruleBeingMoved.getAclId());
List<NetworkACLItemVO> allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId());
validateAclConsistency(moveNetworkAclItemCmd, lockedAcl, allAclRules);
NetworkACLItem networkACLItem = null;
if (previousRule == null) {
return moveRuleToTheTop(ruleBeingMoved, allAclRules);
networkACLItem = moveRuleToTheTop(ruleBeingMoved, allAclRules);
} else if (nextRule == null) {
networkACLItem = moveRuleToTheBottom(ruleBeingMoved, allAclRules);
} else {
networkACLItem = moveRuleBetweenAclRules(ruleBeingMoved, allAclRules, previousRule, nextRule);
}
if (nextRule == null) {
return moveRuleToTheBottom(ruleBeingMoved, allAclRules);
VpcVO vpc = _vpcDao.findById(lockedAcl.getVpcId());
if (Objects.isNull(vpc)) {
return networkACLItem;
}
return moveRuleBetweenAclRules(ruleBeingMoved, allAclRules, previousRule, nextRule);
final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId());
final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId());
List<NetworkVO> networks = _networkDao.listByAclId(lockedAcl.getId());
if (Objects.nonNull(nsxProvider) && !networks.isEmpty()) {
allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId());
_networkAclMgr.reorderAclRules(vpc, networks, allAclRules);
}
return networkACLItem;
} finally {
_networkACLDao.releaseFromLockTable(ruleBeingMoved.getAclId());
}

View File

@ -34,7 +34,6 @@ import java.util.Map;
import com.cloud.dc.DataCenter;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.network.dao.NsxProviderDao;
import com.cloud.network.element.NsxProviderVO;
import com.cloud.network.vpc.dao.VpcDao;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ServerApiException;
@ -138,8 +137,6 @@ public class NetworkACLServiceImplTest {
private VpcVO vpcVOMock;
@Mock
DataCenter dataCenterVO;
@Mock
NsxProviderVO nsxProviderVO;
@Mock
private Account accountMock;