junos_linkagg implementation and junos modules refactor (#26587)

* junos_linkagg implementation and junos modules refactor

*  junos_linkagg implementation
*  junos_linkagg integration test
*  net_linkagg integration test for junos
*  decouple `load_config` and `commit` operations,
   to allow single commit (in case on confirm commit) and
   to perform batch commit (multiple `load_config` followed by single
   `commit`)
*  Other related refactor

* Fix CI issues

* Fix unit test failure
This commit is contained in:
Ganesh Nalawade 2017-07-11 09:52:53 +05:30 committed by GitHub
parent 82558baaf6
commit be89ef3eb6
30 changed files with 1140 additions and 220 deletions

View file

@ -191,31 +191,21 @@ def get_diff(module):
return to_text(output.text, encoding='latin1').strip()
def load_config(module, candidate, warnings, action='merge', commit=False, format='xml',
comment=None, confirm=False, confirm_timeout=None):
def load_config(module, candidate, warnings, action='merge', format='xml'):
if not candidate:
return
with locked_config(module):
if isinstance(candidate, list):
candidate = '\n'.join(candidate)
if isinstance(candidate, list):
candidate = '\n'.join(candidate)
reply = load_configuration(module, candidate, action=action, format=format)
if isinstance(reply, list):
warnings.extend(reply)
reply = load_configuration(module, candidate, action=action, format=format)
if isinstance(reply, list):
warnings.extend(reply)
validate(module)
diff = get_diff(module)
validate(module)
if diff:
if commit:
commit_configuration(module, confirm=confirm, comment=comment,
confirm_timeout=confirm_timeout)
else:
discard_changes(module)
return diff
return get_diff(module)
def get_param(module, key):
@ -293,88 +283,90 @@ def map_obj_to_ele(module, want, top, value_map=None):
oper = 'inactive'
# build xml subtree
for obj in want:
if container.tag != top_ele[-1]:
node = SubElement(container, top_ele[-1])
else:
node = container
if container.tag != top_ele[-1]:
node = SubElement(container, top_ele[-1])
else:
node = container
for fxpath, attributes in obj.items():
for attr in attributes:
tag_only = attr.get('tag_only', False)
leaf_only = attr.get('leaf_only', False)
is_value = attr.get('value_req', False)
is_key = attr.get('is_key', False)
value = attr.get('value')
field_top = attr.get('top')
# operation 'delete' is added as element attribute
# only if it is key or leaf only node
if state == 'absent' and not (is_key or leaf_only):
continue
for fxpath, attributes in want.items():
for attr in attributes:
tag_only = attr.get('tag_only', False)
leaf_only = attr.get('leaf_only', False)
value_req = attr.get('value_req', False)
is_key = attr.get('is_key', False)
parent_attrib = attr.get('parent_attrib', True)
value = attr.get('value')
field_top = attr.get('top')
# for tag only node if value is false continue to next attr
if tag_only and not value:
continue
# operation 'delete' is added as element attribute
# only if it is key or leaf only node
if state == 'absent' and not (is_key or leaf_only):
continue
# convert param value to device specific value
if value_map and fxpath in value_map:
value = value_map[fxpath].get(value)
# for tag only node if value is false continue to next attr
if tag_only and not value:
continue
if value or tag_only or leaf_only:
ele = node
if field_top:
# eg: top = 'system/syslog/file'
# field_top = 'system/syslog/file/contents'
# <file>
# <name>test</name>
# <contents>
# </contents>
# </file>
ele_list = root.xpath(top + '/' + field_top)
# convert param value to device specific value
if value_map and fxpath in value_map:
value = value_map[fxpath].get(value)
if not len(ele_list):
fields = field_top.split('/')
ele = node
for item in fields:
inner_ele = root.xpath(top + '/' + item)
if len(inner_ele):
ele = inner_ele[0]
else:
ele = SubElement(ele, item)
else:
ele = ele_list[0]
if value or tag_only or leaf_only:
ele = node
if field_top:
# eg: top = 'system/syslog/file'
# field_top = 'system/syslog/file/contents'
# <file>
# <name>test</name>
# <contents>
# </contents>
# </file>
ele_list = root.xpath(top + '/' + field_top)
tags = fxpath.split('/')
if value:
value = to_text(value, errors='surrogate_then_replace')
for item in tags:
ele = SubElement(ele, item)
if tag_only:
if state == 'present':
if not value:
# if value of tag_only node is false, delete the node
ele.set('delete', 'delete')
elif leaf_only:
if state == 'present':
ele.set(oper, oper)
ele.text = value
else:
ele.set('delete', 'delete')
# Add value of leaf node if required while deleting.
# in some cases if value is present while deleting, it
# can result in error, hence the check
if is_value:
ele.text = value
if is_key:
par = ele.getparent()
par.set('delete', 'delete')
if not len(ele_list):
fields = field_top.split('/')
ele = node
for item in fields:
inner_ele = root.xpath(top + '/' + item)
if len(inner_ele):
ele = inner_ele[0]
else:
ele = SubElement(ele, item)
else:
ele.text = value
par = ele.getparent()
ele = ele_list[0]
tags = fxpath.split('/')
if value:
value = to_text(value, errors='surrogate_then_replace')
for item in tags:
ele = SubElement(ele, item)
if tag_only:
if state == 'present':
if not value:
# if value of tag_only node is false, delete the node
ele.set('delete', 'delete')
elif leaf_only:
if state == 'present':
ele.set(oper, oper)
ele.text = value
else:
ele.set('delete', 'delete')
# Add value of leaf node if required while deleting.
# in some cases if value is present while deleting, it
# can result in error, hence the check
if value_req:
ele.text = value
if is_key:
par = ele.getparent()
par.set('delete', 'delete')
else:
ele.text = value
par = ele.getparent()
if parent_attrib:
if state == 'present':
# set replace attribute at parent node
if not par.attrib.get('replace'):