mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 19:31:26 -07:00
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:
parent
82558baaf6
commit
be89ef3eb6
30 changed files with 1140 additions and 220 deletions
|
@ -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'):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue