mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add the ability for the ios_vrf module to apply route targets to a VRF (#34248)
* Add the ability for the ios_vrf module to apply route targets to a VRF * Fix W293 blank line contains whitespace
This commit is contained in:
parent
9d1c48f7a4
commit
d5a8974ef3
2 changed files with 116 additions and 25 deletions
|
@ -85,8 +85,20 @@ options:
|
||||||
in the device active configuration
|
in the device active configuration
|
||||||
default: present
|
default: present
|
||||||
choices: ['present', 'absent']
|
choices: ['present', 'absent']
|
||||||
"""
|
route_both:
|
||||||
|
description:
|
||||||
|
- Adds an export and import list of extended route target communities to the VRF.
|
||||||
|
version_added: "2.5"
|
||||||
|
route_export:
|
||||||
|
description:
|
||||||
|
- Adds an export list of extended route target communities to the VRF.
|
||||||
|
version_added: "2.5"
|
||||||
|
route_import:
|
||||||
|
description:
|
||||||
|
- Adds an import list of extended route target communities to the VRF.
|
||||||
|
version_added: "2.5"
|
||||||
|
|
||||||
|
"""
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: configure a vrf named management
|
- name: configure a vrf named management
|
||||||
ios_vrf:
|
ios_vrf:
|
||||||
|
@ -107,6 +119,30 @@ EXAMPLES = """
|
||||||
- blue
|
- blue
|
||||||
- green
|
- green
|
||||||
purge: yes
|
purge: yes
|
||||||
|
|
||||||
|
- name: Creates a list of import RTs for the VRF with the same parameters
|
||||||
|
ios_vrf:
|
||||||
|
name: test_import
|
||||||
|
rd: 1:100
|
||||||
|
route_import:
|
||||||
|
- 1:100
|
||||||
|
- 3:100
|
||||||
|
|
||||||
|
- name: Creates a list of export RTs for the VRF with the same parameters
|
||||||
|
ios_vrf:
|
||||||
|
name: test_export
|
||||||
|
rd: 1:100
|
||||||
|
route_export:
|
||||||
|
- 1:100
|
||||||
|
- 3:100
|
||||||
|
|
||||||
|
- name: Creates a list of import and export route targets for the VRF with the same parameters
|
||||||
|
ios_vrf:
|
||||||
|
name: test_both
|
||||||
|
rd: 1:100
|
||||||
|
route_both:
|
||||||
|
- 1:100
|
||||||
|
- 3:100
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -205,6 +241,21 @@ def map_obj_to_commands(updates, module):
|
||||||
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)
|
||||||
|
|
||||||
|
if needs_update(want, have, 'route_import'):
|
||||||
|
for route in want['route_import']:
|
||||||
|
cmd = 'route-target import %s' % route
|
||||||
|
add_command_to_vrf(want['name'], cmd, commands)
|
||||||
|
|
||||||
|
if needs_update(want, have, 'route_export'):
|
||||||
|
for route in want['route_export']:
|
||||||
|
cmd = 'route-target export %s' % route
|
||||||
|
add_command_to_vrf(want['name'], cmd, commands)
|
||||||
|
|
||||||
|
if needs_update(want, have, 'route_both'):
|
||||||
|
for route in want['route_both']:
|
||||||
|
cmd = 'route-target both %s' % route
|
||||||
|
add_command_to_vrf(want['name'], cmd, commands)
|
||||||
|
|
||||||
if want['interfaces'] is not None:
|
if want['interfaces'] is not None:
|
||||||
# handle the deletes
|
# handle the deletes
|
||||||
for intf in set(have.get('interfaces', [])).difference(want['interfaces']):
|
for intf in set(have.get('interfaces', [])).difference(want['interfaces']):
|
||||||
|
@ -247,17 +298,38 @@ def parse_rd(configobj, name):
|
||||||
def parse_interfaces(configobj, name):
|
def parse_interfaces(configobj, name):
|
||||||
vrf_cfg = 'vrf forwarding %s' % name
|
vrf_cfg = 'vrf forwarding %s' % name
|
||||||
interfaces = list()
|
interfaces = list()
|
||||||
|
|
||||||
for intf in re.findall('^interface .+', str(configobj), re.M):
|
for intf in re.findall('^interface .+', str(configobj), re.M):
|
||||||
if vrf_cfg in '\n'.join(configobj[intf].children):
|
if vrf_cfg in '\n'.join(configobj[intf].children):
|
||||||
interfaces.append(intf.split(' ')[1])
|
interfaces.append(intf.split(' ')[1])
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def parse_import(configobj, name):
|
||||||
|
cfg = configobj['vrf definition %s' % name]
|
||||||
|
cfg = '\n'.join(cfg.children)
|
||||||
|
matches = re.findall(r'route-target\s+import\s+(.+)', cfg, re.M)
|
||||||
|
return matches
|
||||||
|
|
||||||
|
|
||||||
|
def parse_export(configobj, name):
|
||||||
|
cfg = configobj['vrf definition %s' % name]
|
||||||
|
cfg = '\n'.join(cfg.children)
|
||||||
|
matches = re.findall(r'route-target\s+export\s+(.+)', cfg, re.M)
|
||||||
|
return matches
|
||||||
|
|
||||||
|
|
||||||
|
def parse_both(configobj, name):
|
||||||
|
matches = list()
|
||||||
|
export_match = parse_export(configobj, name)
|
||||||
|
import_match = parse_import(configobj, name)
|
||||||
|
matches.extend(export_match)
|
||||||
|
matches.extend(import_match)
|
||||||
|
return matches
|
||||||
|
|
||||||
|
|
||||||
def map_config_to_obj(module):
|
def map_config_to_obj(module):
|
||||||
config = get_config(module)
|
config = get_config(module)
|
||||||
configobj = NetworkConfig(indent=1, contents=config)
|
configobj = NetworkConfig(indent=1, contents=config)
|
||||||
|
|
||||||
match = re.findall(r'^vrf definition (\S+)', config, re.M)
|
match = re.findall(r'^vrf definition (\S+)', config, re.M)
|
||||||
if not match:
|
if not match:
|
||||||
return list()
|
return list()
|
||||||
|
@ -270,7 +342,10 @@ def map_config_to_obj(module):
|
||||||
'state': 'present',
|
'state': 'present',
|
||||||
'description': parse_description(configobj, item),
|
'description': parse_description(configobj, item),
|
||||||
'rd': parse_rd(configobj, item),
|
'rd': parse_rd(configobj, item),
|
||||||
'interfaces': parse_interfaces(configobj, item)
|
'interfaces': parse_interfaces(configobj, item),
|
||||||
|
'route_import': parse_import(configobj, item),
|
||||||
|
'route_export': parse_export(configobj, item),
|
||||||
|
'route_both': parse_both(configobj, item)
|
||||||
}
|
}
|
||||||
instances.append(obj)
|
instances.append(obj)
|
||||||
return instances
|
return instances
|
||||||
|
@ -322,6 +397,9 @@ def map_params_to_obj(module):
|
||||||
item['rd'] = get_value('rd')
|
item['rd'] = get_value('rd')
|
||||||
item['interfaces'] = get_value('interfaces')
|
item['interfaces'] = get_value('interfaces')
|
||||||
item['state'] = get_value('state')
|
item['state'] = get_value('state')
|
||||||
|
item['route_import'] = get_value('route_import')
|
||||||
|
item['route_export'] = get_value('route_export')
|
||||||
|
item['route_both'] = get_value('route_both')
|
||||||
objects.append(item)
|
objects.append(item)
|
||||||
|
|
||||||
return objects
|
return objects
|
||||||
|
@ -375,6 +453,9 @@ def main():
|
||||||
name=dict(),
|
name=dict(),
|
||||||
description=dict(),
|
description=dict(),
|
||||||
rd=dict(),
|
rd=dict(),
|
||||||
|
route_export=dict(type='list'),
|
||||||
|
route_import=dict(type='list'),
|
||||||
|
route_both=dict(type='list'),
|
||||||
|
|
||||||
interfaces=dict(type='list'),
|
interfaces=dict(type='list'),
|
||||||
|
|
||||||
|
@ -385,8 +466,7 @@ def main():
|
||||||
|
|
||||||
argument_spec.update(ios_argument_spec)
|
argument_spec.update(ios_argument_spec)
|
||||||
|
|
||||||
mutually_exclusive = [('name', 'vrfs')]
|
mutually_exclusive = [('name', 'vrfs'), ('route_import', 'route_both'), ('route_export', 'route_both')]
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec=argument_spec,
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
mutually_exclusive=mutually_exclusive,
|
mutually_exclusive=mutually_exclusive,
|
||||||
supports_check_mode=True)
|
supports_check_mode=True)
|
||||||
|
|
|
@ -27,7 +27,6 @@ from .ios_module import TestIosModule, load_fixture
|
||||||
|
|
||||||
|
|
||||||
class TestIosVrfModule(TestIosModule):
|
class TestIosVrfModule(TestIosModule):
|
||||||
|
|
||||||
module = ios_vrf
|
module = ios_vrf
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -74,9 +73,7 @@ class TestIosVrfModule(TestIosModule):
|
||||||
|
|
||||||
def test_ios_vrf_interfaces(self):
|
def test_ios_vrf_interfaces(self):
|
||||||
set_module_args(dict(name='test_1', interfaces=['Ethernet1']))
|
set_module_args(dict(name='test_1', interfaces=['Ethernet1']))
|
||||||
commands = ['interface Ethernet2', 'no vrf forwarding test_1',
|
commands = ['interface Ethernet2', 'no vrf forwarding test_1', 'interface Ethernet1', 'vrf forwarding test_1', 'ip address 1.2.3.4/5']
|
||||||
'interface Ethernet1', 'vrf forwarding test_1',
|
|
||||||
'ip address 1.2.3.4/5']
|
|
||||||
self.execute_module(changed=True, commands=commands, sort=False)
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
def test_ios_vrf_state_absent(self):
|
def test_ios_vrf_state_absent(self):
|
||||||
|
@ -86,8 +83,7 @@ class TestIosVrfModule(TestIosModule):
|
||||||
|
|
||||||
def test_ios_vrf_purge_all(self):
|
def test_ios_vrf_purge_all(self):
|
||||||
set_module_args(dict(purge=True))
|
set_module_args(dict(purge=True))
|
||||||
commands = ['no vrf definition test_1', 'no vrf definition test_2',
|
commands = ['no vrf definition test_1', 'no vrf definition test_2', 'no vrf definition test_3']
|
||||||
'no vrf definition test_3']
|
|
||||||
self.execute_module(changed=True, commands=commands)
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
def test_ios_vrf_purge_all_but_one(self):
|
def test_ios_vrf_purge_all_but_one(self):
|
||||||
|
@ -98,39 +94,54 @@ class TestIosVrfModule(TestIosModule):
|
||||||
def test_ios_vrfs_no_purge(self):
|
def test_ios_vrfs_no_purge(self):
|
||||||
vrfs = [{'name': 'test_1'}, {'name': 'test_4'}]
|
vrfs = [{'name': 'test_1'}, {'name': 'test_4'}]
|
||||||
set_module_args(dict(vrfs=vrfs))
|
set_module_args(dict(vrfs=vrfs))
|
||||||
commands = ['vrf definition test_4',
|
commands = ['vrf definition test_4', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit']
|
||||||
'address-family ipv4', 'exit',
|
|
||||||
'address-family ipv6', 'exit']
|
|
||||||
self.execute_module(changed=True, commands=commands)
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
def test_ios_vrfs_purge(self):
|
def test_ios_vrfs_purge(self):
|
||||||
vrfs = [{'name': 'test_1'}, {'name': 'test_4'}]
|
vrfs = [{'name': 'test_1'}, {'name': 'test_4'}]
|
||||||
set_module_args(dict(vrfs=vrfs, purge=True))
|
set_module_args(dict(vrfs=vrfs, purge=True))
|
||||||
commands = ['vrf definition test_4',
|
commands = ['vrf definition test_4', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'no vrf definition test_2',
|
||||||
'address-family ipv4', 'exit',
|
|
||||||
'address-family ipv6', 'exit',
|
|
||||||
'no vrf definition test_2',
|
|
||||||
'no vrf definition test_3']
|
'no vrf definition test_3']
|
||||||
self.execute_module(changed=True, commands=commands)
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
def test_ios_vrfs_global_arg(self):
|
def test_ios_vrfs_global_arg(self):
|
||||||
vrfs = [{'name': 'test_1'}, {'name': 'test_2'}]
|
vrfs = [{'name': 'test_1'}, {'name': 'test_2'}]
|
||||||
set_module_args(dict(vrfs=vrfs, description='test string'))
|
set_module_args(dict(vrfs=vrfs, description='test string'))
|
||||||
commands = ['vrf definition test_1', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string',
|
commands = ['vrf definition test_1', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string', 'vrf definition test_2',
|
||||||
'vrf definition test_2', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string']
|
'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string']
|
||||||
self.execute_module(changed=True, commands=commands, sort=False)
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
def test_ios_vrfs_local_override_description(self):
|
def test_ios_vrfs_local_override_description(self):
|
||||||
vrfs = [{'name': 'test_1', 'description': 'test vrf 1'},
|
vrfs = [{'name': 'test_1', 'description': 'test vrf 1'}, {'name': 'test_2'}]
|
||||||
{'name': 'test_2'}]
|
|
||||||
set_module_args(dict(vrfs=vrfs, description='test string'))
|
set_module_args(dict(vrfs=vrfs, description='test string'))
|
||||||
commands = ['vrf definition test_2', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string']
|
commands = ['vrf definition test_2', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'description test string']
|
||||||
self.execute_module(changed=True, commands=commands, sort=False)
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
def test_ios_vrfs_local_override_state(self):
|
def test_ios_vrfs_local_override_state(self):
|
||||||
vrfs = [{'name': 'test_1', 'state': 'absent'},
|
vrfs = [{'name': 'test_1', 'state': 'absent'}, {'name': 'test_2'}]
|
||||||
{'name': 'test_2'}]
|
|
||||||
set_module_args(dict(vrfs=vrfs, description='test string'))
|
set_module_args(dict(vrfs=vrfs, description='test string'))
|
||||||
commands = ['no vrf definition test_1', 'vrf definition test_2', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit',
|
commands = ['no vrf definition test_1', 'vrf definition test_2', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit',
|
||||||
'description test string']
|
'description test string']
|
||||||
self.execute_module(changed=True, commands=commands, sort=False)
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
|
def test_ios_vrf_route_both(self):
|
||||||
|
set_module_args(dict(name='test_5', rd='2:100', route_both=['2:100', '3:100']))
|
||||||
|
commands = ['vrf definition test_5', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'rd 2:100', 'route-target both 2:100',
|
||||||
|
'route-target both 3:100']
|
||||||
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
|
def test_ios_vrf_route_import(self):
|
||||||
|
set_module_args(dict(name='test_6', rd='3:100', route_import=['3:100', '4:100']))
|
||||||
|
commands = ['vrf definition test_6', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'rd 3:100', 'route-target import 3:100',
|
||||||
|
'route-target import 4:100']
|
||||||
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
|
def test_ios_vrf_route_export(self):
|
||||||
|
set_module_args(dict(name='test_7', rd='4:100', route_export=['3:100', '4:100']))
|
||||||
|
commands = ['vrf definition test_7', 'address-family ipv4', 'exit', 'address-family ipv6', 'exit', 'rd 4:100', 'route-target export 3:100',
|
||||||
|
'route-target export 4:100']
|
||||||
|
self.execute_module(changed=True, commands=commands, sort=False)
|
||||||
|
|
||||||
|
def test_ios_vrf_route_both_exclusive(self):
|
||||||
|
set_module_args(dict(name='test_8', rd='5:100', route_both=['3:100', '4:100'], route_export=['3:100', '4:100']))
|
||||||
|
self.execute_module(failed=True)
|
||||||
|
|
Loading…
Reference in a new issue