Browse Source

NSX Policy: patch security rules with ChildResourceReference

This change adds support for specifying ChildResourceReference entries
in NSX H-API transactions.
It also adds a method patch_entries to update security policy rules
specifying only individual rules to add.

This allows for adding rules to a security policy in a much faster way.

Change-Id: Ib2c9298b013a799a5363951855be6d16ba76d7a8
changes/55/815355/1
Salvatore Orlando 7 months ago committed by Salvatore Orlando
parent
commit
6437a44df5
  1. 78
      vmware_nsxlib/tests/unit/v3/policy/test_transaction.py
  2. 29
      vmware_nsxlib/v3/policy/core_resources.py
  3. 57
      vmware_nsxlib/v3/policy/transaction.py

78
vmware_nsxlib/tests/unit/v3/policy/test_transaction.py

@ -483,6 +483,84 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
def test_updating_security_policy_and_dfw_rules_no_child_rules(self):
return self._test_updating_security_policy_and_dfw_rules(False)
@mock.patch('vmware_nsxlib.v3.policy.core_defs.NsxPolicyApi.get')
def test_updating_security_policy_patch_rules(self, mock_get_api):
dfw_rule1 = {'id': 'rule_id1', 'action': 'ALLOW',
'display_name': 'rule1', 'description': None,
'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
'logged': False,
'destination_groups': ['destination_url'],
'source_groups': ['src_url'], 'resource_type': 'Rule',
'scope': None, 'sequence_number': None, 'tag': None,
'services': ['ANY']}
dfw_rule2 = {'id': 'rule_id2', 'action': 'DROP',
'display_name': 'rule2', 'description': None,
'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
'logged': False,
'destination_groups': ['destination_url'],
'source_groups': ['src_url'], 'resource_type': 'Rule',
'scope': None, 'sequence_number': None, 'tag': None,
'services': ['ANY']}
security_policy = {'id': 'security_policy_id1',
'display_name': 'security_policy',
'category': 'Application',
'resource_type': 'SecurityPolicy'}
domain = {'resource_type': 'Domain', 'id': 'domain1'}
domain_id = domain['id']
map_id = security_policy['id']
dfw_rule_entries = [self.policy_lib.comm_map.build_entry(
name=rule['display_name'],
domain_id=domain_id,
map_id=map_id,
entry_id=rule['id'],
source_groups=rule['source_groups'],
dest_groups=rule['destination_groups'],
ip_protocol=rule['ip_protocol'],
action=rule['action'],
direction=rule['direction']
) for rule in [dfw_rule1, dfw_rule2]]
def get_group_path(group_id, domain_id):
return '/infra/domains/' + domain_id + '/groups/' + group_id
for dfw_rule in [dfw_rule1, dfw_rule2]:
dfw_rule['destination_groups'] = [get_group_path(group_id,
domain_id)
for group_id in
dfw_rule['destination_groups']]
dfw_rule['source_groups'] = [get_group_path(group_id, domain_id)
for group_id in
dfw_rule['source_groups']]
security_policy_values = copy.deepcopy(security_policy)
security_policy_values.update({'rules':
copy.deepcopy([dfw_rule1, dfw_rule2])})
mock_get_api.return_value = security_policy_values
with trans.NsxPolicyTransaction():
self.policy_lib.comm_map.patch_entries(
domain_id=domain_id,
map_id=map_id,
entries=dfw_rule_entries,
)
child_security_policies = [{
'resource_type': 'ChildResourceReference',
'target_type': 'SecurityPolicy',
'id': security_policy['id'],
}]
child_rules = [{'resource_type': 'ChildRule', 'Rule': dfw_rule1},
{'resource_type': 'ChildRule', 'Rule': dfw_rule2}]
child_security_policies[0].update({'children': child_rules})
domain.update({'children': child_security_policies})
child_domains = [{
'resource_type': 'ChildDomain',
'Domain': domain
}]
expected_body = {'resource_type': 'Infra',
'children': child_domains}
self.assert_infra_patch_call(expected_body)
@mock.patch('vmware_nsxlib.v3.policy.core_defs.NsxPolicyApi.get')
def test_updating_security_policy_with_no_entries_set(self, mock_get_api):
dfw_rule1 = {'id': 'rule_id1', 'action': 'ALLOW',

29
vmware_nsxlib/v3/policy/core_resources.py

@ -3707,6 +3707,35 @@ class NsxPolicySecurityPolicyBaseApi(NsxPolicyResourceBase):
_update()
def patch_entries(self, domain_id, map_id, entries,
tenant=constants.POLICY_INFRA_TENANT):
# Specify that we want to use a childresourcerefence
map_def = self._init_parent_def(
domain_id=domain_id, map_id=map_id, tenant=tenant,
child_resource_ref=True)
@utils.retry_upon_exception(
exceptions.StaleRevision,
max_attempts=self.policy_api.client.max_attempts)
def _update():
transaction = trans.NsxPolicyTransaction.get_current()
if not transaction:
err_msg = ("patch_entries can only be used within "
"H-API transactions")
raise exceptions.ManagerException(
details=err_msg)
patch_entries = []
for entry in entries:
rule = entry.get_obj_dict()
LOG.debug("#### ADDING ENTRY: %s", entry)
patch_entries.append(
self.entry_def.adapt_from_rule_dict(
rule, domain_id, map_id))
self._create_or_store(map_def, patch_entries)
_update()
def update_entries_logged(self, domain_id, map_id, logged,
tenant=constants.POLICY_INFRA_TENANT):
"""Update all communication map entries logged flags"""

57
vmware_nsxlib/v3/policy/transaction.py

@ -16,6 +16,8 @@
import threading
from oslo_log import log
from vmware_nsxlib._i18n import _
from vmware_nsxlib.v3 import exceptions
@ -25,6 +27,9 @@ from vmware_nsxlib.v3.policy import core_defs
from vmware_nsxlib.v3 import utils
LOG = log.getLogger(__name__)
class NsxPolicyTransactionException(exceptions.NsxLibException):
message = _("Policy Transaction Error: %(msg)s")
@ -100,11 +105,19 @@ class NsxPolicyTransaction(object):
self.defs = sorted_defs
def _build_wrapper_dict(self, resource_class, node, delete=False):
wrapper_dict = {'resource_type': 'Child%s' % resource_class,
resource_class: node}
def _build_wrapper_dict(self, resource_class, node, delete=False,
child_resource_ref=False):
if child_resource_ref:
wrapper_dict = {'resource_type': 'ChildResourceReference',
'target_type': resource_class,
'id': node['id'],
'children': []}
else:
wrapper_dict = {'resource_type': 'Child%s' % resource_class,
resource_class: node}
if delete:
wrapper_dict.update({'marked_for_delete': True})
LOG.debug("### WRAPPER DICT:%s", wrapper_dict)
return wrapper_dict
def _find_parent_in_dict(self, d, resource_def, level=1):
@ -124,21 +137,26 @@ class NsxPolicyTransaction(object):
node = {'resource_type': resource_type,
'id': parent_id,
'children': []}
LOG.debug("#### UNEXPECTED: %s", resource_type)
return self._build_wrapper_dict(resource_class, node), node
# iterate over all objects in d, and look for resource type
for child in d:
parent = None
if (child.get('target_type') == resource_type and
child['resource_type'] == 'ChildResourceReference'):
parent = child
if resource_type in child and child[resource_type]:
parent = child[resource_type]
# If resource type matches, check for id
if parent['id'] == parent_id:
if is_leaf:
return parent
if 'children' not in parent:
parent['children'] = []
# If resource type matches, check for id
if parent and parent['id'] == parent_id:
if is_leaf:
return parent
if 'children' not in parent:
parent['children'] = []
return self._find_parent_in_dict(
parent['children'], resource_def, level + 1)
return self._find_parent_in_dict(
parent['children'], resource_def, level + 1)
# Parent not found - create a node for missing parent
wrapper, node = create_missing_node()
@ -162,6 +180,7 @@ class NsxPolicyTransaction(object):
url = top_def.get_resource_path()
body = {'resource_type': top_def.resource_type(),
'children': []}
# iterate over defs (except top level def)
for resource_def in self.defs[1:]:
parent_dict = None
@ -185,10 +204,18 @@ class NsxPolicyTransaction(object):
child_def = resource_def.mandatory_child_def
child_dict_key = child_def.get_last_section_dict_key
node[child_dict_key] = [child_def.get_obj_dict()]
parent_dict['children'].append(
self._build_wrapper_dict(resource_class,
node,
resource_def.get_delete()))
child_resource_ref = (
resource_def.has_attr('child_resource_ref') and
resource_def.get_attr('child_resource_ref'))
LOG.debug("#### BEFORE WRAP CALL")
LOG.debug("#### NODE XXX: %s", node)
LOG.debug("#### CHILD REF:%s", child_resource_ref)
meh = self._build_wrapper_dict(resource_class,
node,
resource_def.get_delete(),
child_resource_ref)
parent_dict['children'].append(meh)
if body:
headers = {'nsx-enable-partial-patch': 'true'}

Loading…
Cancel
Save