Skip to content

Commit

Permalink
nxos_interfaces_ospf: fix passive-interface states & check_mode (ansi…
Browse files Browse the repository at this point in the history
…ble#54260)

* nxos_interfaces_ospf: fix passive-interface states & check_mode

This fix addresses issues ansible#41704 and ansible#45343.

The crux of the problem is that `passive-interface` should have been treated as a tri-state value instead of a boolean.

The `no` form of the command disables the passive state on an interface (allows it to form adjacencies and send routing updates).  It's essentially an override for `passive-interface default` which enables passive state on all OSPF interfaces.\*
This `no` config will be present in `running-config`.

   \**See `router ospf` configuration.*

Since both enable and disable states are explicit configs, the proper way to remove either of these is with the `default` syntax.

Passive-interface config syntax:
```
  ip ospf passive-interface              # enable  (nvgens)
  no ip ospf passive-interface           # disable (nvgens)
  default ip ospf passive-interface      # default (removes config, does not nvgen)
```

Code changes:

* `passive_interface` param changed from boolean to string, restricted to `true`,`false`,`default`.

* Several passive-interface specific checks were added because the existing module logic tends to test for true or false and doesn't handle the None case.

* Fixed `check_mode`.

Sanity verified on: N9K,N7K,N3K,N6K

* Fix doc header

* Unit tests for passive-interface

* doc fix #2

* Fix indent for SA

* Remove 'default' keyword, restore bool behavior

* remove changes to sanity
  • Loading branch information
chrisvanheuveln authored and trishnaguha committed Mar 27, 2019
1 parent 98a3fa2 commit 20fb77c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
28 changes: 21 additions & 7 deletions lib/ansible/modules/network/nxos/nxos_interface_ospf.py
Expand Up @@ -67,8 +67,10 @@
integer or the keyword 'default'.
passive_interface:
description:
- Setting to true will prevent this interface from receiving
HELLO packets.
- Enable or disable passive-interface state on this interface.
true - (enable) Prevent OSPF from establishing an adjacency or
sending routing updates on this interface.
false - (disable) Override global 'passive-interface default' for this interface.
type: bool
network:
description:
Expand Down Expand Up @@ -190,9 +192,12 @@ def get_value(arg, config, module):
value = value_list[3]
elif arg == 'passive_interface':
has_no_command = re.search(r'\s+no\s+{0}\s*$'.format(command), config, re.M)
value = False
if has_command and not has_no_command:
if has_no_command:
value = False
elif has_command:
value = True
else:
value = None
elif arg in BOOL_PARAMS:
value = bool(has_command)
else:
Expand Down Expand Up @@ -249,6 +254,8 @@ def get_default_commands(existing, proposed, existing_commands, key, module):
encryption_type,
existing['message_digest_password'])
commands.append(command)
elif 'passive-interface' in key:
commands.append('default ip ospf passive-interface')
else:
commands.append('no {0} {1}'.format(key, existing_value))
return commands
Expand Down Expand Up @@ -332,6 +339,11 @@ def state_absent(module, existing, proposed, candidate):
existing_commands = apply_key_map(PARAM_TO_COMMAND_KEYMAP, existing)

for key, value in existing_commands.items():
if 'ip ospf passive-interface' in key:
# cli is present for both enabled or disabled; 'no' will not remove
commands.append('default ip ospf passive-interface')
continue

if value:
if key.startswith('ip ospf message-digest-key'):
if 'options' not in key:
Expand All @@ -346,8 +358,7 @@ def state_absent(module, existing, proposed, candidate):
encryption_type,
existing['message_digest_password'])
commands.append(command)
elif key in ['ip ospf authentication message-digest',
'ip ospf passive-interface', 'ip ospf network']:
elif key in ['ip ospf authentication message-digest', 'ip ospf network']:
if value:
commands.append('no {0}'.format(key))
elif key == 'ip router ospf':
Expand Down Expand Up @@ -438,6 +449,8 @@ def main():
value = 'default'
if existing.get(key) or (not existing.get(key) and value):
proposed[key] = value
elif 'passive_interface' in key and existing.get(key) is None and value is False:
proposed[key] = value

proposed['area'] = normalize_area(proposed['area'], module)
if 'hello_interval' in proposed and proposed['hello_interval'] == '10':
Expand All @@ -451,7 +464,8 @@ def main():

if candidate:
candidate = candidate.items_text()
load_config(module, candidate)
if not module.check_mode:
load_config(module, candidate)
result['changed'] = True
result['commands'] = candidate

Expand Down
@@ -0,0 +1,7 @@
interface Ethernet1/33
interface Ethernet1/34
ip router ospf 1 area 0.0.0.1
ip ospf passive-interface
interface Ethernet1/35
ip router ospf 1 area 0.0.0.1
no ip ospf passive-interface
30 changes: 30 additions & 0 deletions test/units/modules/network/nxos/test_nxos_interface_ospf.py
Expand Up @@ -56,3 +56,33 @@ def test_loopback_interface_failed(self):
self.execute_module(failed=True, changed=False)
set_module_args(dict(interface='loopback0', ospf=1, area=0, network='broadcast'))
self.execute_module(failed=True, changed=False)

def test_nxos_interface_ospf_passive(self):
# default -> True
set_module_args(dict(interface='ethernet1/33', ospf=1, area=1, passive_interface=True))
self.execute_module(changed=True, commands=['interface Ethernet1/33',
'ip router ospf 1 area 0.0.0.1',
'ip ospf passive-interface'])
# default -> False
set_module_args(dict(interface='ethernet1/33', ospf=1, area=1, passive_interface=False))
self.execute_module(changed=True, commands=['interface Ethernet1/33',
'ip router ospf 1 area 0.0.0.1',
'no ip ospf passive-interface'])
# True -> False
set_module_args(dict(interface='ethernet1/34', ospf=1, area=1, passive_interface=False))
self.execute_module(changed=True, commands=['interface Ethernet1/34',
'no ip ospf passive-interface'])
# True -> default (absent)
set_module_args(dict(interface='ethernet1/34', ospf=1, area=1, state='absent'))
self.execute_module(changed=True, commands=['interface Ethernet1/34',
'no ip router ospf 1 area 0.0.0.1',
'default ip ospf passive-interface'])
# False -> True
set_module_args(dict(interface='ethernet1/35', ospf=1, area=1, passive_interface=True))
self.execute_module(changed=True, commands=['interface Ethernet1/35',
'ip ospf passive-interface'])
# False -> default (absent)
set_module_args(dict(interface='ethernet1/35', ospf=1, area=1, state='absent'))
self.execute_module(changed=True, commands=['interface Ethernet1/35',
'no ip router ospf 1 area 0.0.0.1',
'default ip ospf passive-interface'])

0 comments on commit 20fb77c

Please sign in to comment.