summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Sprygada <privateip@users.noreply.github.com>2016-08-26 21:39:36 -0400
committerGitHub <noreply@github.com>2016-08-26 21:39:36 -0400
commit5917a736234e2ac2bdc111dfe19d2b59a570344f (patch)
tree8c9b7274894d78286c0064ad47c2c6b03fc30181
parenta093fb1c83d51c7c8a4eb4a1dbc098735e25ebbc (diff)
parentcababe0947b01fa1e7bf6e1b65424564a9bbd68c (diff)
downloadansible-modules-core-5917a736234e2ac2bdc111dfe19d2b59a570344f.tar.gz
Merge pull request #4563 from privateip/iosxr_config
update iosxr_config with new arguments
-rw-r--r--network/iosxr/iosxr_config.py273
1 files changed, 198 insertions, 75 deletions
diff --git a/network/iosxr/iosxr_config.py b/network/iosxr/iosxr_config.py
index 1f9f4d4c..63c2a702 100644
--- a/network/iosxr/iosxr_config.py
+++ b/network/iosxr/iosxr_config.py
@@ -26,9 +26,8 @@ description:
- Cisco IOS XR configurations use a simple block indent file syntax
for segmenting 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
+ a deterministic way.
+extends_documentation_fragment: iosxr
options:
lines:
description:
@@ -37,7 +36,9 @@ options:
in the device running-config. Be sure to note the configuration
command syntax as some commands are automatically modified by the
device config parser.
- required: true
+ required: false
+ default: null
+ aliases: ['commands']
parents:
description:
- The ordered set of parents that uniquely identify the section
@@ -46,6 +47,16 @@ options:
level or global commands.
required: false
default: null
+ src:
+ description:
+ - Specifies the source path to the file that contains the configuration
+ or configuration template to load. The path to the source file can
+ either be the full path on the Ansible control host or a relative
+ path from the playbook or role root directory. This argument is mutually
+ exclusive with I(lines).
+ required: false
+ default: null
+ version_added: "2.2"
before:
description:
- The ordered set of commands to push on to the command stack if
@@ -69,11 +80,13 @@ options:
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.
+ to position. If match is set to I(exact), command lines
+ must be an equal match. Finally, if match is set to I(none), the
+ module will not attempt to compare the source configuration with
+ the running configuration on the remote device.
required: false
default: line
- choices: ['line', 'strict', 'exact']
+ choices: ['line', 'strict', 'exact', 'none']
replace:
description:
- Instructs the module on the way to perform the configuration
@@ -91,9 +104,26 @@ options:
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.
+ - Note this argument should be considered deprecated. To achieve
+ the equivalent, set the match argument to none. This argument
+ will be removed in a future release.
required: false
default: false
- choices: [ "true", "false" ]
+ choices: [ "yes", "no" ]
+ version_added: "2.2"
+ update:
+ description:
+ - The I(update) argument controls how the configuration statements
+ are processed on the remote device. Valid choices for the I(update)
+ argument are I(merge) and I(check). When the argument is set to
+ I(merge), the configuration changes are merged with the current
+ device running configuration. When the argument is set to I(check)
+ the configuration updates are determined but not actually configured
+ on the remote device.
+ required: false
+ default: merge
+ choices: ['merge', 'replace', 'check']
+ version_added: "2.2"
config:
description:
- The module, by default, will connect to the remote device and
@@ -105,25 +135,56 @@ options:
config for comparison.
required: false
default: null
+ backup:
+ description:
+ - This argument will cause the module to create a full backup of
+ the current C(running-config) from the remote device before any
+ changes are made. The backup file is written to the C(backup)
+ folder in the playbook root directory. If the directory does not
+ exist, it is created.
+ required: false
+ default: no
+ choices: ['yes', 'no']
+ version_added: "2.2"
+ comment:
+ description:
+ - Allows a commit description to be specified to be included
+ when the configuration is committed. If the configuration is
+ not changed or committed, this argument is ignored.
+ required: false
+ default: 'configured by iosxr_config'
+ version_added: "2.2"
"""
EXAMPLES = """
-- iosxr_config:
- lines: ['hostname {{ inventory_hostname }}']
- force: yes
+# Note: examples below use the following provider dict to handle
+# transport and authentication to the node.
+vars:
+ cli:
+ host: "{{ inventory_hostname }}"
+ username: cisco
+ password: cisco
+ transport: cli
-- iosxr_config:
- lines:
- - description configured by ansible
- - ipv4 address 10.0.0.25 255.255.255.0
- parents: ['interface GigabitEthernet0/0/0/0']
+- name: configure top level configuration
+ iosxr_config:
+ lines: hostname {{ inventory_hostname }}
+ provider: "{{ cli }}"
-- iosxr_config:
- commands: "{{lookup('file', 'datcenter1.txt')}}"
- parents: ['ipv4 access-list test']
- before: ['no ip access-listv4 test']
- replace: block
+- name: configure interface settings
+ iosxr_config:
+ lines:
+ - description test interface
+ - ip address 172.31.1.1 255.255.255.0
+ parents: interface GigabitEthernet0/0/0/0
+ provider: "{{ cli }}"
+- name: load a config from disk and replace the current config
+ iosxr_config:
+ src: config.cfg
+ update: replace
+ backup: yes
+ provider: "{{ cli }}"
"""
RETURN = """
@@ -132,82 +193,144 @@ updates:
returned: always
type: list
sample: ['...', '...']
-
-responses:
- description: The set of responses from issuing the commands on the device
- retured: always
- type: list
- sample: ['...', '...']
+backup_path:
+ description: The full path to the backup file
+ returned: when backup is yes
+ type: path
+ sample: /playbooks/ansible/backup/iosxr01.2016-07-16@22:28:34
"""
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, dumps
+from ansible.module_utils.iosxr import NetworkModule, NetworkError
-def get_config(module):
- config = module.params['config'] or dict()
- if not config and not module.params['force']:
- config = module.config
- return config
+DEFAULT_COMMIT_COMMENT = 'configured by iosxr_config'
-def main():
+def invoke(name, *args, **kwargs):
+ func = globals().get(name)
+ if func:
+ return func(*args, **kwargs)
+
+def check_args(module, warnings):
+ if module.params['parents']:
+ if not module.params['lines'] or module.params['src']:
+ warnings.append('ignoring unnecessary argument parents')
+ if module.params['match'] == 'none' and module.params['replace']:
+ warnings.append('ignoring unnecessary argument replace')
+ if module.params['update'] == 'replace' and not module.params['src']:
+ module.fail_json(msg='Must specify src when update is `replace`')
+ if module.params['force']:
+ warnings.append('The force argument is deprecated, please use '
+ 'match=none instead. This argument will be '
+ 'removed in the future')
+
+
+def get_config(module, result):
+ contents = module.params['config'] or result.get('__config__')
+ if not contents:
+ contents = module.config.get_config()
+ return NetworkConfig(indent=1, contents=contents)
+
+def get_candidate(module):
+ candidate = NetworkConfig(indent=1)
+ if module.params['src']:
+ candidate.load(module.params['src'])
+ elif module.params['lines']:
+ parents = module.params['parents'] or list()
+ candidate.add(module.params['lines'], parents=parents)
+ return candidate
+
+def load_config(module, commands, result):
+ replace = module.params['update'] == 'replace'
+ comment = module.params['comment']
+ commit = not module.check_mode
+ diff = module.config.load_config(commands, replace=replace, commit=commit,
+ comment=comment)
+ result['diff'] = dict(prepared=diff)
+ result['changed'] = True
+
+def run(module, result):
+ match = module.params['match']
+ replace = module.params['replace']
+ update = module.params['update']
+
+ candidate = get_candidate(module)
+
+ if match != 'none' and update != 'replace':
+ config = get_config(module, result)
+ configobjs = candidate.difference(config, match=match, replace=replace)
+ else:
+ config = None
+ configobjs = candidate.items
+
+ if configobjs:
+ commands = dumps(configobjs, 'commands')
+
+ if module.params['before']:
+ commands[:0] = module.params['before']
+
+ if module.params['after']:
+ commands.extend(module.params['after'])
+
+ result['updates'] = commands.split('\n')
+
+ if update != 'check':
+ load_config(module, commands, result)
+
+def main():
+ """main entry point for module execution
+ """
argument_spec = dict(
- lines=dict(aliases=['commands'], required=True, type='list'),
+ lines=dict(aliases=['commands'], type='list'),
parents=dict(type='list'),
+
+ src=dict(type='path'),
+
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()
+ match=dict(default='line', choices=['line', 'strict', 'exact', 'none']),
+ replace=dict(default='line', choices=['line', 'block']),
- before = module.params['before']
- after = module.params['after']
+ update=dict(choices=['merge', 'replace', 'check'], default='merge'),
+ backup=dict(type='bool', default=False),
+ comment=dict(default=DEFAULT_COMMIT_COMMENT),
- match = module.params['match']
- replace = module.params['replace']
+ # this argument is deprecated in favor of setting match: none
+ # it will be removed in a future version
+ force=dict(default=False, type='bool'),
- contents = get_config(module)
- config = module.parse_config(contents)
+ config=dict(),
+ )
- if not module.params['force']:
- contents = get_config(module)
- config = NetworkConfig(contents=contents, indent=1)
+ mutually_exclusive = [('lines', 'src')]
- candidate = NetworkConfig(indent=1)
- candidate.add(lines, parents=parents)
+ module = NetworkModule(argument_spec=argument_spec,
+ connect_on_load=False,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True)
- commands = candidate.difference(config, path=parents, match=match, replace=replace)
- else:
- commands = parents
- commands.extend(lines)
+ if module.params['force'] is True:
+ module.params['match'] = 'none'
- result = dict(changed=False)
+ warnings = list()
+ check_args(module, warnings)
- if commands:
- if before:
- commands[:0] = before
+ result = dict(changed=False, warnings=warnings)
- if after:
- commands.extend(after)
+ if module.params['backup']:
+ config = module.config.get_config()
+ result['__config__'] = config
+ result['__backup__'] = config
- if not module.check_mode:
- commands = [str(c).strip() for c in commands]
- response = module.configure(commands)
- result['responses'] = response
- result['changed'] = True
+ try:
+ run(module, result)
+ except NetworkError:
+ exc = get_exception()
+ module.fail_json(msg=str(exc), **exc.kwargs)
- result['updates'] = commands
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()