Skip to content

Commit

Permalink
Add diff and check modes for route_maps and prefix_lists modules (ans…
Browse files Browse the repository at this point in the history
…ible-collections#331)

* Add diff and check modes for route_maps and prefix_lists modules

* Add fragment file

* Change GitHub workflow version to fix sanilty check error

* Merge with main

* Address review comments and fix sanity errors

* Add diff sample text for doc
  • Loading branch information
mingjunzhang2019 authored Apr 3, 2024
1 parent e8f990d commit 8e451ec
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- sonic_route_maps - Add playbook check and diff modes support for route_maps module (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/331).
- sonic_prefix_lists - Add playbook check and diff modes support for prefix_lists module (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/331).
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,32 @@
import (
remove_empties_from_list,
update_states,
remove_empties_from_list,
)

from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.sonic import (
to_request,
edit_config
)

from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.utils.formatted_diff_utils import (
__DELETE_CONFIG_IF_NO_SUBCONFIG,
get_new_config,
get_formatted_config_diff
)

# from ansible.module_utils.connection import ConnectionError

TEST_KEYS = [
{"config": {"afi": "", "name": ""}},
{"prefixes": {"ge": "", "le": "", "prefix": "", "sequence": ""}}
]

TEST_KEYS_generate_config = [
{"config": {"afi": "", "name": "", '__delete_op': __DELETE_CONFIG_IF_NO_SUBCONFIG}},
{"prefixes": {"ge": "", "le": "", "prefix": "", "sequence": "", '__delete_op': __DELETE_CONFIG_IF_NO_SUBCONFIG}}
]

DELETE = "delete"
PATCH = "patch"

Expand Down Expand Up @@ -117,6 +129,23 @@ def execute_module(self):
if result['changed']:
result['after'] = changed_prefix_lists_facts

new_config = changed_prefix_lists_facts
old_config = existing_prefix_lists_facts
if self._module.check_mode:
result.pop('after', None)
new_config = get_new_config(commands, existing_prefix_lists_facts,
TEST_KEYS_generate_config)
new_config = self.post_process_generated_config(new_config)
result['after(generated)'] = new_config

if self._module._diff:
new_config = remove_empties_from_list(new_config)
old_config = remove_empties_from_list(old_config)
self.sort_lists_in_config(new_config)
self.sort_lists_in_config(old_config)
result['diff'] = get_formatted_config_diff(old_config,
new_config,
self._module._verbosity)
result['warnings'] = warnings
return result

Expand Down Expand Up @@ -597,6 +626,21 @@ def set_ipaddress_net_attrs(self, prefix_val, conf_afi):
prefix_net['prefixlen'] = int(prefix_val.split("/")[1])
return prefix_net

def sort_lists_in_config(self, config):
if config:
config.sort(key=lambda x: x['name'])
for cfg in config:
if 'prefixes' in cfg and cfg['prefixes']:
cfg['prefixes'].sort(key=lambda x: (x['sequence'], x['action'], x['prefix']))

def post_process_generated_config(self, configs):
confs = remove_empties_from_list(configs)
if confs:
for conf in confs[:]:
if not conf.get('prefixes', None):
confs.remove(conf)
return confs

@staticmethod
def _convert_config_list_to_dict(config_list):
config_dict = {}
Expand Down
40 changes: 40 additions & 0 deletions plugins/module_utils/network/sonic/config/route_maps/route_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
get_normalize_interface_name,
check_required
)
from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.utils.formatted_diff_utils import (
__DELETE_CONFIG_IF_NO_SUBCONFIG,
get_new_config,
get_formatted_config_diff
)
from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.sonic import (
to_request,
edit_config
Expand All @@ -45,6 +50,10 @@
{"config": {"map_name": "", "sequence_num": ""}}
]

TEST_KEYS_generate_config = [
{"config": {"map_name": "", "sequence_num": "", '__delete_op': __DELETE_CONFIG_IF_NO_SUBCONFIG}}
]

DELETE = "delete"
PATCH = "patch"

Expand Down Expand Up @@ -125,6 +134,21 @@ def execute_module(self):
if result['changed']:
result['after'] = changed_route_maps_facts

