diff options
author | Peter Sprygada <psprygada@ansible.com> | 2016-02-12 17:00:15 -0500 |
---|---|---|
committer | Peter Sprygada <psprygada@ansible.com> | 2016-02-12 17:04:30 -0500 |
commit | 0e270da561d28504d5d09e95293c86d2db3bf8b8 (patch) | |
tree | 8985959a2fce179769f338240f4f316d096742d1 /network/iosxr/iosxr_config.py | |
parent | fb82e08e73fbe9b0f5a6ce380ec705964d54c87f (diff) | |
download | ansible-modules-core-0e270da561d28504d5d09e95293c86d2db3bf8b8.tar.gz |
initial add of iosxr_config module
This adds a new module, iosxr_config, that can be used for configuring
Cisco IOS XR devices. It is provides a set of arguments for sending
configuration commands to the device over cli
Diffstat (limited to 'network/iosxr/iosxr_config.py')
-rw-r--r-- | network/iosxr/iosxr_config.py | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/network/iosxr/iosxr_config.py b/network/iosxr/iosxr_config.py new file mode 100644 index 00000000..24299c59 --- /dev/null +++ b/network/iosxr/iosxr_config.py @@ -0,0 +1,256 @@ +#!/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/>. +# + +DOCUMENTATION = """ +--- +module: iosxr_config +version_added: "2.1" +author: "Peter sprygada (@privateip)" +short_description: Manage Cisco IOS XR configuration sections +description: + - Cisco IOS XR configurations use a simple block indent file sytanx + for segementing configuration into sections. This module provides + an implementation for working with IOS XR configuration sections in + a deterministic way. This module works with either CLI or NXAPI + transports. +extends_documentation_fragment: ios +options: + lines: + description: + - The ordered set of commands that should be configured in the + section. The commands must be the exact same commands as found + in the device running-config. Be sure to note the configuration + command syntanx as some commands are automatically modified by the + device config parser. + required: true + parents: + description: + - The ordered set of parents that uniquely identify the section + the commands should be checked against. If the parents argument + is omitted, the commands are checked against the set of top + level or global commands. + required: false + default: null + before: + description: + - The ordered set of commands to push on to the command stack if + a change needs to be made. This allows the playbook designer + the opportunity to perform configuration commands prior to pushing + any changes without affecting how the set of commands are matched + against the system + required: false + default: null + after: + description: + - The ordered set of commands to append to the end of the command + stack if a changed needs to be made. Just like with I(before) this + allows the playbook designer to append a set of commands to be + executed after the command set. + required: false + default: null + match: + description: + - Instructs the module on the way to perform the matching of + the set of commands against the current device config. If + match is set to I(line), commands are matched line by line. If + match is set to I(strict), command lines are matched with respect + to position. Finally if match is set to I(exact), command lines + must be an equal match. + required: false + default: line + choices: ['line', 'strict', 'exact'] + replace: + description: + - Instructs the module on the way to perform the configuration + on the device. If the replace argument is set to I(line) then + the modified lines are pushed to the device in configuration + mode. If the replace argument is set to I(block) then the entire + command block is pushed to the device in configuration mode if any + line is not correct + required: false + default: line + choices: ['line', 'block'] + force: + description: + - The force argument instructs the module to not consider the + current devices running-config. When set to true, this will + cause the module to push the contents of I(src) into the device + without first checking if already configured. + required: false + default: false + choices: BOOLEANS + config: + description: + - The module, by default, will connect to the remote device and + retrieve the current running-config to use as a base for comparing + against the contents of source. There are times when it is not + desirable to have the task get the current running-config for + every task in a playbook. The I(config) argument allows the + implementer to pass in the configuruation to use as the base + config for comparision. + required: false + default: null +""" + +EXAMPLES = """ +- iosxr_config: + lines: ['hostname {{ inventory_hostname }}'] + force: yes + +- iosxr_config: + lines: + - description configured by ansible + - ipv4 address 10.0.0.25 255.255.255.0 + parents: ['interface GigabitEthernet0/0/0/0'] + +- iosxr_config: + commands: "{{lookup('file', 'datcenter1.txt'}}" + parents: ['ipv4 access-list test'] + before: ['no ip access-listv4 test'] + replace: block + +""" + +RETURN = """ +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['...', '...'] + +responses: + description: The set of responses from issuing the commands on the device + retured: always + type: list + sample: ['...', '...'] +""" +import re +import itertools + +def get_config(module): + config = module.params['config'] or dict() + if not config and not module.params['force']: + config = module.config + return config + + +def build_candidate(lines, parents, config, strategy): + candidate = list() + + if strategy == 'strict': + if len(lines) != len(config): + candidate = list(lines) + else: + for index, cmd in enumerate(lines): + try: + if cmd != config[index]: + candidate.append(cmd) + except IndexError: + candidate.append(cmd) + + elif strategy == 'exact': + if len(lines) != len(config): + candidate = list(lines) + else: + for cmd, cfg in itertools.izip(lines, config): + if cmd != cfg: + candidate = list(lines) + break + + else: + for cmd in lines: + if cmd not in config: + candidate.append(cmd) + + return candidate + + +def main(): + + argument_spec = dict( + lines=dict(aliases=['commands'], required=True, type='list'), + parents=dict(type='list'), + before=dict(type='list'), + after=dict(type='list'), + match=dict(default='line', choices=['line', 'strict', 'exact']), + replace=dict(default='line', choices=['line', 'block']), + force=dict(default=False, type='bool'), + config=dict() + ) + + module = get_module(argument_spec=argument_spec, + supports_check_mode=True) + + lines = module.params['lines'] + parents = module.params['parents'] or list() + + before = module.params['before'] + after = module.params['after'] + + match = module.params['match'] + replace = module.params['replace'] + + contents = get_config(module) + config = module.parse_config(contents) + + if parents: + for parent in parents: + for item in config: + if item.text == parent: + config = item + + try: + children = [c.text for c in config.children] + except AttributeError: + children = [c.text for c in config] + + else: + children = [c.text for c in config if not c.parents] + + result = dict(changed=False) + + candidate = build_candidate(lines, parents, children, match) + + if candidate: + if replace == 'line': + candidate[:0] = parents + else: + candidate = list(parents) + candidate.extend(lines) + + if before: + candidate[:0] = before + + if after: + candidate.extend(after) + + if not module.check_mode: + response = module.configure(candidate) + result['responses'] = response + result['changed'] = True + + result['updates'] = candidate + return module.exit_json(**result) + +from ansible.module_utils.basic import * +from ansible.module_utils.shell import * +from ansible.module_utils.netcfg import * +from ansible.module_utils.iosxr import * +if __name__ == '__main__': + main() + |