diff --git a/lib/ansible/modules/network/nxos/nxos_pim.py b/lib/ansible/modules/network/nxos/nxos_pim.py index 625dbfeaeb9..aa67c408124 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim.py +++ b/lib/ansible/modules/network/nxos/nxos_pim.py @@ -31,6 +31,14 @@ description: - Manages configuration of a Protocol Independent Multicast (PIM) instance. author: Gabriele Gerbino (@GGabriele) options: + bfd: + description: + - Enables BFD on all PIM interfaces. + - "Dependency: 'feature bfd'" + version_added: "2.9" + type: str + choices: ['enable', 'disable'] + ssm_range: description: - Configure group ranges for Source Specific Multicast (SSM). @@ -42,8 +50,9 @@ options: required: true ''' EXAMPLES = ''' -- name: Configure ssm_range +- name: Configure ssm_range, enable bfd nxos_pim: + bfd: enable ssm_range: "224.0.0.0/8" - name: Set to default @@ -60,7 +69,9 @@ commands: description: commands sent to the device returned: always type: list - sample: ["ip pim ssm range 224.0.0.0/8"] + sample: + - ip pim bfd + - ip pim ssm range 224.0.0.0/8 ''' @@ -73,7 +84,8 @@ from ansible.module_utils.network.common.config import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { - 'ssm_range': 'ip pim ssm range' + 'bfd': 'ip pim bfd', + 'ssm_range': 'ip pim ssm range', } @@ -82,15 +94,17 @@ def get_existing(module, args): config = str(get_config(module)) for arg in args: - command = PARAM_TO_COMMAND_KEYMAP[arg] - has_command = re.search(r'^{0}\s(?P.*)$'.format(command), config, re.M) + if 'ssm_range' in arg: + # may be 'n.n.n.n/s', 'none', or 'default' + m = re.search(r'ssm range (?P(?:[\s\d.\/]+|none|default))?$', config, re.M) + if m: + # Remove rsvd SSM range + value = m.group('value').replace('232.0.0.0/8', '') + existing[arg] = value.split() + + elif 'bfd' in arg and 'ip pim bfd' in config: + existing[arg] = 'enable' - value = '' - if has_command: - value = has_command.group('value') - if value == '232.0.0.0/8': - value = '' # remove the reserved value - existing[arg] = value.split() return existing @@ -98,7 +112,7 @@ def apply_key_map(key_map, table): new_dict = {} for key, value in table.items(): new_key = key_map.get(key) - if value: + if value is not None: new_dict[new_key] = value return new_dict @@ -108,12 +122,20 @@ def get_commands(module, existing, proposed, candidate): proposed_commands = apply_key_map(PARAM_TO_COMMAND_KEYMAP, proposed) for key, value in proposed_commands.items(): - if key == 'ip pim ssm range' and value == 'default': - # no cmd needs a value but the actual value does not matter - command = 'no ip pim ssm range none' - commands.append(command) - else: - command = '{0} {1}'.format(key, value) + command = '' + if key == 'ip pim ssm range': + if value == 'default': + # no cmd needs a value but the actual value does not matter + command = 'no ip pim ssm range none' + elif value == 'none': + command = 'ip pim ssm range none' + elif value: + command = 'ip pim ssm range {0}'.format(value) + elif key == 'ip pim bfd': + no_cmd = 'no ' if value == 'disable' else '' + command = no_cmd + key + + if command: commands.append(command) if commands: @@ -122,42 +144,52 @@ def get_commands(module, existing, proposed, candidate): def main(): argument_spec = dict( - ssm_range=dict(required=True, type='list'), + bfd=dict(required=False, type='str', choices=['enable', 'disable']), + ssm_range=dict(required=False, type='list', default=[]), ) argument_spec.update(nxos_argument_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - warnings = list() check_args(module, warnings) result = {'changed': False, 'commands': [], 'warnings': warnings} - ssm_range_list = module.params['ssm_range'] - for item in ssm_range_list: - splitted_ssm_range = item.split('.') - if len(splitted_ssm_range) != 4 and item != 'none' and item != 'default': - module.fail_json(msg="Valid ssm_range values are multicast addresses " - "or the keyword 'none' or the keyword 'default'.") + params = module.params + args = [k for k in PARAM_TO_COMMAND_KEYMAP.keys() if params[k] is not None] - args = PARAM_TO_COMMAND_KEYMAP.keys() + # SSM syntax check + if 'ssm_range' in args: + for item in params['ssm_range']: + if re.search('none|default', item): + break + if len(item.split('.')) != 4: + module.fail_json(msg="Valid ssm_range values are multicast addresses " + "or the keyword 'none' or the keyword 'default'.") existing = get_existing(module, args) - proposed_args = dict((k, v) for k, v in module.params.items() if k in args) + proposed_args = dict((k, v) for k, v in params.items() if k in args) proposed = {} for key, value in proposed_args.items(): if key == 'ssm_range': - if value[0] == 'default': + if value and value[0] == 'default': if existing.get(key): proposed[key] = 'default' else: v = sorted(set([str(i) for i in value])) - ex = sorted(set([str(i) for i in existing.get(key)])) + ex = sorted(set([str(i) for i in existing.get(key, [])])) if v != ex: proposed[key] = ' '.join(str(s) for s in v) + elif key == 'bfd': + if value != existing.get('bfd', 'disable'): + proposed[key] = value + + elif value != existing.get(key): + proposed[key] = value + candidate = CustomNetworkConfig(indent=3) get_commands(module, existing, proposed, candidate) diff --git a/test/integration/targets/nxos_pim/tests/common/sanity.yaml b/test/integration/targets/nxos_pim/tests/common/sanity.yaml index e4d25de5d52..be374ec550d 100644 --- a/test/integration/targets/nxos_pim/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_pim/tests/common/sanity.yaml @@ -3,17 +3,24 @@ - debug: msg="Using provider={{ connection.transport }}" when: ansible_connection == "local" -- name: "Setup: Disable feature PIM" +- name: "Setup: Disable features" nxos_feature: &disable_feature - feature: pim + feature: "{{ item }}" provider: "{{ connection }}" state: disabled + ignore_errors: yes + loop: + - pim + - bfd -- name: "Setup: Enable feature PIM" +- name: "Setup: Enable features" nxos_feature: - feature: pim + feature: "{{ item }}" provider: "{{ connection }}" state: enabled + loop: + - pim + - bfd - name: "Setup: Configure ssm_range none" nxos_pim: &none @@ -21,9 +28,10 @@ provider: "{{ connection }}" - block: - - name: Configure ssm_range + - name: Initial config from none nxos_pim: &configure - ssm_range: + bfd: enable + ssm_range: - "239.128.1.0/24" - "224.0.0.0/8" provider: "{{ connection }}" @@ -33,7 +41,7 @@ that: - "result.changed == true" - - name: Check idempotence + - name: Initial config idempotence nxos_pim: *configure register: result @@ -43,13 +51,14 @@ - name: Configure ssm_range default nxos_pim: &conf_default + bfd: disable ssm_range: "default" provider: "{{ connection }}" register: result - assert: *true - - name: Check idempotence + - name: ssm_range default idempotence nxos_pim: *conf_default register: result @@ -61,14 +70,22 @@ - assert: *true - - name: Check idempotence + - meta: end_play + - name: ssm_range none idempotence nxos_pim: *none register: result - assert: *false always: - - name: "Disable feature PIM" - nxos_feature: *disable_feature + - name: "Teardown: Disable features" + nxos_feature: + feature: "{{ item }}" + provider: "{{ connection }}" + state: disabled + ignore_errors: yes + loop: + - pim + - bfd - debug: msg="END connection={{ ansible_connection }} nxos_pim sanity test" diff --git a/test/units/modules/network/nxos/fixtures/nxos_pim/config.cfg b/test/units/modules/network/nxos/fixtures/nxos_pim/config.cfg index 101f1894824..9771622d6f9 100644 --- a/test/units/modules/network/nxos/fixtures/nxos_pim/config.cfg +++ b/test/units/modules/network/nxos/fixtures/nxos_pim/config.cfg @@ -1 +1,2 @@ +ip pim bfd ip pim ssm range 127.0.0.0/31 diff --git a/test/units/modules/network/nxos/test_nxos_pim.py b/test/units/modules/network/nxos/test_nxos_pim.py index da6c1b10433..f4aa4332459 100644 --- a/test/units/modules/network/nxos/test_nxos_pim.py +++ b/test/units/modules/network/nxos/test_nxos_pim.py @@ -43,17 +43,58 @@ class TestNxosPimModule(TestNxosModule): self.mock_load_config.stop() def load_fixtures(self, commands=None, device=''): - self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') self.load_config.return_value = None - def test_nxos_pim(self): - set_module_args(dict(ssm_range='232.0.0.0/8')) - self.execute_module(changed=True, commands=['ip pim ssm range 232.0.0.0/8']) + def test_nxos_pim_1(self): + # Add/ Modify + self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') + set_module_args(dict(ssm_range='233.0.0.0/8')) + self.execute_module(changed=True, commands=[ + 'ip pim ssm range 233.0.0.0/8', + ]) - def test_nxos_pim_none(self): + def test_nxos_pim_2(self): + # Remove existing values + self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') + set_module_args(dict(bfd='disable', ssm_range='none')) + self.execute_module(changed=True, commands=[ + 'no ip pim bfd', + 'ip pim ssm range none', + ]) + + def test_nxos_pim_3(self): + # bfd None (disable)-> enable + self.get_config.return_value = None + set_module_args(dict(bfd='enable')) + self.execute_module(changed=True, commands=['ip pim bfd']) + + # bfd None (disable) -> disable + set_module_args(dict(bfd='disable')) + self.execute_module(changed=False) + + # ssm None to 'default' + set_module_args(dict(ssm_range='default')) + self.execute_module(changed=False) + + def test_nxos_pim_4(self): + # SSM 'none' + self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') set_module_args(dict(ssm_range='none')) self.execute_module(changed=True, commands=['ip pim ssm range none']) - def test_nxos_pim_no_change(self): - set_module_args(dict(ssm_range='127.0.0.0/31')) + def test_nxos_pim_5(self): + # SSM 'default' + self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') + set_module_args(dict(ssm_range='default')) + self.execute_module(changed=True, commands=['no ip pim ssm range none']) + + # SSM 'default' idempotence + self.get_config.return_value = None + set_module_args(dict(ssm_range='default')) + self.execute_module(changed=False) + + def test_nxos_pim_6(self): + # Idempotence + self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg') + set_module_args(dict(bfd='enable', ssm_range='127.0.0.0/31')) self.execute_module(changed=False, commands=[])