From 83c9d1259ee7551a2f17c812a5cbab1da1a350cd Mon Sep 17 00:00:00 2001 From: Mingjun Zhang <54682183+mingjunzhang2019@users.noreply.github.com> Date: Tue, 29 Aug 2023 13:49:33 -0700 Subject: [PATCH] Add diff check modes support for vrfs logging and ip_neighbor modules (#285) * Add diff and check modes support for vrfs logging and ip_neighbor modules * Add fragment file --- ...ff-modes-for-vrfs-logging-ip-neighbor.yaml | 2 + .../sonic/config/ip_neighbor/ip_neighbor.py | 44 ++++++++++++- .../network/sonic/config/logging/logging.py | 65 +++++++++++------- .../network/sonic/config/vrfs/vrfs.py | 66 ++++++++++++------- 4 files changed, 129 insertions(+), 48 deletions(-) create mode 100644 changelogs/fragments/285-playbook-check-diff-modes-for-vrfs-logging-ip-neighbor.yaml diff --git a/changelogs/fragments/285-playbook-check-diff-modes-for-vrfs-logging-ip-neighbor.yaml b/changelogs/fragments/285-playbook-check-diff-modes-for-vrfs-logging-ip-neighbor.yaml new file mode 100644 index 000000000..2bfc3f4f2 --- /dev/null +++ b/changelogs/fragments/285-playbook-check-diff-modes-for-vrfs-logging-ip-neighbor.yaml @@ -0,0 +1,2 @@ +major_changes: + - vrfs_logging_ip_neighbor - Playbook check and diff modes supports for sonic_vrfs, sonic_logging and sonic_ip_neighbor modules (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/285). diff --git a/plugins/module_utils/network/sonic/config/ip_neighbor/ip_neighbor.py b/plugins/module_utils/network/sonic/config/ip_neighbor/ip_neighbor.py index b9a34fd9a..303ec939b 100644 --- a/plugins/module_utils/network/sonic/config/ip_neighbor/ip_neighbor.py +++ b/plugins/module_utils/network/sonic/config/ip_neighbor/ip_neighbor.py @@ -31,6 +31,10 @@ get_diff, update_states, ) +from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.utils.formatted_diff_utils import ( + get_new_config, + get_formatted_config_diff +) from ansible.module_utils.connection import ConnectionError GET = 'get' @@ -59,6 +63,34 @@ } +def __derive_ip_neighbor_config_delete_op(key_set, command, exist_conf): + new_conf = exist_conf + + if 'ipv4_arp_timeout' in command: + new_conf['ipv4_arp_timeout'] = IP_NEIGH_CONFIG_DEFAULT['ipv4_arp_timeout'] + + if 'ipv4_drop_neighbor_aging_time' in command: + new_conf['ipv4_drop_neighbor_aging_time'] = \ + IP_NEIGH_CONFIG_DEFAULT['ipv4_drop_neighbor_aging_time'] + + if 'ipv6_drop_neighbor_aging_time' in command: + new_conf['ipv6_drop_neighbor_aging_time'] = \ + IP_NEIGH_CONFIG_DEFAULT['ipv6_drop_neighbor_aging_time'] + + if 'ipv6_nd_cache_expiry' in command: + new_conf['ipv6_nd_cache_expiry'] = IP_NEIGH_CONFIG_DEFAULT['ipv6_nd_cache_expiry'] + + if 'num_local_neigh' in command: + new_conf['num_local_neigh'] = IP_NEIGH_CONFIG_DEFAULT['num_local_neigh'] + + return True, new_conf + + +TEST_KEYS_formatted_diff = [ + {'__delete_op_default': {'__delete_op': __derive_ip_neighbor_config_delete_op}}, +] + + class Ip_neighbor(ConfigBase): """ The sonic_ip_neighbor class @@ -130,6 +162,16 @@ def execute_module(self): if result['changed']: result['after'] = changed_ip_neighbor_facts + new_config = changed_ip_neighbor_facts + if self._module.check_mode: + result.pop('after', None) + new_config = get_new_config(commands, existing_ip_neighbor_facts, + TEST_KEYS_formatted_diff) + result['after(generated)'] = new_config + + if self._module._diff: + result['config_diff'] = get_formatted_config_diff(existing_ip_neighbor_facts, + new_config) result['warnings'] = warnings return result @@ -255,7 +297,7 @@ def _state_overridden(self, want, have): requests = self.build_merge_requests(commands) if len(requests) > 0: - commands = update_states(commands, "overriden") + commands = update_states(commands, "overridden") else: commands = [] diff --git a/plugins/module_utils/network/sonic/config/logging/logging.py b/plugins/module_utils/network/sonic/config/logging/logging.py index 6657de19e..46e02d23a 100644 --- a/plugins/module_utils/network/sonic/config/logging/logging.py +++ b/plugins/module_utils/network/sonic/config/logging/logging.py @@ -28,9 +28,13 @@ from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.utils.utils import ( get_diff, update_states, - send_requests, get_normalize_interface_name, ) +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 PATCH = 'PATCH' @@ -44,6 +48,11 @@ "remote_servers": {"host": ""} } ] +TEST_KEYS_formatted_diff = [ + { + "remote_servers": {"host": "", '__delete_op': __DELETE_CONFIG_IF_NO_SUBCONFIG} + } +] class Logging(ConfigBase): @@ -104,6 +113,16 @@ def execute_module(self): if result['changed']: result['after'] = changed_logging_facts + new_config = changed_logging_facts + if self._module.check_mode: + result.pop('after', None) + new_config = get_new_config(commands, existing_logging_facts, + TEST_KEYS_formatted_diff) + result['after(generated)'] = new_config + + if self._module._diff: + result['config_diff'] = get_formatted_config_diff(existing_logging_facts, + new_config) result['warnings'] = warnings return result @@ -222,6 +241,9 @@ def _state_replaced(self, want, have): :returns: the commands necessary to migrate the current configuration to the desired configuration """ + commands = [] + requests = [] + replaced_config = self.get_replaced_config(have, want) if 'remote_servers' in replaced_config: replaced_config['remote_servers'].sort(key=self.get_host) @@ -230,21 +252,18 @@ def _state_replaced(self, want, have): if replaced_config and replaced_config != want: delete_all = False - requests = self.get_delete_requests(replaced_config, delete_all) - send_requests(self._module, requests) + del_requests = self.get_delete_requests(replaced_config, delete_all) + requests.extend(del_requests) + commands.extend(update_states(replaced_config, "deleted")) replaced_config = [] - commands = [] - requests = [] - if not replaced_config and want: - commands = want - requests = self.get_merge_requests(commands, replaced_config) + add_commands = want + add_requests = self.get_merge_requests(add_commands, replaced_config) - if len(requests) > 0: - commands = update_states(commands, "replaced") - else: - commands = [] + if len(add_requests) > 0: + requests.extend(add_requests) + commands.extend(update_states(add_commands, "replaced")) return commands, requests @@ -263,23 +282,23 @@ def _state_overridden(self, want, have): if 'remote_servers' in want: want['remote_servers'].sort(key=self.get_host) + commands = [] + requests = [] + if have and have != want: delete_all = True - requests = self.get_delete_requests(have, delete_all) - send_requests(self._module, requests) + del_requests = self.get_delete_requests(have, delete_all) + requests.extend(del_requests) + commands.extend(update_states(have, "deleted")) have = [] - commands = [] - requests = [] - if not have and want: - commands = want - requests = self.get_merge_requests(commands, have) + add_commands = want + add_requests = self.get_merge_requests(add_commands, have) - if len(requests) > 0: - commands = update_states(commands, "overridden") - else: - commands = [] + if len(add_requests) > 0: + requests.extend(add_requests) + commands.extend(update_states(add_commands, "overridden")) return commands, requests diff --git a/plugins/module_utils/network/sonic/config/vrfs/vrfs.py b/plugins/module_utils/network/sonic/config/vrfs/vrfs.py index 7fce1cdeb..156168884 100644 --- a/plugins/module_utils/network/sonic/config/vrfs/vrfs.py +++ b/plugins/module_utils/network/sonic/config/vrfs/vrfs.py @@ -28,9 +28,13 @@ from ansible_collections.dellemc.enterprise_sonic.plugins.module_utils.network.sonic.utils.utils import ( get_diff, update_states, - send_requests, normalize_interface_name ) +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 PATCH = 'patch' @@ -38,6 +42,10 @@ TEST_KEYS = [ {'interfaces': {'name': ''}} ] +TEST_KEYS_formatted_diff = [ + {'config': {'name': ''}}, + {'interfaces': {'name': '', '__delete_op': __DELETE_CONFIG_IF_NO_SUBCONFIG}} +] class Vrfs(ConfigBase): @@ -98,6 +106,16 @@ def execute_module(self): if result['changed']: result['after'] = changed_vrf_interfaces_facts + new_config = changed_vrf_interfaces_facts + if self._module.check_mode: + result.pop('after', None) + new_config = get_new_config(commands, existing_vrf_interfaces_facts, + TEST_KEYS_formatted_diff) + result['after(generated)'] = new_config + + if self._module._diff: + result['config_diff'] = get_formatted_config_diff(existing_vrf_interfaces_facts, + new_config) result['warnings'] = warnings return result @@ -204,27 +222,27 @@ def _state_replaced(self, want, have): :returns: the commands necessary to migrate the current configuration to the desired configuration """ + commands = [] + requests = [] + replaced_config = self.get_replaced_config(have, want) self.sort_config(replaced_config) self.sort_config(want) if replaced_config and replaced_config != want: self.delete_all_flag = False - requests = self.get_delete_vrf_interface_requests(replaced_config, have) - send_requests(self._module, requests) + del_requests = self.get_delete_vrf_interface_requests(replaced_config, have) + requests.extend(del_requests) + commands.extend(update_states(replaced_config, "deleted")) replaced_config = [] - commands = [] - requests = [] - if not replaced_config and want: - commands = want - requests = self.get_create_requests(commands, have) + add_commands = want + add_requests = self.get_create_requests(add_commands, have) - if len(requests) > 0: - commands = update_states(commands, "replaced") - else: - commands = [] + if len(add_requests) > 0: + requests.extend(add_requests) + commands.extend(update_states(add_commands, "replaced")) return commands, requests @@ -241,23 +259,23 @@ def _state_overridden(self, want, have): self.sort_config(have) self.sort_config(want) + commands = [] + requests = [] + if have and have != want: self.delete_all_flag = True - requests = self.get_delete_vrf_interface_requests(have, have) - send_requests(self._module, requests) + del_requests = self.get_delete_vrf_interface_requests(have, have) + requests.extend(del_requests) + commands.extend(update_states(have, "deleted")) have = [] - commands = [] - requests = [] - if not have and want: - commands = want - requests = self.get_create_requests(commands, have) + add_commands = want + add_requests = self.get_create_requests(add_commands, have) - if len(requests) > 0: - commands = update_states(commands, "overridden") - else: - commands = [] + if len(add_requests) > 0: + requests.extend(add_requests) + commands.extend(update_states(add_commands, "overridden")) return commands, requests @@ -387,7 +405,7 @@ def sort_config(self, conf): if conf: conf.sort(key=self.get_vrf_name) for vrf in conf: - if 'members' in vrf and 'interfaces' in vrf['members']: + if vrf.get('members', None) and vrf['members'].get('interfaces', None): vrf['members']['interfaces'].sort(key=self.get_interface_name) def get_replaced_config(self, have, want):