new_config = changed_route_maps_facts
old_config = existing_route_maps_facts
if self._module.check_mode:
result.pop('after', None)
new_config = get_new_config(commands, existing_route_maps_facts,
TEST_KEYS_generate_config)
new_config = self.post_process_generated_config(new_config)
result['after(generated)'] = new_config

if self._module._diff:
self.sort_lists_in_config(new_config)
self.sort_lists_in_config(old_config)
result['diff'] = get_formatted_config_diff(old_config,
new_config,
self._module._verbosity)
result['warnings'] = warnings
return result

Expand Down Expand Up @@ -2352,3 +2376,19 @@ def validate_and_normalize_config(self, input_config_list):
route_map['match']['peer']['interface'] = updated_intf_name

return updated_config_list

def sort_lists_in_config(self, config):
if config:
config.sort(key=lambda x: (x['map_name'],
x.get('sequence_num') if x.get('sequence_num') is not None else 0))

def post_process_generated_config(self, configs):
confs = remove_empties_from_list(configs)
if confs:
for conf in confs[:]:
rm_match = conf.get('match', None)
rm_set = conf.get('set', None)
rm_call = conf.get('call', None)
if not rm_match and not rm_set and not rm_call:
confs.remove(conf)
return confs
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,10 @@ def sort_lists_in_config(self, config):
cfg['static_list'].sort(key=self.get_prefix)
for rt in cfg['static_list']:
if 'next_hops' in rt and rt['next_hops']:
rt['next_hops'].sort(key=lambda x: (x['index'].get('blackhole', None) is not None,
x['index'].get('interface', None) is not None,
x['index'].get('nexthop_vrf', None) is not None,
x['index'].get('next_hop', None) is not None))
rt['next_hops'].sort(key=lambda x: (x['index'].get('blackhole') if x['index'].get('blackhole') is not None else False,
x['index'].get('interface') if x['index'].get('interface') is not None else '',
x['index'].get('nexthop_vrf') if x['index'].get('nexthop_vrf') is not None else '',
x['index'].get('next_hop') if x['index'].get('next_hop') is not None else ''))

def get_vrf_name(self, vrf_name):
return vrf_name.get('vrf_name')
Expand Down
37 changes: 37 additions & 0 deletions plugins/modules/sonic_prefix_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
module: sonic_prefix_lists
version_added: "2.0.0"
author: Kerry Meyer (@kerry-meyer)
notes:
- Supports C(check_mode).
- Supports D(diff_mode).
short_description: prefix list configuration handling for SONiC
description:
- This module provides configuration management for prefix list parameters on devices running SONiC.
Expand Down Expand Up @@ -492,6 +495,40 @@
# }
# ],
"""
RETURN = """
before:
description: The configuration prior to the model invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The resulting configuration model invocation.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after(generated):
description: The generated configuration model invocation.
returned: when C(check_mode)
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
diff:
description: The difference between 'before' and 'after' (or 'after(generated)').
returned: when D(diff_mode)
type: list
sample: >
The difference shows several lines of context around the lines that differ.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""


from ansible.module_utils.basic import AnsibleModule
Expand Down
9 changes: 9 additions & 0 deletions plugins/modules/sonic_route_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
module: sonic_route_maps
version_added: "2.1.0"
author: "Kerry Meyer (@kerry-meyer)"
notes:
- Supports C(check_mode).
short_description: route map configuration handling for SONiC
description:
- This module provides configuration management for route map parameters on devices running SONiC.
Expand Down Expand Up @@ -1576,6 +1578,13 @@
sample: >
The configuration returned will always be in the same format
as the parameters above.
after(generated):
description: The generated configuration model invocation.
returned: when C(check_mode)
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
Expand Down
1 change: 1 addition & 0 deletions tests/sanity/ignore-3.10.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins/action/sonic.py action-plugin-docs #action plugin for base class
1 change: 1 addition & 0 deletions tests/sanity/ignore-3.11.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins/action/sonic.py action-plugin-docs #action plugin for base class
1 change: 1 addition & 0 deletions tests/sanity/ignore-3.12.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins/action/sonic.py action-plugin-docs #action plugin for base class

0 comments on commit 8e451ec

Please sign in to comment.