diff --git a/changelogs/fragments/251-replaced-overridden-for-bgp-communities-module.yaml b/changelogs/fragments/251-replaced-overridden-for-bgp-communities-module.yaml new file mode 100644 index 000000000..5b9da775a --- /dev/null +++ b/changelogs/fragments/251-replaced-overridden-for-bgp-communities-module.yaml @@ -0,0 +1,2 @@ +minor_changes: + - sonic_bgp_communities - Add support for replaced and overridden states (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/251). diff --git a/plugins/module_utils/network/sonic/argspec/bgp_communities/bgp_communities.py b/plugins/module_utils/network/sonic/argspec/bgp_communities/bgp_communities.py index 867e55204..c90fab8e9 100644 --- a/plugins/module_utils/network/sonic/argspec/bgp_communities/bgp_communities.py +++ b/plugins/module_utils/network/sonic/argspec/bgp_communities/bgp_communities.py @@ -1,6 +1,6 @@ # # -*- coding: utf-8 -*- -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -54,6 +54,6 @@ def __init__(self, **kwargs): 'default': 'standard', 'type': 'str'}}, 'type': 'list'}, - 'state': {'choices': ['merged', 'deleted'], + 'state': {'choices': ['merged', 'deleted', 'replaced', 'overridden'], 'default': 'merged', 'type': 'str'}} # pylint: disable=C0301 diff --git a/plugins/module_utils/network/sonic/config/bgp_communities/bgp_communities.py b/plugins/module_utils/network/sonic/config/bgp_communities/bgp_communities.py index 670fb26d3..82ed70a3f 100644 --- a/plugins/module_utils/network/sonic/config/bgp_communities/bgp_communities.py +++ b/plugins/module_utils/network/sonic/config/bgp_communities/bgp_communities.py @@ -1,6 +1,6 @@ # # -*- coding: utf-8 -*- -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) """ @@ -62,6 +62,13 @@ class Bgp_communities(ConfigBase): 'bgp_communities', ] + standard_communities_map = { + 'no_peer': 'NOPEER', + 'no_export': 'NO_EXPORT', + 'no_advertise': 'NO_ADVERTISE', + 'local_as': 'NO_EXPORT_SUBCONFED' + } + def __init__(self, module): super(Bgp_communities, self).__init__(module) @@ -89,6 +96,7 @@ def execute_module(self): existing_bgp_communities_facts = self.get_bgp_communities_facts() commands, requests = self.set_config(existing_bgp_communities_facts) + if commands and len(requests) > 0: if not self._module.check_mode: try: @@ -116,6 +124,13 @@ def set_config(self, existing_bgp_communities_facts): to the desired configuration """ want = self._module.params['config'] + if want: + for conf in want: + if conf.get("match", None): + conf["match"] = conf["match"].upper() + if conf.get("members", {}) and conf['members'].get("regex", []): + conf['members']['regex'].sort() + have = existing_bgp_communities_facts resp = self.set_state(want, have) return to_list(resp) @@ -138,17 +153,16 @@ def set_state(self, want, have): # fp.write('comm: have: ' + str(have) + '\n') # fp.write('comm: diff: ' + str(diff) + '\n') if state == 'overridden': - commands, requests = self._state_overridden(want, have, diff) + commands, requests = self._state_overridden(want, have) elif state == 'deleted': - commands, requests = self._state_deleted(want, have, diff) + commands, requests = self._state_deleted(want, have) elif state == 'merged': commands, requests = self._state_merged(want, have, diff) elif state == 'replaced': - commands, requests = self._state_replaced(want, have, diff) + commands, requests = self._state_replaced(want, have) return commands, requests - @staticmethod - def _state_replaced(**kwargs): + def _state_replaced(self, want, have): """ The command generator when state is replaced :rtype: A list @@ -156,10 +170,13 @@ def _state_replaced(**kwargs): to the desired configuration """ commands = [] - return commands + requests = [] + + commands, requests = self.get_replaced_overridden_config(want, have, "replaced") - @staticmethod - def _state_overridden(**kwargs): + return commands, requests + + def _state_overridden(self, want, have): """ The command generator when state is overridden :rtype: A list @@ -167,7 +184,11 @@ def _state_overridden(**kwargs): to the desired configuration """ commands = [] - return commands + requests = [] + + commands, requests = self.get_replaced_overridden_config(want, have, "overridden") + + return commands, requests def _state_merged(self, want, have, diff): """ The command generator when state is merged @@ -177,7 +198,7 @@ def _state_merged(self, want, have, diff): the current configuration """ commands = diff - requests = self.get_modify_bgp_community_requests(commands, have) + requests = self.get_modify_bgp_community_requests(commands, have, "merged") if commands and len(requests) > 0: commands = update_states(commands, "merged") else: @@ -185,7 +206,7 @@ def _state_merged(self, want, have, diff): return commands, requests - def _state_deleted(self, want, have, diff): + def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list @@ -217,28 +238,18 @@ def _state_deleted(self, want, have, diff): return commands, requests - def get_delete_single_bgp_community_member_requests(self, name, type, members): + def get_delete_single_bgp_community_member_requests(self, name, members): requests = [] for member in members: url = "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:" url = url + "bgp-defined-sets/community-sets/community-set={name}/config/{members_param}" method = "DELETE" - memberstr = member - if type == 'expanded': - memberstr = 'REGEX:' + member - members_params = {'community-member': memberstr} + members_params = {'community-member': member} members_str = urlencode(members_params) request = {"path": url.format(name=name, members_param=members_str), "method": method} requests.append(request) return requests - def get_delete_all_members_bgp_community_requests(self, name): - url = "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:" - url = url + "bgp-defined-sets/community-sets/community-set={}/config/community-member" - method = "DELETE" - request = {"path": url.format(name), "method": method} - return request - def get_delete_single_bgp_community_requests(self, name): url = "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set={}" method = "DELETE" @@ -255,70 +266,90 @@ def get_delete_all_bgp_communities(self, commands): return requests def get_delete_bgp_communities(self, commands, have, is_delete_all): - # with open('/root/ansible_log.log', 'a+') as fp: - # fp.write('bgp_commmunities: delete requests ************** \n') requests = [] if is_delete_all: requests = self.get_delete_all_bgp_communities(commands) else: for cmd in commands: name = cmd['name'] - type = cmd['type'] - members = cmd['members'] - if members: - if members['regex']: - diff_members = [] - for item in have: - if item['name'] == name and item['members']: - for member_want in members['regex']: - if str(member_want) in item['members']['regex']: - diff_members.append(member_want) - if diff_members: - requests.extend(self.get_delete_single_bgp_community_member_requests(name, type, diff_members)) - else: - for item in have: - if item['name'] == name: - if item['members']: - requests.append(self.get_delete_all_members_bgp_community_requests(name)) - else: - for item in have: - if item['name'] == name: + members = cmd.get('members', None) + cmd_type = cmd['type'] + diff_members = [] + + for item in have: + if item['name'] == name: + if 'permit' not in cmd or cmd['permit'] is None: + cmd['permit'] = item['permit'] + + if cmd == item: requests.append(self.get_delete_single_bgp_community_requests(name)) + break + + if cmd_type == "standard": + for attr in self.standard_communities_map: + if cmd.get(attr, None) and item[attr] and cmd[attr] == item[attr]: + diff_members.append(self.standard_communities_map[attr]) + + if members: + if members.get('regex', []): + for member_want in members['regex']: + if item.get('members', None) and item['members'].get('regex', []): + if str(member_want) in item['members']['regex']: + diff_members.append("REGEX:" + str(member_want)) + else: + requests.append(self.get_delete_single_bgp_community_requests(name)) + + else: + if cmd_type == "standard": + no_attr = True + for attr in self.standard_communities_map: + if cmd.get(attr, None): + no_attr = False + break + if no_attr: + requests.append(self.get_delete_single_bgp_community_requests(name)) + else: + requests.append(self.get_delete_single_bgp_community_requests(name)) + break + + if diff_members: + requests.extend(self.get_delete_single_bgp_community_member_requests(name, diff_members)) - # with open('/root/ansible_log.log', 'a+') as fp: - # fp.write('bgp_commmunities: delete requests' + str(requests) + '\n') return requests def get_new_add_request(self, conf): url = "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" method = "PATCH" - # members = conf['members'] - # members_str = ', '.join(members) - # members_list = list() - # for member in members.split(','): - # members_list.append(str(member)) + community_members = [] + community_action = "" if 'match' not in conf: conf['match'] = "ANY" - # with open('/root/ansible_log.log', 'a+') as fp: - # fp.write('bgp_communities: conf' + str(conf) + '\n') - if 'local_as' in conf and conf['local_as']: - conf['members']['regex'].append("NO_EXPORT_SUBCONFED") - if 'no_peer' in conf and conf['no_peer']: - conf['members']['regex'].append("NOPEER") - if 'no_export' in conf and conf['no_export']: - conf['members']['regex'].append("NO_EXPORT") - if 'no_advertise' in conf and conf['no_advertise']: - conf['members']['regex'].append("NO_ADVERTISE") - input_data = {'name': conf['name'], 'members_list': conf['members']['regex'], 'match': conf['match']} - if conf['type'] == 'expanded': - input_data['regex'] = "REGEX:" - else: - input_data['regex'] = "" + + if conf['type'] == 'standard': + for attr in self.standard_communities_map: + if attr in conf and conf[attr]: + community_members.append(self.standard_communities_map[attr]) + if 'members' in conf and conf['members'] and conf['members'].get('regex', []): + for i in conf['members']['regex']: + community_members.extend([str(i)]) + if not community_members: + self._module.fail_json(msg='Cannot create standard community-list {0} without community attributes'.format(conf['name'])) + + elif conf['type'] == 'expanded': + if 'members' in conf and conf['members'] and conf['members'].get('regex', []): + for i in conf['members']['regex']: + community_members.extend(["REGEX:" + str(i)]) + if not community_members: + self._module.fail_json(msg='Cannot create expanded community-list {0} without community attributes'.format(conf['name'])) + if conf['permit']: - input_data['permit'] = "PERMIT" + community_action = "PERMIT" else: - input_data['permit'] = "DENY" + community_action = "DENY" + + input_data = {'name': conf['name'], 'members_list': community_members, 'match': conf['match'].upper(), 'permit': community_action} + payload_template = """ { "openconfig-bgp-policy:community-sets": { @@ -328,7 +359,7 @@ def get_new_add_request(self, conf): "config": { "community-set-name": "{{name}}", "community-member": [ - {% for member in members_list %}"{{regex}}{{member}}"{%- if not loop.last -%},{% endif %}{%endfor%} + {% for member in members_list %}"{{member}}"{%- if not loop.last -%},{% endif %}{%endfor%} ], "openconfig-bgp-policy-ext:action": "{{permit}}", "match-set-options": "{{match}}" @@ -342,27 +373,118 @@ def get_new_add_request(self, conf): intended_payload = t.render(input_data) ret_payload = json.loads(intended_payload) request = {"path": url, "method": method, "data": ret_payload} - # with open('/root/ansible_log.log', 'a+') as fp: - # fp.write('bgp_communities: request' + str(request) + '\n') + return request - def get_modify_bgp_community_requests(self, commands, have): + def get_modify_bgp_community_requests(self, commands, have, cur_state): requests = [] if not commands: return requests for conf in commands: - for item in have: - if item['name'] == conf['name']: - if 'type' not in conf: - conf['type'] = item['type'] - if 'permit' not in conf: - conf['permit'] = item['permit'] - if 'match' not in conf: - conf['match'] = item['match'] - if 'members' not in conf: - conf['members'] = item['members'] + if cur_state == "merged": + for item in have: + if item['name'] == conf['name']: + if 'type' not in conf: + conf['type'] = item['type'] + if 'permit' not in conf or conf['permit'] is None: + conf['permit'] = item['permit'] + if 'match' not in conf: + conf['match'] = item['match'] + if conf['type'] == "standard": + for attr in self.standard_communities_map: + if attr not in conf and attr in item: + conf[attr] = item[attr] + else: + if 'members' not in conf: + if item.get('members', {}) and item['members'].get('regex', []): + conf['members'] = {'regex': item['members']['regex']} + else: + conf['members'] = item['members'] + break + new_req = self.get_new_add_request(conf) if new_req: requests.append(new_req) return requests + + def get_replaced_overridden_config(self, want, have, cur_state): + commands, requests = [], [] + + commands_del, requests_del = [], [] + commands_add, requests_add = [], [] + + for conf in want: + name = conf['name'] + in_have = False + for have_conf in have: + if have_conf['name'] == name: + in_have = True + if have_conf['type'] != conf['type']: + # If both community list are of same name but different types + commands_del.append(have_conf) + commands_add.append(conf) + else: + is_change = False + + if have_conf['permit'] != conf['permit']: + is_change = True + + if have_conf['match'] != conf['match']: + is_change = is_delete = True + + if conf["type"] == "standard": + no_attr = True + for attr in self.standard_communities_map: + if not conf.get(attr, None): + if have_conf.get(attr, None): + is_change = True + else: + no_attr = False + if not have_conf.get(attr, None): + is_change = True + + if no_attr: + # Since standard type needs atleast one attribute to exist + self._module.fail_json(msg='Cannot create standard community-list {0} without community attributes'.format(conf['name'])) + else: + members = conf.get('members', {}) + if members and members.get('regex', []): + if have_conf.get('members', {}) and have_conf['members'].get('regex', []): + if set(have_conf['members']['regex']).symmetric_difference(set(members['regex'])): + is_change = True + else: + # If there are no members in any community list of want, then + # that particular community list request to be ignored since + # expanded type needs community-member to exist + self._module.fail_json(msg='Cannot create expanded community-list {0} without community attributes'.format(conf['name'])) + + if is_change: + commands_add.append(conf) + commands_del.append(have_conf) + break + + if not in_have: + commands_add.append(conf) + + if cur_state == "overridden": + for have_conf in have: + in_want = next((conf for conf in want if conf['name'] == have_conf['name']), None) + if not in_want: + commands_del.append(have_conf) + + if commands_del: + requests_del = self.get_delete_bgp_communities(commands_del, have, False) + + if len(requests_del) > 0: + commands.extend(update_states(commands_del, "deleted")) + requests.extend(requests_del) + + if commands_add: + requests_add = self.get_modify_bgp_community_requests(commands_add, have, cur_state) + + if len(requests_add) > 0: + commands.extend(update_states(commands_add, cur_state)) + requests.extend(requests_add) + + return commands, requests diff --git a/plugins/module_utils/network/sonic/facts/bgp_communities/bgp_communities.py b/plugins/module_utils/network/sonic/facts/bgp_communities/bgp_communities.py index aa23e71b4..a673a7071 100644 --- a/plugins/module_utils/network/sonic/facts/bgp_communities/bgp_communities.py +++ b/plugins/module_utils/network/sonic/facts/bgp_communities/bgp_communities.py @@ -66,26 +66,34 @@ def get_bgp_communities(self): match = member_config['match-set-options'] permit_str = member_config.get('openconfig-bgp-policy-ext:action', None) members = member_config.get("community-member", []) - result['name'] = name + result['name'] = str(name) result['match'] = match + result['members'] = None + result['permit'] = False if permit_str and permit_str == 'PERMIT': result['permit'] = True - else: - result['permit'] = False if members: result['type'] = 'expanded' if 'REGEX' in members[0] else 'standard' - else: - result['type'] = '' if result['type'] == 'expanded': members = [':'.join(i.split(':')[1:]) for i in members] - result['local_as'] = True if "NO_EXPORT_SUBCONFED" in members else False - result['no_advertise'] = True if "NO_ADVERTISE" in members else False - result['no_export'] = True if "NO_EXPORT" in members else False - result['no_peer'] = True if "NOPEER" in members else False - result['members'] = {'regex': members} + members.sort() + result['members'] = {'regex': members} + else: + result['local_as'] = None + result['no_advertise'] = None + result['no_export'] = None + result['no_peer'] = None + for i in members: + if "NO_EXPORT_SUBCONFED" in i: + result['local_as'] = True + elif "NO_ADVERTISE" in i: + result['no_advertise'] = True + elif "NO_EXPORT" in i: + result['no_export'] = True + elif "NOPEER" in i: + result['no_peer'] = True + bgp_communities_configs.append(result) - # with open('/root/ansible_log.log', 'a+') as fp: - # fp.write('bgp_communities: ' + str(bgp_communities_configs) + '\n') return bgp_communities_configs def populate_facts(self, connection, ansible_facts, data=None): @@ -128,17 +136,5 @@ def render_config(self, spec, conf): :rtype: dictionary :returns: The generated config """ - config = deepcopy(spec) - try: - config['name'] = str(conf['name']) - config['members'] = conf['members'] - config['match'] = conf['match'] - config['type'] = conf['type'] - config['permit'] = conf['permit'] - except TypeError: - config['name'] = None - config['members'] = None - config['match'] = None - config['type'] = None - config['permit'] = None - return utils.remove_empties(config) + + return conf diff --git a/plugins/modules/sonic_bgp_communities.py b/plugins/modules/sonic_bgp_communities.py index 08c8dcc7f..dd1c2b083 100644 --- a/plugins/modules/sonic_bgp_communities.py +++ b/plugins/modules/sonic_bgp_communities.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -52,7 +52,7 @@ required: True type: str description: - - Name of the BGP communitylist. + - Name of the BGP community-list. type: type: str description: @@ -67,6 +67,7 @@ type: bool description: - Permits or denies this community. + - Default value while adding a new community-list is C(False). aann: required: False type: str @@ -120,6 +121,8 @@ choices: - merged - deleted + - replaced + - overridden default: merged """ EXAMPLES = """ @@ -130,18 +133,21 @@ # # show bgp community-list # Standard community list test: match: ANY -# 101 -# 201 -# Standard community list test1: match: ANY -# 301 +# permit local-as +# permit no-peer +# Expanded community list test1: match: ANY +# deny 101 +# deny 302 -- name: Deletes BGP community member +- name: Delete a BGP community-list member dellemc.enterprise_sonic.sonic_bgp_communities: config: - - name: test + - name: test1 + type: expanded + permit: false members: regex: - - 201 + - 302 state: deleted # After state: @@ -149,9 +155,10 @@ # # show bgp community-list # Standard community list test: match: ANY -# 101 -# Standard community list test1: match: ANY -# 301 +# permit local-as +# permit no-peer +# Expanded community list test1: match: ANY +# deny 101 # Using deleted @@ -161,15 +168,17 @@ # # show bgp community-list # Standard community list test: match: ANY -# 101 +# permit local-as +# permit no-peer # Expanded community list test1: match: ANY -# 201 +# deny 101 +# deny 302 -- name: Deletes a single BGP community +- name: Delete a single BGP community-list dellemc.enterprise_sonic.sonic_bgp_communities: config: - name: test - members: + type: standard state: deleted # After state: @@ -177,7 +186,8 @@ # # show bgp community-list # Expanded community list test1: match: ANY -# 201 +# deny 101 +# deny 302 # Using deleted @@ -187,11 +197,13 @@ # # show bgp community-list # Standard community list test: match: ANY -# 101 +# permit local-as +# permit no-peer # Expanded community list test1: match: ANY -# 201 +# deny 101 +# deny 302 -- name: Delete All BGP communities +- name: Delete All BGP community-lists dellemc.enterprise_sonic.sonic_bgp_communities: config: state: deleted @@ -210,14 +222,17 @@ # # show bgp community-list # Standard community list test: match: ANY -# 101 +# permit local-as +# permit no-peer # Expanded community list test1: match: ANY -# 201 +# deny 101 +# deny 302 -- name: Deletes all members in a single BGP community +- name: Delete all members in a single BGP community-list dellemc.enterprise_sonic.sonic_bgp_communities: config: - - name: test + - name: test1 + type: expanded members: regex: state: deleted @@ -226,9 +241,9 @@ # ------------ # # show bgp community-list -# Expanded community list test: match: ANY -# Expanded community list test1: match: ANY -# 201 +# Standard community list test: match: ANY +# permit local-as +# permit no-peer # Using merged @@ -236,23 +251,105 @@ # Before state: # ------------- # -# show bgp as-path-access-list -# AS path list test: +# show bgp community-list +# Expanded community list test1: match: ANY +# permit 101 +# permit 302 -- name: Adds 909.* to test as-path list - dellemc.enterprise_sonic.sonic_bgp_as_paths: +- name: Add a new BGP community-list + dellemc.enterprise_sonic.sonic_bgp_communities: config: - - name: test + - name: test2 + type: expanded + permit: true members: - - 909.* + regex: + - 909 state: merged # After state: # ------------ # -# show bgp as-path-access-list -# AS path list test: -# members: 909.* +# show bgp community-list +# Expanded community list test1: match: ANY +# permit 101 +# permit 302 +# Expanded community list test2: match: ANY +# permit 909 + + +# Using replaced + +# Before state: +# ------------- +# +# show bgp community-list +# Standard community list test: match: ANY +# permit local-as +# permit no-peer +# Expanded community list test1: match: ANY +# deny 101 +# deny 302 + +- name: Replacing a single BGP community-list + dellemc.enterprise_sonic.sonic_bgp_communities: + config: + - name: test + type: expanded + members: + regex: + - 301 + - name: test3 + type: standard + no_advertise: true + no_peer: true + permit: false + match: ALL + state: replaced + +# After state: +# ------------ +# +# show bgp community-list +# Expanded community list test: match: ANY +# deny 301 +# Expanded community list test1: match: ANY +# deny 101 +# deny 302 +# Standard community list test3: match: ALL +# deny no-advertise +# deny no-peer + + +# Using overridden + +# Before state: +# ------------- +# +# show bgp community-list +# Standard community list test: match: ANY +# permit local-as +# permit no-peer +# Expanded community list test1: match: ANY +# deny 101 +# deny 302 + +- name: Override entire BGP community-lists + dellemc.enterprise_sonic.sonic_bgp_communities: + config: + - name: test3 + type: expanded + members: + regex: + - 301 + state: overridden + +# After state: +# ------------ +# +# show bgp community-list +# Expanded community list test3: match: ANY +# deny 301 """ diff --git a/tests/regression/roles/sonic_bgp_communities/defaults/main.yml b/tests/regression/roles/sonic_bgp_communities/defaults/main.yml index eb32d2759..cf27073be 100644 --- a/tests/regression/roles/sonic_bgp_communities/defaults/main.yml +++ b/tests/regression/roles/sonic_bgp_communities/defaults/main.yml @@ -9,7 +9,7 @@ tests: input: - name: test type: expanded - permit: false + permit: true match: ANY members: regex: @@ -17,19 +17,16 @@ tests: - "12" - name: test2 type: standard - permit: true + permit: false + no_export: true match: ALL - members: - regex: - - "21" - - "22" - name: test_case_02 description: Update created BGP properties state: merged input: - name: test type: expanded - permit: false + permit: true match: ANY members: regex: @@ -38,20 +35,16 @@ tests: - 14 - name: test2 type: standard - permit: true + permit: false + no_peer: true match: ALL - members: - regex: - - "23" - - "24" - - 25 - name: test_case_03 description: Update1 created BGP properties state: merged input: - name: test type: expanded - permit: true + permit: false match: ANY members: regex: @@ -59,12 +52,8 @@ tests: - "12" - name: test2 type: standard - permit: false + permit: true match: ALL - members: - regex: - - "21" - - "22" - name: test_case_04 description: Delete BGP properties state: deleted @@ -78,10 +67,7 @@ tests: - name: test2 type: standard match: ALL - members: - regex: - - "23" - - "24" + no_export: true - name: test_case_05 description: Delete1 BGP properties state: deleted @@ -91,11 +77,124 @@ tests: members: regex: - name: test_case_06 - description: Delete2 BGP properties - state: deleted + description: Update2 BGP properties + state: merged input: - name: test + type: expanded + match: ANY + permit: true + members: + regex: + - 201 + - name: test3 + type: expanded + match: ALL + permit: true + members: + regex: + - "110" + - 111 - name: test_case_07 + description: Replace BGP properties + state: replaced + input: + - name: test + type: standard + local_as: true + permit: true + - name: test2 + type: expanded + match: ALL + permit: false + members: + regex: + - "220" + - 222 + - "123" + - name: test_case_08 + description: Replace2 BGP properties + state: replaced + input: + - name: test4 + type: standard + permit: true + no_peer: true + - name: test5 + type: expanded + members: + regex: + - 113 + permit: true + - name: test_case_09 + description: Override BGP properties + state: overridden + input: + - name: test3 + type: standard + local_as: True + permit: false + - name: test2 + type: standard + permit: true + no_export: true + - name: test_case_10 + description: Override2 BGP properties + state: overridden + input: + - name: test3 + type: standard + permit: false + no_export: true + - name: test4 + type: expanded + permit: false + members: + regex: + - 113 + - name: test2 + type: standard + permit: true + no_export: true + - name: test_case_11 + description: Override3 BGP properties + state: overridden + input: + - name: test4 + type: expanded + permit: false + members: + regex: + - 113 + - name: test2 + type: standard + local_as: true + no_peer: true + no_advertise: true + permit: true + no_export: true + - name: test_case_12 + description: Override4 BGP properties + state: overridden + input: + - name: test4 + type: expanded + permit: false + members: + regex: + - 113 + - name: test2 + type: standard + local_as: true + no_advertise: true + permit: true + no_export: true + - name: test_case_13 + description: Delete2 BGP properties + state: deleted + input: + - name: test4 + - name: test_case_14 description: Delete2 BGP properties state: deleted input: [] diff --git a/tests/unit/modules/network/sonic/fixtures/sonic_bgp_communities.yaml b/tests/unit/modules/network/sonic/fixtures/sonic_bgp_communities.yaml index 3493ff6ca..cb827bfe0 100644 --- a/tests/unit/modules/network/sonic/fixtures/sonic_bgp_communities.yaml +++ b/tests/unit/modules/network/sonic/fixtures/sonic_bgp_communities.yaml @@ -6,12 +6,7 @@ merged_01: members: regex: - 808.* - aann: aann_test_str - local_as: False match: ALL - no_advertise: True - no_export: True - no_peer: True permit: True type: expanded existing_bgp_config: @@ -42,15 +37,14 @@ merged_01: community-set-name: 'test' community-member: - REGEX:808.* - - REGEX:NOPEER - - REGEX:NO_EXPORT - - REGEX:NO_ADVERTISE openconfig-bgp-policy-ext:action: 'PERMIT' match-set-options: 'ALL' merged_02: module_args: config: - name: test + type: standard + permit: True local_as: False no_export: True no_peer: True @@ -65,10 +59,7 @@ merged_02: config: community-set-name: 'test' community-member: - - REGEX:808.* - - REGEX:NOPEER - - REGEX:NO_EXPORT - - REGEX:NO_ADVERTISE + - NO_ADVERTISE openconfig-bgp-policy-ext:action: 'PERMIT' match-set-options: 'ALL' expected_config_requests: @@ -81,9 +72,6 @@ merged_02: config: community-set-name: 'test' community-member: - - 808.* - - NOPEER - - NO_EXPORT - NO_ADVERTISE - NOPEER - NO_EXPORT @@ -93,6 +81,7 @@ deleted_01: module_args: config: - name: test + type: expanded members: regex: - 808.* @@ -110,9 +99,9 @@ deleted_01: community-set-name: 'test' community-member: - REGEX:808.* - - REGEX:NOPEER - - REGEX:NO_EXPORT - - REGEX:NO_ADVERTISE + - REGEX:919.* + - REGEX:930.* + - REGEX:772.* openconfig-bgp-policy-ext:action: 'PERMIT' match-set-options: 'ALL' - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" @@ -122,14 +111,22 @@ deleted_01: sonic-vrf:VRF_LIST: - vrf_name: default expected_config_requests: - - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test/config/community-member=808.%2A" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test/config/community-member=REGEX%3A808.%2A" method: "delete" deleted_02: module_args: config: - name: test + type: expanded + match: ALL + permit: True members: - regex: + regex: + - name: test2 + type: standard + match: ANY + permit: False + local_as: True state: deleted existing_bgp_config: - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" @@ -143,11 +140,21 @@ deleted_02: community-set-name: 'test' community-member: - REGEX:808.* - - REGEX:NOPEER - - REGEX:NO_EXPORT - - REGEX:NO_ADVERTISE + - REGEX:919.* + - REGEX:700.* + - REGEX:888.* openconfig-bgp-policy-ext:action: 'PERMIT' match-set-options: 'ALL' + - community-set-name: 'test2' + config: + community-set-name: 'test2' + community-member: + - NO_ADVERTISE + - NOPEER + - NO_EXPORT_SUBCONFED + - NO_EXPORT + openconfig-bgp-policy-ext:action: 'DENY' + match-set-options: 'ANY' - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" response: code: 200 @@ -155,7 +162,9 @@ deleted_02: sonic-vrf:VRF_LIST: - vrf_name: default expected_config_requests: - - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test/config/community-member" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test" + method: "delete" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test2/config/community-member=NO_EXPORT_SUBCONFED" method: "delete" deleted_03: module_args: @@ -171,11 +180,112 @@ deleted_03: - community-set-name: 'test' config: community-set-name: 'test' + community-member: + - NOPEER + - NO_EXPORT + - NO_ADVERTISE + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ALL' + - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" + response: + code: 200 + value: + sonic-vrf:VRF_LIST: + - vrf_name: default + expected_config_requests: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + method: "delete" + +replaced_01: + module_args: + config: + - name: test + members: + regex: + - 808.* + match: ALL + permit: True + type: expanded + state: replaced + existing_bgp_config: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + response: + code: 200 + value: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test' + config: + community-set-name: 'test' + community-member: + - NO_ADVERTISE + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ANY' + - community-set-name: 'test2' + config: + community-set-name: 'test2' + community-member: + - REGEX:808.* + - REGEX:919.* + - REGEX:700.* + - REGEX:888.* + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ALL' + - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" + response: + code: 200 + value: + sonic-vrf:VRF_LIST: + - vrf_name: default + expected_config_requests: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test" + method: "delete" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + method: "patch" + data: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test' + config: + community-set-name: 'test' + community-member: + - REGEX:808.* + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ALL' + +replaced_02: + module_args: + config: + - name: test2 + members: + regex: + - 808.* + match: ALL + permit: False + type: expanded + state: replaced + existing_bgp_config: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + response: + code: 200 + value: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test' + config: + community-set-name: 'test' + community-member: + - NO_ADVERTISE + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ANY' + - community-set-name: 'test2' + config: + community-set-name: 'test2' community-member: - REGEX:808.* - - REGEX:NOPEER - - REGEX:NO_EXPORT - - REGEX:NO_ADVERTISE + - REGEX:919.* + - REGEX:700.* + - REGEX:888.* openconfig-bgp-policy-ext:action: 'PERMIT' match-set-options: 'ALL' - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" @@ -185,5 +295,88 @@ deleted_03: sonic-vrf:VRF_LIST: - vrf_name: default expected_config_requests: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test2" + method: "delete" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + method: "patch" + data: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test2' + config: + community-set-name: 'test2' + community-member: + - REGEX:808.* + openconfig-bgp-policy-ext:action: 'DENY' + match-set-options: 'ALL' + +overridden_01: + module_args: + config: + - name: test + type: standard + permit: True + local_as: True + no_export: True + no_peer: True + - name: test1 + no_advertise: True + permit: true + type: standard + state: overridden + existing_bgp_config: - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + response: + code: 200 + value: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test1' + config: + community-set-name: 'test1' + community-member: + - NO_ADVERTISE + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ANY' + - community-set-name: 'test3' + config: + community-set-name: 'test3' + community-member: + - NO_ADVERTISE + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ANY' + - community-set-name: 'test' + config: + community-set-name: 'test' + community-member: + - REGEX:808.* + - REGEX:919.* + - REGEX:700.* + - REGEX:888.* + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ALL' + - path: "data/sonic-vrf:sonic-vrf/VRF/VRF_LIST" + response: + code: 200 + value: + sonic-vrf:VRF_LIST: + - vrf_name: default + expected_config_requests: + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test" + method: "delete" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets/community-set=test3" method: "delete" + - path: "data/openconfig-routing-policy:routing-policy/defined-sets/openconfig-bgp-policy:bgp-defined-sets/community-sets" + method: "patch" + data: + openconfig-bgp-policy:community-sets: + community-set: + - community-set-name: 'test' + config: + community-set-name: 'test' + community-member: + - NO_EXPORT_SUBCONFED + - NO_EXPORT + - NOPEER + openconfig-bgp-policy-ext:action: 'PERMIT' + match-set-options: 'ANY' diff --git a/tests/unit/modules/network/sonic/test_sonic_bgp_communities.py b/tests/unit/modules/network/sonic/test_sonic_bgp_communities.py index 1d7db62e7..64451a890 100644 --- a/tests/unit/modules/network/sonic/test_sonic_bgp_communities.py +++ b/tests/unit/modules/network/sonic/test_sonic_bgp_communities.py @@ -14,7 +14,7 @@ from .sonic_module import TestSonicModule -class TestSonicBgpModule(TestSonicModule): +class TestSonicBgpCommunitiesModule(TestSonicModule): module = sonic_bgp_communities @classmethod @@ -31,7 +31,7 @@ def setUpClass(cls): cls.fixture_data = cls.load_fixtures('sonic_bgp_communities.yaml') def setUp(self): - super(TestSonicBgpModule, self).setUp() + super(TestSonicBgpCommunitiesModule, self).setUp() self.facts_edit_config = self.mock_facts_edit_config.start() self.config_edit_config = self.mock_config_edit_config.start() @@ -42,7 +42,7 @@ def setUp(self): self.utils_edit_config.side_effect = self.facts_side_effect def tearDown(self): - super(TestSonicBgpModule, self).tearDown() + super(TestSonicBgpCommunitiesModule, self).tearDown() self.mock_facts_edit_config.stop() self.mock_config_edit_config.stop() self.mock_utils_edit_config.stop() @@ -81,3 +81,24 @@ def test_sonic_bgp_communities_deleted_03(self): self.initialize_config_requests(self.fixture_data['deleted_03']['expected_config_requests']) result = self.execute_module(changed=True) self.validate_config_requests() + + def test_sonic_bgp_communities_replaced_01(self): + set_module_args(self.fixture_data['replaced_01']['module_args']) + self.initialize_facts_get_requests(self.fixture_data['replaced_01']['existing_bgp_config']) + self.initialize_config_requests(self.fixture_data['replaced_01']['expected_config_requests']) + result = self.execute_module(changed=True) + self.validate_config_requests() + + def test_sonic_bgp_communities_replaced_02(self): + set_module_args(self.fixture_data['replaced_02']['module_args']) + self.initialize_facts_get_requests(self.fixture_data['replaced_02']['existing_bgp_config']) + self.initialize_config_requests(self.fixture_data['replaced_02']['expected_config_requests']) + result = self.execute_module(changed=True) + self.validate_config_requests() + + def test_sonic_bgp_communities_overridden_01(self): + set_module_args(self.fixture_data['overridden_01']['module_args']) + self.initialize_facts_get_requests(self.fixture_data['overridden_01']['existing_bgp_config']) + self.initialize_config_requests(self.fixture_data['overridden_01']['expected_config_requests']) + result = self.execute_module(changed=True) + self.validate_config_requests()