Add ios_vrf declarative intent config check (#28001)
* Add ios_vrf declarative intent config check Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * add version for delay param * modify ios_vrf unit testpull/4420/head
parent
eb33cc88bd
commit
12460dd713
|
@ -62,6 +62,11 @@ options:
|
||||||
- Identifies the set of interfaces that
|
- Identifies the set of interfaces that
|
||||||
should be configured in the VRF. Interfaces must be routed
|
should be configured in the VRF. Interfaces must be routed
|
||||||
interfaces in order to be placed into a VRF.
|
interfaces in order to be placed into a VRF.
|
||||||
|
delay:
|
||||||
|
description:
|
||||||
|
- Time in seconds to wait before checking for the operational state on remote
|
||||||
|
device.
|
||||||
|
version_added: "2.4"
|
||||||
purge:
|
purge:
|
||||||
description:
|
description:
|
||||||
- Instructs the module to consider the
|
- Instructs the module to consider the
|
||||||
|
@ -127,16 +132,37 @@ delta:
|
||||||
sample: "0:00:10.469466"
|
sample: "0:00:10.469466"
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.connection import exec_command
|
||||||
from ansible.module_utils.ios import load_config, get_config
|
from ansible.module_utils.ios import load_config, get_config
|
||||||
from ansible.module_utils.ios import ios_argument_spec, check_args
|
from ansible.module_utils.ios import ios_argument_spec, check_args
|
||||||
from ansible.module_utils.netcfg import NetworkConfig
|
from ansible.module_utils.netcfg import NetworkConfig
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
|
|
||||||
|
def get_interface_type(interface):
|
||||||
|
|
||||||
|
if interface.upper().startswith('ET'):
|
||||||
|
return 'ethernet'
|
||||||
|
elif interface.upper().startswith('VL'):
|
||||||
|
return 'svi'
|
||||||
|
elif interface.upper().startswith('LO'):
|
||||||
|
return 'loopback'
|
||||||
|
elif interface.upper().startswith('MG'):
|
||||||
|
return 'management'
|
||||||
|
elif interface.upper().startswith('MA'):
|
||||||
|
return 'management'
|
||||||
|
elif interface.upper().startswith('PO'):
|
||||||
|
return 'portchannel'
|
||||||
|
elif interface.upper().startswith('NV'):
|
||||||
|
return 'nve'
|
||||||
|
else:
|
||||||
|
return 'unknown'
|
||||||
|
|
||||||
|
|
||||||
def add_command_to_vrf(name, cmd, commands):
|
def add_command_to_vrf(name, cmd, commands):
|
||||||
if 'vrf definition %s' % name not in commands:
|
if 'vrf definition %s' % name not in commands:
|
||||||
commands.append('vrf definition %s' % name)
|
commands.append('vrf definition %s' % name)
|
||||||
|
@ -149,7 +175,8 @@ def map_obj_to_commands(updates, module):
|
||||||
for update in updates:
|
for update in updates:
|
||||||
want, have = update
|
want, have = update
|
||||||
|
|
||||||
needs_update = lambda x: want.get(x) and (want.get(x) != have.get(x))
|
def needs_update(want, have, x):
|
||||||
|
return want.get(x) and (want.get(x) != have.get(x))
|
||||||
|
|
||||||
if want['state'] == 'absent':
|
if want['state'] == 'absent':
|
||||||
commands.append('no vrf definition %s' % want['name'])
|
commands.append('no vrf definition %s' % want['name'])
|
||||||
|
@ -158,11 +185,11 @@ def map_obj_to_commands(updates, module):
|
||||||
if not have.get('state'):
|
if not have.get('state'):
|
||||||
commands.append('vrf definition %s' % want['name'])
|
commands.append('vrf definition %s' % want['name'])
|
||||||
|
|
||||||
if needs_update('description'):
|
if needs_update(want, have, 'description'):
|
||||||
cmd = 'description %s' % want['description']
|
cmd = 'description %s' % want['description']
|
||||||
add_command_to_vrf(want['name'], cmd, commands)
|
add_command_to_vrf(want['name'], cmd, commands)
|
||||||
|
|
||||||
if needs_update('rd'):
|
if needs_update(want, have, 'rd'):
|
||||||
cmd = 'rd %s' % want['rd']
|
cmd = 'rd %s' % want['rd']
|
||||||
add_command_to_vrf(want['name'], cmd, commands)
|
add_command_to_vrf(want['name'], cmd, commands)
|
||||||
|
|
||||||
|
@ -300,18 +327,36 @@ def update_objects(want, have):
|
||||||
updates.append((entry, item))
|
updates.append((entry, item))
|
||||||
return updates
|
return updates
|
||||||
|
|
||||||
|
|
||||||
|
def check_declarative_intent_params(want, module):
|
||||||
|
if module.params['interfaces']:
|
||||||
|
name = module.params['name']
|
||||||
|
rc, out, err = exec_command(module, 'show vrf | include {0}'.format(name))
|
||||||
|
|
||||||
|
if rc == 0:
|
||||||
|
data = out.strip().split()
|
||||||
|
vrf = data[0]
|
||||||
|
interface = data[-1]
|
||||||
|
|
||||||
|
for w in want:
|
||||||
|
if w['name'] == vrf:
|
||||||
|
for i in w['interfaces']:
|
||||||
|
if get_interface_type(i) is not get_interface_type(interface):
|
||||||
|
module.fail_json(msg="Interface %s not configured on vrf %s" % (interface, name))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
""" main entry point for module execution
|
""" main entry point for module execution
|
||||||
"""
|
"""
|
||||||
argument_spec = dict(
|
argument_spec = dict(
|
||||||
vrfs=dict(type='list'),
|
vrfs=dict(type='list'),
|
||||||
name=dict(),
|
|
||||||
|
|
||||||
|
name=dict(),
|
||||||
description=dict(),
|
description=dict(),
|
||||||
rd=dict(),
|
rd=dict(),
|
||||||
|
|
||||||
interfaces=dict(type='list'),
|
interfaces=dict(type='list'),
|
||||||
|
|
||||||
|
delay=dict(default=10, type='int'),
|
||||||
purge=dict(type='bool', default=False),
|
purge=dict(type='bool', default=False),
|
||||||
state=dict(default='present', choices=['present', 'absent'])
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
)
|
)
|
||||||
|
@ -350,6 +395,11 @@ def main():
|
||||||
load_config(module, commands)
|
load_config(module, commands)
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
|
|
||||||
|
if result['changed']:
|
||||||
|
time.sleep(module.params['delay'])
|
||||||
|
|
||||||
|
check_declarative_intent_params(want, module)
|
||||||
|
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -38,12 +38,17 @@ class TestIosVrfModule(TestIosModule):
|
||||||
self.mock_load_config = patch('ansible.modules.network.ios.ios_vrf.load_config')
|
self.mock_load_config = patch('ansible.modules.network.ios.ios_vrf.load_config')
|
||||||
self.load_config = self.mock_load_config.start()
|
self.load_config = self.mock_load_config.start()
|
||||||
|
|
||||||
|
self.mock_exec_command = patch('ansible.modules.network.ios.ios_vrf.exec_command')
|
||||||
|
self.exec_command = self.mock_exec_command.start()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.mock_get_config.stop()
|
self.mock_get_config.stop()
|
||||||
self.mock_load_config.stop()
|
self.mock_load_config.stop()
|
||||||
|
self.mock_exec_command.stop()
|
||||||
|
|
||||||
def load_fixtures(self, commands=None):
|
def load_fixtures(self, commands=None):
|
||||||
self.get_config.return_value = load_fixture('ios_vrf_config.cfg')
|
self.get_config.return_value = load_fixture('ios_vrf_config.cfg')
|
||||||
|
self.exec_command.return_value = (0, load_fixture('ios_vrf_config.cfg').strip(), None)
|
||||||
self.load_config.return_value = None
|
self.load_config.return_value = None
|
||||||
|
|
||||||
def test_ios_vrf_name(self):
|
def test_ios_vrf_name(self):
|
||||||
|
|
Loading…
Reference in New Issue