summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/network/ios/ios_vrf.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules/network/ios/ios_vrf.py')
-rw-r--r--lib/ansible/modules/network/ios/ios_vrf.py719
1 files changed, 0 insertions, 719 deletions
diff --git a/lib/ansible/modules/network/ios/ios_vrf.py b/lib/ansible/modules/network/ios/ios_vrf.py
deleted file mode 100644
index 1ac01e1339..0000000000
--- a/lib/ansible/modules/network/ios/ios_vrf.py
+++ /dev/null
@@ -1,719 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_vrf
-version_added: "2.3"
-author: "Peter Sprygada (@privateip)"
-short_description: Manage the collection of VRF definitions on Cisco IOS devices
-description:
- - This module provides declarative management of VRF definitions on
- Cisco IOS devices. It allows playbooks to manage individual or
- the entire VRF collection. It also supports purging VRF definitions from
- the configuration that are not explicitly defined.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- vrfs:
- description:
- - The set of VRF definition objects to be configured on the remote
- IOS device. Ths list entries can either be the VRF name or a hash
- of VRF definitions and attributes. This argument is mutually
- exclusive with the C(name) argument.
- name:
- description:
- - The name of the VRF definition to be managed on the remote IOS
- device. The VRF definition name is an ASCII string name used
- to uniquely identify the VRF. This argument is mutually exclusive
- with the C(vrfs) argument
- description:
- description:
- - Provides a short description of the VRF definition in the
- current active configuration. The VRF definition value accepts
- alphanumeric characters used to provide additional information
- about the VRF.
- rd:
- description:
- - The router-distinguisher value uniquely identifies the VRF to
- routing processes on the remote IOS system. The RD value takes
- the form of C(A:B) where C(A) and C(B) are both numeric values.
- interfaces:
- description:
- - Identifies the set of interfaces that
- should be configured in the VRF. Interfaces must be routed
- interfaces in order to be placed into a VRF.
- associated_interfaces:
- description:
- - This is a intent option and checks the operational state of the for given vrf C(name)
- for associated interfaces. If the value in the C(associated_interfaces) does not match with
- the operational state of vrf interfaces on device it will result in failure.
- version_added: "2.5"
- delay:
- description:
- - Time in seconds to wait before checking for the operational state on remote
- device.
- version_added: "2.4"
- default: 10
- purge:
- description:
- - Instructs the module to consider the
- VRF definition absolute. It will remove any previously configured
- VRFs on the device.
- default: false
- type: bool
- state:
- description:
- - Configures the state of the VRF definition
- as it relates to the device operational configuration. When set
- to I(present), the VRF should be configured in the device active
- configuration and when set to I(absent) the VRF should not be
- in the device active configuration
- default: present
- 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"
- route_both_ipv4:
- description:
- - Adds an export and import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_export_ipv4:
- description:
- - Adds an export list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_import_ipv4:
- description:
- - Adds an import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_both_ipv6:
- description:
- - Adds an export and import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_export_ipv6:
- description:
- - Adds an export list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_import_ipv6:
- description:
- - Adds an import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
-
-"""
-EXAMPLES = """
-- name: configure a vrf named management
- ios_vrf:
- name: management
- description: oob mgmt vrf
- interfaces:
- - Management1
-
-- name: remove a vrf named test
- ios_vrf:
- name: test
- state: absent
-
-- name: configure set of VRFs and purge any others
- ios_vrf:
- vrfs:
- - red
- - blue
- - green
- 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 import RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_import_ipv4
- rd: 1:100
- route_import_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of import RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_import_ipv6
- rd: 1:100
- route_import_ipv6:
- - 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 export RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_export_ipv4
- rd: 1:100
- route_export_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of export RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_export_ipv6
- rd: 1:100
- route_export_ipv6:
- - 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
-
-- name: Creates a list of import and export route targets in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_both_ipv4
- rd: 1:100
- route_both_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of import and export route targets in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_both_ipv6
- rd: 1:100
- route_both_ipv6:
- - 1:100
- - 3:100
-
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - vrf definition ansible
- - description management vrf
- - rd: 1:100
-start:
- description: The time the job started
- returned: always
- type: str
- sample: "2016-11-16 10:38:15.126146"
-end:
- description: The time the job ended
- returned: always
- type: str
- sample: "2016-11-16 10:38:25.595612"
-delta:
- description: The time elapsed to perform all operations
- returned: always
- type: str
- sample: "0:00:10.469466"
-"""
-import re
-import time
-from functools import partial
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import exec_command
-from ansible.module_utils.network.ios.ios import load_config, get_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.network.common.config import NetworkConfig
-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):
- if 'vrf definition %s' % name not in commands:
- commands.extend(['vrf definition %s' % name])
- commands.append(cmd)
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
-
- for update in updates:
- want, have = update
-
- def needs_update(want, have, x):
- if isinstance(want.get(x), list) and isinstance(have.get(x), list):
- return want.get(x) and (want.get(x) != have.get(x)) and not all(elem in have.get(x) for elem in want.get(x))
- return want.get(x) and (want.get(x) != have.get(x))
-
- if want['state'] == 'absent':
- commands.append('no vrf definition %s' % want['name'])
- continue
-
- if not have.get('state'):
- commands.extend(['vrf definition %s' % want['name']])
- ipv6 = len([k for k, v in module.params.items() if (k.endswith('_ipv6') or k.endswith('_both')) and v]) != 0
- ipv4 = len([k for k, v in module.params.items() if (k.endswith('_ipv4') or k.endswith('_both')) and v]) != 0
- if ipv4:
- commands.extend(['address-family ipv4', 'exit'])
- if ipv6:
- commands.extend(['address-family ipv6', 'exit'])
-
- if needs_update(want, have, 'description'):
- cmd = 'description %s' % want['description']
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'rd'):
- cmd = 'rd %s' % want['rd']
- 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_import_ipv4'):
- cmd = 'address-family ipv4'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_import_ipv4']:
- cmd = 'route-target import %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_export_ipv4'):
- cmd = 'address-family ipv4'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_export_ipv4']:
- cmd = 'route-target export %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_import_ipv6'):
- cmd = 'address-family ipv6'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_import_ipv6']:
- cmd = 'route-target import %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_export_ipv6'):
- cmd = 'address-family ipv6'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_export_ipv6']:
- cmd = 'route-target export %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if want['interfaces'] is not None:
- # handle the deletes
- for intf in set(have.get('interfaces', [])).difference(want['interfaces']):
- commands.extend(['interface %s' % intf,
- 'no vrf forwarding %s' % want['name']])
-
- # handle the adds
- for intf in set(want['interfaces']).difference(have.get('interfaces', [])):
- cfg = get_config(module)
- configobj = NetworkConfig(indent=1, contents=cfg)
- children = configobj['interface %s' % intf].children
- intf_config = '\n'.join(children)
-
- commands.extend(['interface %s' % intf,
- 'vrf forwarding %s' % want['name']])
-
- match = re.search('ip address .+', intf_config, re.M)
- if match:
- commands.append(match.group())
-
- return commands
-
-
-def parse_description(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'description (.+)$', cfg, re.M)
- if match:
- return match.group(1)
-
-
-def parse_rd(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'rd (.+)$', cfg, re.M)
- if match:
- return match.group(1)
-
-
-def parse_interfaces(configobj):
- vrf_cfg = 'vrf forwarding'
- interfaces = dict()
- for intf in set(re.findall('^interface .+', str(configobj), re.M)):
- for line in configobj[intf].children:
- if vrf_cfg in line:
- try:
- interfaces[line.split()[-1]].append(intf.split(' ')[1])
- except KeyError:
- interfaces[line.split()[-1]] = [intf.split(' ')[1]]
- 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, address_family='global'):
- rd_pattern = re.compile('(?P<rd>.+:.+)')
- matches = list()
- export_match = None
- import_match = None
- if address_family == "global":
- export_match = parse_export(configobj, name)
- import_match = parse_import(configobj, name)
- elif address_family == "ipv4":
- export_match = parse_export_ipv4(configobj, name)
- import_match = parse_import_ipv4(configobj, name)
- elif address_family == "ipv6":
- export_match = parse_export_ipv6(configobj, name)
- import_match = parse_import_ipv6(configobj, name)
- if import_match and export_match:
- for ex in export_match:
- exrd = rd_pattern.search(ex)
- exrd = exrd.groupdict().get('rd')
- for im in import_match:
- imrd = rd_pattern.search(im)
- imrd = imrd.groupdict().get('rd')
- if exrd == imrd:
- matches.extend([exrd]) if exrd not in matches else None
- matches.extend([imrd]) if imrd not in matches else None
- return matches
-
-
-def parse_import_ipv4(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv4']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+import\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_export_ipv4(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv4']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+export\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_import_ipv6(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv6']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+import\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_export_ipv6(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv6']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+export\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def map_config_to_obj(module):
- config = get_config(module)
- configobj = NetworkConfig(indent=1, contents=config)
- match = re.findall(r'^vrf definition (\S+)', config, re.M)
- if not match:
- return list()
-
- instances = list()
-
- interfaces = parse_interfaces(configobj)
-
- for item in set(match):
- obj = {
- 'name': item,
- 'state': 'present',
- 'description': parse_description(configobj, item),
- 'rd': parse_rd(configobj, item),
- 'interfaces': interfaces.get(item),
- 'route_import': parse_import(configobj, item),
- 'route_export': parse_export(configobj, item),
- 'route_both': parse_both(configobj, item),
- 'route_import_ipv4': parse_import_ipv4(configobj, item),
- 'route_export_ipv4': parse_export_ipv4(configobj, item),
- 'route_both_ipv4': parse_both(configobj, item, address_family='ipv4'),
- 'route_import_ipv6': parse_import_ipv6(configobj, item),
- 'route_export_ipv6': parse_export_ipv6(configobj, item),
- 'route_both_ipv6': parse_both(configobj, item, address_family='ipv6'),
- }
- instances.append(obj)
- return instances
-
-
-def get_param_value(key, item, module):
- # if key doesn't exist in the item, get it from module.params
- if not item.get(key):
- value = module.params[key]
-
- # if key does exist, do a type check on it to validate it
- else:
- value_type = module.argument_spec[key].get('type', 'str')
- type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
- type_checker(item[key])
- value = item[key]
-
- # validate the param value (if validator func exists)
- validator = globals().get('validate_%s' % key)
- if validator:
- validator(value, module)
-
- return value
-
-
-def map_params_to_obj(module):
- vrfs = module.params.get('vrfs')
- if not vrfs:
- if not module.params['name'] and module.params['purge']:
- return list()
- elif not module.params['name']:
- module.fail_json(msg='name is required')
- collection = [{'name': module.params['name']}]
- else:
- collection = list()
- for item in vrfs:
- if not isinstance(item, dict):
- collection.append({'name': item})
- elif 'name' not in item:
- module.fail_json(msg='name is required')
- else:
- collection.append(item)
-
- objects = list()
- for item in collection:
- get_value = partial(get_param_value, item=item, module=module)
- item['description'] = get_value('description')
- item['rd'] = get_value('rd')
- item['interfaces'] = get_value('interfaces')
- 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')
- item['route_import_ipv4'] = get_value('route_import_ipv4')
- item['route_export_ipv4'] = get_value('route_export_ipv4')
- item['route_both_ipv4'] = get_value('route_both_ipv4')
- item['route_import_ipv6'] = get_value('route_import_ipv6')
- item['route_export_ipv6'] = get_value('route_export_ipv6')
- item['route_both_ipv6'] = get_value('route_both_ipv6')
- both_addresses_family = ["", "_ipv6", "_ipv4"]
- for address_family in both_addresses_family:
- if item["route_both%s" % address_family]:
- if not item["route_export%s" % address_family]:
- item["route_export%s" % address_family] = list()
- if not item["route_import%s" % address_family]:
- item["route_import%s" % address_family] = list()
- item["route_export%s" % address_family].extend(get_value("route_both%s" % address_family))
- item["route_import%s" % address_family].extend(get_value("route_both%s" % address_family))
- item['associated_interfaces'] = get_value('associated_interfaces')
- objects.append(item)
-
- return objects
-
-
-def update_objects(want, have):
- updates = list()
- for entry in want:
- item = next((i for i in have if i['name'] == entry['name']), None)
- if all((item is None, entry['state'] == 'present')):
- updates.append((entry, {}))
- else:
- for key, value in iteritems(entry):
- if value:
- try:
- if isinstance(value, list):
- if sorted(value) != sorted(item[key]):
- if (entry, item) not in updates:
- updates.append((entry, item))
- elif value != item[key]:
- if (entry, item) not in updates:
- updates.append((entry, item))
- except TypeError:
- pass
- return updates
-
-
-def check_declarative_intent_params(want, module, result):
- if module.params['associated_interfaces']:
-
- if result['changed']:
- time.sleep(module.params['delay'])
-
- name = module.params['name']
- rc, out, err = exec_command(module, 'show vrf | include {0}'.format(name))
-
- if rc == 0:
- data = out.strip().split()
- # data will be empty if the vrf was just added
- if not data:
- return
- vrf = data[0]
- interface = data[-1]
-
- for w in want:
- if w['name'] == vrf:
- if w.get('associated_interfaces') is None:
- continue
- for i in w['associated_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():
- """ main entry point for module execution
- """
- argument_spec = dict(
- vrfs=dict(type='list'),
-
- name=dict(),
- description=dict(),
- rd=dict(),
- route_export=dict(type='list'),
- route_import=dict(type='list'),
- route_both=dict(type='list'),
- route_export_ipv4=dict(type='list'),
- route_import_ipv4=dict(type='list'),
- route_both_ipv4=dict(type='list'),
- route_export_ipv6=dict(type='list'),
- route_import_ipv6=dict(type='list'),
- route_both_ipv6=dict(type='list'),
-
-
- interfaces=dict(type='list'),
- associated_interfaces=dict(type='list'),
-
- delay=dict(default=10, type='int'),
- purge=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent'])
- )
-
- argument_spec.update(ios_argument_spec)
-
- mutually_exclusive = [('name', 'vrfs')]
- module = AnsibleModule(argument_spec=argument_spec,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- result = {'changed': False}
-
- warnings = list()
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
- commands = map_obj_to_commands(update_objects(want, have), module)
-
- if module.params['purge']:
- want_vrfs = [x['name'] for x in want]
- have_vrfs = [x['name'] for x in have]
- for item in set(have_vrfs).difference(want_vrfs):
- cmd = 'no vrf definition %s' % item
- if cmd not in commands:
- commands.append(cmd)
-
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- check_declarative_intent_params(want, module, result)
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()