From e42ca6002f8ca83c53fdba4c066cbe956d18e60d Mon Sep 17 00:00:00 2001 From: Shih-Hao Li Date: Fri, 12 Apr 2019 16:49:02 -0700 Subject: [PATCH] Enhance updating a group and security policy - Allow updating a group and conditions in a single request - Allow updating a security policy with entries in a single request Change-Id: Ifb643365a0072e4b7094d09b0a632a2e3a1306b0 (cherry picked from commit e55f95e2904454ee782461438d9e790659f44956) --- .../tests/unit/v3/policy/test_resources.py | 99 ++++++++++++++++--- vmware_nsxlib/v3/policy/core_resources.py | 51 ++++++++-- 2 files changed, 128 insertions(+), 22 deletions(-) diff --git a/vmware_nsxlib/tests/unit/v3/policy/test_resources.py b/vmware_nsxlib/tests/unit/v3/policy/test_resources.py index b4ed0312..f9f1dc03 100644 --- a/vmware_nsxlib/tests/unit/v3/policy/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/policy/test_resources.py @@ -510,6 +510,54 @@ class TestPolicyGroup(NsxPolicyLibTestCase): self.assert_called_with_def( update_call, expected_def) + def test_update_with_conditions(self): + domain_id = '111' + group_id = '222' + name = 'name' + new_name = 'new name' + description = 'desc' + new_description = 'new desc' + + cond_val1 = '123' + cond_val2 = '456' + cond_op = constants.CONDITION_OP_EQUALS + cond_member_type = constants.CONDITION_MEMBER_VM + cond_key = constants.CONDITION_KEY_TAG + cond1_def = core_defs.Condition(value=cond_val1, + key=cond_key, + operator=cond_op, + member_type=cond_member_type) + cond2_def = core_defs.Condition(value=cond_val2, + key=cond_key, + operator=cond_op, + member_type=cond_member_type) + original_group = { + 'id': group_id, + 'resource_type': 'Group', + 'display_name': name, + 'description': description, + 'expression': [cond1_def.get_obj_dict()]} + updated_group = { + 'id': group_id, + 'resource_type': 'Group', + 'display_name': new_name, + 'description': new_description, + 'expression': [cond2_def.get_obj_dict()]} + group_def = core_defs.GroupDef( + domain_id=domain_id, + group_id=group_id, + tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, "get", + return_value=original_group),\ + mock.patch.object(self.policy_api.client, + "update") as update_call: + self.resourceApi.update_with_conditions( + domain_id, group_id, name=new_name, + description=new_description, + conditions=[cond2_def], tenant=TEST_TENANT) + update_call.assert_called_once_with( + group_def.get_resource_path(), updated_group) + def test_unset(self): domain_id = '111' group_id = '222' @@ -1817,6 +1865,17 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): self.assert_called_with_def(update_call, entry_def) def test_update_entries(self): + domain_id = '111' + map_id = '222' + entries = "fake_entries" + with mock.patch.object(self.resourceApi, + "update_with_entries") as update_call: + self.resourceApi.update_entries( + domain_id, map_id, entries, tenant=TEST_TENANT) + update_call.assert_called_once_with( + domain_id, map_id, entries, tenant=TEST_TENANT) + + def test_update_with_entries(self): domain_id = '111' map_id = '222' entry1_id = 'entry1' @@ -1834,18 +1893,28 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): entry_id=entry2_id, scope=['scope2'], tenant=TEST_TENANT) - original_map = {'rules': [ - {'id': entry1_id, 'resource_type': 'Rule', - 'dsiplay_name': 'name1', 'scope': ['scope1']}, - {'id': entry2_id, 'resource_type': 'Rule', - 'display_name': 'name2', 'scope': ['scope2']}, - {'id': entry3_id, 'resource_type': 'Rule', - 'display_name': 'name3', 'scope': ['scope3']}]} - updated_map = {'rules': [ - {'id': entry1_id, 'resource_type': 'Rule', - 'dsiplay_name': 'name1', 'scope': ['new_scope1']}, - {'id': entry2_id, 'resource_type': 'Rule', - 'display_name': 'name2', 'scope': ['scope2']}]} + original_map = { + 'id': map_id, + 'resource_type': self.resource_type, + 'category': constants.CATEGORY_APPLICATION, + 'display_name': 'map_name', + 'rules': [ + {'id': entry1_id, 'resource_type': 'Rule', + 'dsiplay_name': 'name1', 'scope': ['scope1']}, + {'id': entry2_id, 'resource_type': 'Rule', + 'display_name': 'name2', 'scope': ['scope2']}, + {'id': entry3_id, 'resource_type': 'Rule', + 'display_name': 'name3', 'scope': ['scope3']}]} + updated_map = { + 'id': map_id, + 'resource_type': self.resource_type, + 'category': constants.CATEGORY_APPLICATION, + 'display_name': 'new_map_name', + 'rules': [ + {'id': entry1_id, 'resource_type': 'Rule', + 'dsiplay_name': 'name1', 'scope': ['new_scope1']}, + {'id': entry2_id, 'resource_type': 'Rule', + 'display_name': 'name2', 'scope': ['scope2']}]} map_def = self.mapDef( domain_id=domain_id, map_id=map_id, @@ -1854,9 +1923,9 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): return_value=original_map),\ mock.patch.object(self.policy_api.client, "update") as update_call: - self.resourceApi.update_entries( - domain_id, map_id, [entry1, entry2], - tenant=TEST_TENANT) + self.resourceApi.update_with_entries( + domain_id, map_id, entries=[entry1, entry2], + name='new_map_name', tenant=TEST_TENANT) update_call.assert_called_once_with( map_def.get_resource_path(), updated_map) diff --git a/vmware_nsxlib/v3/policy/core_resources.py b/vmware_nsxlib/v3/policy/core_resources.py index 002ba080..9971b225 100644 --- a/vmware_nsxlib/v3/policy/core_resources.py +++ b/vmware_nsxlib/v3/policy/core_resources.py @@ -455,6 +455,32 @@ class NsxPolicyGroupApi(NsxPolicyResourceBase): tags=tags, tenant=tenant) + def update_with_conditions( + self, domain_id, group_id, + name=IGNORE, description=IGNORE, conditions=IGNORE, + tags=IGNORE, tenant=constants.POLICY_INFRA_TENANT): + group_def = self._init_def(domain_id=domain_id, + group_id=group_id, + name=name, + description=description, + conditions=conditions, + tags=tags, + tenant=tenant) + group_path = group_def.get_resource_path() + + @utils.retry_upon_exception( + exceptions.StaleRevision, + max_attempts=self.policy_api.client.max_attempts) + def _update(): + # Get the current data of group + group = self.policy_api.get(group_def) + group_def.set_obj_dict(group) + body = group_def.get_obj_dict() + # Update the entire group at the NSX + self.policy_api.client.update(group_path, body) + + _update() + def get_realized_state(self, domain_id, group_id, entity_type=None, tenant=constants.POLICY_INFRA_TENANT, realization_info=None): @@ -2857,10 +2883,18 @@ class NsxPolicySecurityPolicyBaseApi(NsxPolicyResourceBase): def update_entries(self, domain_id, map_id, entries, tenant=constants.POLICY_INFRA_TENANT): - map_def = self.parent_entry_def( - domain_id=domain_id, - map_id=map_id, - tenant=tenant) + self.update_with_entries(domain_id, map_id, entries, tenant=tenant) + + def update_with_entries(self, domain_id, map_id, entries=IGNORE, + name=IGNORE, description=IGNORE, + category=constants.CATEGORY_APPLICATION, + tags=IGNORE, map_sequence_number=IGNORE, + tenant=constants.POLICY_INFRA_TENANT): + map_def = self._init_parent_def( + domain_id=domain_id, map_id=map_id, + tenant=tenant, name=name, description=description, + category=category, tags=tags, + map_sequence_number=map_sequence_number) map_path = map_def.get_resource_path() def _overwrite_entries(old_entries, new_entries): @@ -2883,11 +2917,14 @@ class NsxPolicySecurityPolicyBaseApi(NsxPolicyResourceBase): exceptions.StaleRevision, max_attempts=self.policy_api.client.max_attempts) def _update(): - # Get the current data of communication map & its' entries + # Get the current data of communication map & its entries comm_map = self.policy_api.get(map_def) - comm_map['rules'] = _overwrite_entries(comm_map['rules'], entries) + map_def.set_obj_dict(comm_map) + body = map_def.get_obj_dict() + if entries != IGNORE: + body['rules'] = _overwrite_entries(comm_map['rules'], entries) # Update the entire map at the NSX - self.policy_api.client.update(map_path, comm_map) + self.policy_api.client.update(map_path, body) _update()