Enhance support for policy transaction

Add support for non first level objects, such as segment ports

Change-Id: I55f7f7f1921f7ff9c57adb93355943ffc7a9c542
This commit is contained in:
Anna Khmelnitsky
2019-01-17 09:06:08 -08:00
parent d8943d19c8
commit a7af647090
2 changed files with 120 additions and 15 deletions

View File

@@ -158,3 +158,91 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
'IpAddressPool': pool}]} 'IpAddressPool': pool}]}
self.assert_infra_patch_call(expected_body) self.assert_infra_patch_call(expected_body)
def test_groups_only(self):
g1 = {'resource_type': 'Group', 'id': 'group1',
'display_name': 'g1',
'description': 'first group'}
g2 = {'resource_type': 'Group', 'id': 'group2',
'description': 'second group',
'display_name': 'g2'}
d1 = {'resource_type': 'Domain', 'id': 'domain1'}
d2 = {'resource_type': 'Domain', 'id': 'domain2'}
with trans.NsxPolicyTransaction():
for d in (d1, d2):
d['children'] = []
for g in (g1, g2):
self.policy_lib.group.create_or_overwrite(
g['display_name'],
d['id'],
g['id'],
g['description'])
d['children'].append({'resource_type': 'ChildGroup',
'Group': g})
expected_body = {'resource_type': 'Infra',
'children': [{'resource_type': 'ChildDomain',
'Domain': d1},
{'resource_type': 'ChildDomain',
'Domain': d2}]}
self.assert_infra_patch_call(expected_body)
def test_segment_ports(self):
port1 = {'id': 'port_on_seg1',
'resource_type': 'SegmentPort',
'display_name': 'port_on_seg1',
'attachment': {'type': 'VIF',
'app_id': 'app1',
'traffic_tag': 5}
}
port2 = {'id': 'port1_on_seg2',
'resource_type': 'SegmentPort',
'display_name': 'port_on_seg2',
'attachment': {'type': 'CHILD',
'app_id': 'app2',
'traffic_tag': None}
}
seg1 = {'id': 'seg1',
'resource_type': 'Segment',
'children': [{'resource_type': 'ChildSegmentPort',
'SegmentPort': port1}]}
seg2 = {'id': 'seg2',
'resource_type': 'Segment',
'children': [{'resource_type': 'ChildSegmentPort',
'SegmentPort': port2}]}
with trans.NsxPolicyTransaction():
self.policy_lib.segment_port.create_or_overwrite(
port1['display_name'],
seg1['id'],
port1['id'],
attachment_type=port1['attachment']['type'],
app_id=port1['attachment']['app_id'],
traffic_tag=port1['attachment']['traffic_tag'])
self.policy_lib.segment_port.create_or_overwrite(
port2['display_name'],
seg2['id'],
port2['id'],
attachment_type=port2['attachment']['type'],
app_id=port2['attachment']['app_id'],
traffic_tag=port2['attachment']['traffic_tag'])
expected_body = {'resource_type': 'Infra',
'children': [{'resource_type': 'ChildSegment',
'Segment': seg1},
{'resource_type': 'ChildSegment',
'Segment': seg2}]}
self.assert_infra_patch_call(expected_body)

View File

@@ -96,15 +96,28 @@ class NsxPolicyTransaction(object):
self.defs = sorted_defs self.defs = sorted_defs
def _build_wrapper_dict(self, resource_class, node):
return {'resource_type': 'Child%s' % resource_class,
resource_class: node}
def _find_parent_in_dict(self, d, resource_def, level=1): def _find_parent_in_dict(self, d, resource_def, level=1):
if len(resource_def.path_defs()) <= level: if len(resource_def.path_defs()) <= level:
return return
parent_type = resource_def.path_defs()[level] parent_type = resource_def.path_defs()[level]
is_leaf = (level + 1 == len(resource_def.path_defs())) is_leaf = (level + 1 == len(resource_def.path_defs()))
resource_type = parent_type.resource_type() resource_type = parent_type.resource_type()
resource_class = parent_type.resource_class()
parent_id = resource_def.get_attr(resource_def.path_ids[level]) parent_id = resource_def.get_attr(resource_def.path_ids[level])
def create_missing_node():
node = {'resource_type': resource_type,
'id': parent_id,
'children': []}
return self._build_wrapper_dict(resource_class, node), node
# iterate over all objects in d, and look for resource type # iterate over all objects in d, and look for resource type
for child in d: for child in d:
if resource_type in child and child[resource_type]: if resource_type in child and child[resource_type]:
@@ -113,17 +126,20 @@ class NsxPolicyTransaction(object):
if parent['id'] == parent_id: if parent['id'] == parent_id:
if is_leaf: if is_leaf:
return parent return parent
if 'children' in parent: if 'children' not in parent:
return self._find_parent_in_dict( parent['children'] = []
parent['children'], resource_def, level + 1)
# Parent not found - for now, raise an exception return self._find_parent_in_dict(
# Support for this will come later parent['children'], resource_def, level + 1)
# TODO(annak): remove this when missing parent body is
# created on demand # Parent not found - create a node for missing parent
raise NsxPolicyTransactionException( wrapper, node = create_missing_node()
"Transactional create is supported for infra level" d.append(wrapper)
" objects and their children") if is_leaf:
# This is the last parent that needs creation
return node
return self._find_parent_in_dict(node['children'], resource_def,
level + 1)
def apply_defs(self): def apply_defs(self):
# TODO(annak): find longest common URL, for now always # TODO(annak): find longest common URL, for now always
@@ -136,7 +152,8 @@ class NsxPolicyTransaction(object):
top_def = self.defs[0] top_def = self.defs[0]
url = top_def.get_resource_path() url = top_def.get_resource_path()
body = {'resource_type': top_def.resource_type()} body = {'resource_type': top_def.resource_type(),
'children': []}
# iterate over defs (except top level def) # iterate over defs (except top level def)
for resource_def in self.defs[1:]: for resource_def in self.defs[1:]:
parent_dict = None parent_dict = None
@@ -145,16 +162,16 @@ class NsxPolicyTransaction(object):
resource_def) resource_def)
if not parent_dict: if not parent_dict:
# Top level resource
parent_dict = body parent_dict = body
if 'children' not in parent_dict: if 'children' not in parent_dict:
parent_dict['children'] = [] parent_dict['children'] = []
resource_class = resource_def.resource_class() resource_class = resource_def.resource_class()
parent_dict['children'].append({ parent_dict['children'].append(
'resource_type': 'Child%s' % resource_class, self._build_wrapper_dict(resource_class,
resource_class: resource_def.get_obj_dict() resource_def.get_obj_dict()))
})
if body: if body:
self.client.patch(url, body) self.client.patch(url, body)