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 test
pull/4420/head
Trishna Guha 2017-08-14 12:27:03 +05:30 committed by GitHub
parent eb33cc88bd
commit 12460dd713
2 changed files with 61 additions and 6 deletions

View File

@ -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__':

View File

@ -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):