From 1cc6aefb62ce1baefe1283df0ba8ed81b2a8eb54 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Tue, 20 Mar 2018 09:51:09 +0200 Subject: [PATCH] Support NO_SNAT & NO_DNAT rules in NSX 2.2 Adding flag ro mark the support of new NAAT rules actions in version 2.2, and adding validation for this field on create & update. Change-Id: I4d99193caac6940911cc071016359a1361428967 --- vmware_nsxlib/tests/unit/v3/test_resources.py | 39 ++++++++++++++----- vmware_nsxlib/v3/__init__.py | 3 +- vmware_nsxlib/v3/core_resources.py | 17 ++++++++ vmware_nsxlib/v3/nsx_constants.py | 1 + 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/vmware_nsxlib/tests/unit/v3/test_resources.py b/vmware_nsxlib/tests/unit/v3/test_resources.py index 5ef18278..ea33dd45 100644 --- a/vmware_nsxlib/tests/unit/v3/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/test_resources.py @@ -660,9 +660,9 @@ class LogicalRouterTestCase(BaseTestResource): test_constants.FAKE_ROUTER_UUID, router_body=fake_router) self.assertEqual(test_constants.FAKE_ROUTER_FW_SEC_UUID, section_id) - def _test_nat_rule_create(self, nsx_version, add_bypas_arg): + def _test_nat_rule_create(self, nsx_version, add_bypas_arg=True, + action='SNAT', expect_failure=False): router = self.get_mocked_resource() - action = 'SNAT' translated_net = '1.1.1.1' priority = 10 @@ -679,11 +679,18 @@ class LogicalRouterTestCase(BaseTestResource): # Ignoring 'bypass_firewall' with version 1.1 with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", return_value=nsx_version): - router.add_nat_rule(test_constants.FAKE_ROUTER_UUID, - action=action, - translated_network=translated_net, - rule_priority=priority, - bypass_firewall=False) + try: + router.add_nat_rule(test_constants.FAKE_ROUTER_UUID, + action=action, + translated_network=translated_net, + rule_priority=priority, + bypass_firewall=False) + except exceptions.InvalidInput as e: + if expect_failure: + return + else: + self.fail("Failed to create NAT rule: %s", e) + test_client.assert_json_call( 'post', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules' % @@ -693,11 +700,25 @@ class LogicalRouterTestCase(BaseTestResource): def test_nat_rule_create_v1(self): # Ignoring 'bypass_firewall' with version 1.1 - self._test_nat_rule_create('1.1.0', False) + self._test_nat_rule_create('1.1.0', add_bypas_arg=False) def test_nat_rule_create_v2(self): # Sending 'bypass_firewall' with version 1.1 - self._test_nat_rule_create('2.0.0', True) + self._test_nat_rule_create('2.0.0') + + def test_nat_rule_create_v22_NO_DNAT(self): + # NO_DNAT is supported from 2.2 & up + self._test_nat_rule_create('2.2.0', action='NO_DNAT') + + def test_nat_rule_create_v2_NO_DNAT(self): + # NO_DNAT is supported from 2.2 & up + self._test_nat_rule_create('2.0.0', action='NO_DNAT', + expect_failure=True) + + def test_nat_rule_create_invalid(self): + # NO_DNAT is supported from 2.2 & up + self._test_nat_rule_create('2.0.0', action='INVALID', + expect_failure=True) def test_nat_rule_list(self): router = self.get_mocked_resource() diff --git a/vmware_nsxlib/v3/__init__.py b/vmware_nsxlib/v3/__init__.py index 99fc5134..6efc594e 100644 --- a/vmware_nsxlib/v3/__init__.py +++ b/vmware_nsxlib/v3/__init__.py @@ -322,7 +322,8 @@ class NsxLib(NsxLibBase): feature == nsx_constants.FEATURE_ON_BEHALF_OF or feature == nsx_constants.FEATURE_RATE_LIMIT or feature == nsx_constants.FEATURE_TRUNK_VLAN or - feature == nsx_constants.FEATURE_ROUTER_TRANSPORT_ZONE): + feature == nsx_constants.FEATURE_ROUTER_TRANSPORT_ZONE or + feature == nsx_constants.FEATURE_NO_DNAT_NO_SNAT): return True if (version.LooseVersion(self.get_version()) >= diff --git a/vmware_nsxlib/v3/core_resources.py b/vmware_nsxlib/v3/core_resources.py index 109eb1df..f81d80e6 100644 --- a/vmware_nsxlib/v3/core_resources.py +++ b/vmware_nsxlib/v3/core_resources.py @@ -512,6 +512,20 @@ class NsxLibLogicalRouter(utils.NsxLibApiBase): 'res': resource, 'values': kwargs}) + def _validate_nat_rule_action(self, action): + if not action: + return + if action in ['SNAT', 'DNAT', 'NO_NAT', 'REFLEXIVE']: + # legal values for all NSX versions + return + if (action not in ['NO_SNAT', 'NO_DNAT'] or ( + self.nsxlib and not self.nsxlib.feature_supported( + nsx_constants.FEATURE_NO_DNAT_NO_SNAT))): + raise exceptions.InvalidInput( + operation="Create/Update NAT rule", + arg_val=action, + arg_name='action') + def add_nat_rule(self, logical_router_id, action, translated_network, source_net=None, dest_net=None, enabled=True, rule_priority=None, @@ -519,6 +533,7 @@ class NsxLibLogicalRouter(utils.NsxLibApiBase): match_resource_type=None, bypass_firewall=True, tags=None): + self._validate_nat_rule_action(action) resource = 'logical-routers/%s/nat/rules' % logical_router_id body = {'action': action, 'enabled': enabled, @@ -595,6 +610,8 @@ class NsxLibLogicalRouter(utils.NsxLibApiBase): return self.client.list(resource) def update_nat_rule(self, logical_router_id, nat_rule_id, **kwargs): + if 'action' in kwargs: + self._validate_nat_rule_action(kwargs['action']) resource = 'logical-routers/%s/nat/rules/%s' % ( logical_router_id, nat_rule_id) return self._update_resource(resource, kwargs, retry=True) diff --git a/vmware_nsxlib/v3/nsx_constants.py b/vmware_nsxlib/v3/nsx_constants.py index e1b6fc83..8c2ab30b 100644 --- a/vmware_nsxlib/v3/nsx_constants.py +++ b/vmware_nsxlib/v3/nsx_constants.py @@ -141,3 +141,4 @@ FEATURE_IPSEC_VPN = 'IPSec VPN' FEATURE_ON_BEHALF_OF = 'On Behalf Of' FEATURE_TRUNK_VLAN = 'Trunk Vlan' FEATURE_ROUTER_TRANSPORT_ZONE = 'Router Transport Zone' +FEATURE_NO_DNAT_NO_SNAT = 'No DNAT/No SNAT'