Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nxos_pim: Add bfd support #56908

Merged
merged 4 commits into from Jun 19, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Next

nxos_pim: Add bfd support

  • Loading branch information...
chrisvanheuveln committed May 24, 2019
commit 2a484ae9073a5fae9aa02857a28cf061dbab3ff3
@@ -31,6 +31,12 @@
- 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: bool
ssm_range:
description:
- Configure group ranges for Source Specific Multicast (SSM).
@@ -42,8 +48,9 @@
required: true
'''
EXAMPLES = '''
- name: Configure ssm_range
- name: Configure ssm_range, enable bfd
nxos_pim:
bfd: true
ssm_range: "224.0.0.0/8"
- name: Set to default
@@ -60,7 +67,9 @@
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 +82,8 @@


PARAM_TO_COMMAND_KEYMAP = {
'ssm_range': 'ip pim ssm range'
'bfd': 'ip pim bfd',
'ssm_range': 'ip pim ssm range',
}


@@ -83,22 +93,25 @@ def get_existing(module, args):

for arg in args:
command = PARAM_TO_COMMAND_KEYMAP[arg]
has_command = re.search(r'^{0}\s(?P<value>.*)$'.format(command), config, re.M)

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()
if 'ssm_range' in arg:
# <value> may be 'n.n.n.n/s', 'none', or 'default'
m = re.search(r'ssm range (?P<value>(?:[\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:
existing[arg] = arg in config

return existing


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 +121,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
This conversation was marked as resolved by chrisvanheuveln

This comment has been minimized.

Copy link
@mikewiebe

mikewiebe May 29, 2019

Contributor

Is this true for all platforms?

This comment has been minimized.

Copy link
@chrisvanheuveln

chrisvanheuveln May 30, 2019

Author Contributor

Yes. I tested this against all of our regression platforms.

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 = '' if value else 'no '
command = no_cmd + key

if command:
commands.append(command)

if commands:
@@ -122,41 +143,45 @@ def get_commands(module, existing, proposed, candidate):

def main():
argument_spec = dict(
ssm_range=dict(required=True, type='list'),
bfd=dict(required=False, type='bool'),
This conversation was marked as resolved by chrisvanheuveln

This comment has been minimized.

Copy link
@mikewiebe

mikewiebe May 29, 2019

Contributor

Since there are no required parameters now, should you add a local method to validate inputs? What happens if you call the module with no parameters?

This comment has been minimized.

Copy link
@chrisvanheuveln

chrisvanheuveln May 30, 2019

Author Contributor

bfd still gets a bool type check so nothing's needed there.

ssm_range gets validated on lines 161-167.

If no parameters are specified then it's idempotent; e.g.

  "msg": {
        "changed": false,
        "commands": [],
        "failed": false
    }

Plus, that would be silly. Just sayin'.

This comment has been minimized.

Copy link
@mikewiebe

mikewiebe May 30, 2019

Contributor

I know.. just could not help myself.. had to ask... Just sayin'

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 = {}
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 value != existing.get(key):
proposed[key] = value

candidate = CustomNetworkConfig(indent=3)
get_commands(module, existing, proposed, candidate)
@@ -1 +1,2 @@
ip pim bfd
ip pim ssm range 127.0.0.0/31
@@ -43,17 +43,49 @@ def tearDown(self):
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(bfd=True, 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_2(self):
# Remove existing values
self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg')
set_module_args(dict(bfd=False, 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 -> true
self.get_config.return_value = None
set_module_args(dict(bfd=True))
self.execute_module(changed=True, commands=['ip pim bfd'])

def test_nxos_pim_none(self):
# 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'])

def test_nxos_pim_6(self):
# Idempotence
self.get_config.return_value = load_fixture('nxos_pim', 'config.cfg')
set_module_args(dict(bfd=True, ssm_range='127.0.0.0/31'))
self.execute_module(changed=False, commands=[])
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.