diff --git a/vmware_nsxlib/tests/unit/v3/policy/test_transaction.py b/vmware_nsxlib/tests/unit/v3/policy/test_transaction.py index 67fb387b..091ca9b1 100644 --- a/vmware_nsxlib/tests/unit/v3/policy/test_transaction.py +++ b/vmware_nsxlib/tests/unit/v3/policy/test_transaction.py @@ -21,6 +21,7 @@ import mock from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase from vmware_nsxlib.tests.unit.v3.policy import policy_testcase from vmware_nsxlib.v3 import policy +from vmware_nsxlib.v3.policy import constants from vmware_nsxlib.v3.policy import transaction as trans @@ -251,6 +252,92 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi): self.assert_infra_patch_call(expected_body) + def test_tier1_nat_rules_create(self): + tier1_id = 'tier1-1' + nat_rule_id1 = 'nat1' + nat_rule_id2 = 'nat2' + + nat_rule1 = {"action": constants.NAT_ACTION_SNAT, + "display_name": "snat rule", + "id": nat_rule_id1, + "resource_type": "PolicyNatRule"} + nat_rule2 = {"action": constants.NAT_ACTION_DNAT, + "display_name": "dnat rule", + "id": nat_rule_id2, + "resource_type": "PolicyNatRule"} + + policy_nat = {"id": "USER", + "resource_type": "PolicyNat", + "children": [ + {"PolicyNatRule": nat_rule1, + "resource_type": "ChildPolicyNatRule"}, + {"PolicyNatRule": nat_rule2, + "resource_type": "ChildPolicyNatRule"}]} + tier1_dict = {"id": tier1_id, + "resource_type": "Tier1", + "children": [{"PolicyNat": policy_nat, + "resource_type": "ChildPolicyNat"}]} + + with trans.NsxPolicyTransaction(): + self.policy_lib.tier1_nat_rule.create_or_overwrite( + 'snat rule', + tier1_id, + nat_rule_id=nat_rule_id1, + action=constants.NAT_ACTION_SNAT) + + self.policy_lib.tier1_nat_rule.create_or_overwrite( + 'dnat rule', + tier1_id, + nat_rule_id=nat_rule_id2, + action=constants.NAT_ACTION_DNAT) + + expected_body = {"resource_type": "Infra", + "children": [{"Tier1": tier1_dict, + "resource_type": "ChildTier1"}]} + + self.assert_infra_patch_call(expected_body) + + def test_tier1_nat_rules_delete(self): + tier1_id = 'tier1-1' + nat_rule_id1 = 'nat1' + nat_rule_id2 = 'nat2' + + nat_rule1 = {"action": constants.NAT_ACTION_DNAT, + "id": nat_rule_id1, + "resource_type": "PolicyNatRule"} + nat_rule2 = {"action": constants.NAT_ACTION_DNAT, + "id": nat_rule_id2, + "resource_type": "PolicyNatRule"} + + policy_nat = {"id": "USER", + "resource_type": "PolicyNat", + "children": [ + {"PolicyNatRule": nat_rule1, + "marked_for_delete": True, + "resource_type": "ChildPolicyNatRule"}, + {"PolicyNatRule": nat_rule2, + "marked_for_delete": True, + "resource_type": "ChildPolicyNatRule"}]} + tier1_dict = {"id": tier1_id, + "resource_type": "Tier1", + "children": [{"PolicyNat": policy_nat, + "resource_type": "ChildPolicyNat"}]} + + with trans.NsxPolicyTransaction(): + self.policy_lib.tier1_nat_rule.delete( + tier1_id, + nat_rule_id=nat_rule_id1) + + self.policy_lib.tier1_nat_rule.delete( + tier1_id, + nat_rule_id=nat_rule_id2) + + expected_body = {"resource_type": "Infra", + "children": [{"Tier1": tier1_dict, + "resource_type": "ChildTier1"}]} + + self.assert_infra_patch_call(expected_body) + def test_creating_security_policy_and_dfw_rules(self): dfw_rule = {'id': 'rule_id1', 'action': 'ALLOW', 'display_name': 'rule1', 'description': None, diff --git a/vmware_nsxlib/v3/policy/core_defs.py b/vmware_nsxlib/v3/policy/core_defs.py index eb584d68..1303e537 100644 --- a/vmware_nsxlib/v3/policy/core_defs.py +++ b/vmware_nsxlib/v3/policy/core_defs.py @@ -272,6 +272,9 @@ class ResourceDef(object): if key not in meta] return len(body_args) == 0 + def set_default_mandatory_vals(self): + pass + class TenantDef(ResourceDef): @property @@ -583,6 +586,25 @@ class RouterNatRule(ResourceDef): 'enabled']) return body + def set_default_mandatory_vals(self): + if not self.has_attr('action'): + self.attrs['action'] = constants.NAT_ACTION_DNAT + + +class Tier1NatDef(RouterDef): + + @property + def path_pattern(self): + return TIER1S_PATH_PATTERN + "%s/nat" + + @property + def path_ids(self): + return ('tenant', 'tier1_id') + + @staticmethod + def resource_type(): + return 'PolicyNat' + class Tier1NatRule(RouterNatRule): @@ -595,7 +617,7 @@ class Tier1NatRule(RouterNatRule): return ('tenant', 'tier1_id', 'nat_id', 'nat_rule_id') def path_defs(self): - return (TenantDef, Tier1Def) + return (TenantDef, Tier1Def, Tier1NatDef) class RouteAdvertisementRule(object): @@ -666,6 +688,21 @@ class Tier0StaticRoute(RouterStaticRoute): return (TenantDef, Tier0Def) +class Tier0NatDef(RouterDef): + + @property + def path_pattern(self): + return TIER0S_PATH_PATTERN + "%s/nat" + + @property + def path_ids(self): + return ('tenant', 'tier0_id') + + @staticmethod + def resource_type(): + return 'PolicyNat' + + class Tier0NatRule(RouterNatRule): @property @@ -677,7 +714,7 @@ class Tier0NatRule(RouterNatRule): return ('tenant', 'tier0_id', 'nat_id', 'nat_rule_id') def path_defs(self): - return (TenantDef, Tier0Def) + return (TenantDef, Tier0Def, Tier0NatDef) class Subnet(object): diff --git a/vmware_nsxlib/v3/policy/core_resources.py b/vmware_nsxlib/v3/policy/core_resources.py index 653a6498..e924918c 100644 --- a/vmware_nsxlib/v3/policy/core_resources.py +++ b/vmware_nsxlib/v3/policy/core_resources.py @@ -370,6 +370,20 @@ class NsxPolicyResourceBase(object): _do_create_with_retry() + def _delete_or_store(self, policy_def): + transaction = trans.NsxPolicyTransaction.get_current() + if transaction: + # Mark this resource is about to be deleted + policy_def.set_delete() + # Set some mandatory default values to avoid failure + # TODO(asarfaty): This can be removed once platform bug is fixed + policy_def.set_default_mandatory_vals() + # Store this def for batch apply for this transaction + transaction.store_def(policy_def, self.policy_api.client) + else: + # No transaction - apply now + self.policy_api.delete(policy_def) + class NsxPolicyDomainApi(NsxPolicyResourceBase): """NSX Policy Domain.""" @@ -1645,7 +1659,7 @@ class NsxPolicyTier1NatRuleApi(NsxPolicyResourceBase): tenant=constants.POLICY_INFRA_TENANT): nat_rule_def = self.entry_def(tier1_id=tier1_id, nat_id=nat_id, nat_rule_id=nat_rule_id, tenant=tenant) - self.policy_api.delete(nat_rule_def) + self._delete_or_store(nat_rule_def) def get(self, tier1_id, nat_rule_id, nat_id=DEFAULT_NAT_ID, tenant=constants.POLICY_INFRA_TENANT):