add support for netconf to junos_template

This commit adds support for sending full syntanx junos configurations using
junos_template and netconf
This commit is contained in:
Peter Sprygada 2016-04-09 10:27:16 -04:00
parent bf2f09e37c
commit a19410483d

View file

@ -15,18 +15,18 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
module: junos_template module: junos_template
version_added: "2.1" version_added: "2.1"
author: "Peter sprygada (@privateip)" author: "Peter Sprygada (@privateip)"
short_description: Manage Juniper JUNOS device configurations short_description: Manage configuration on remote devices running Junos
description: description:
- Manages network device configurations over SSH. This module - The M(junos_template) module will load a candidate configuration
allows implementors to work with the device configuration. It from a template file onto a remote device running Junos. The
provides a way to push a set of commands onto a network device module will return the differences in configuration if the diff
by evaluting the current configuration and only pushing option is specified on the Ansible command line
commands that are not already configured.
extends_documentation_fragment: junos extends_documentation_fragment: junos
options: options:
src: src:
@ -35,17 +35,8 @@ options:
file with config or a template that will be merged during file with config or a template that will be merged during
runtime. By default the task will search for the source runtime. By default the task will search for the source
file in role or playbook root folder in templates directory. file in role or playbook root folder in templates directory.
required: false required: true
default: null default: null
force:
description:
- The force argument instructs the module to not consider the
current devices configuration. 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: [ "true", "false" ]
backup: backup:
description: description:
- When this argument is configured true, the module will backup - When this argument is configured true, the module will backup
@ -54,127 +45,128 @@ options:
the root of the playbook directory. the root of the playbook directory.
required: false required: false
default: false default: false
choices: [ "true", "false" ] choices: ["true", "false"]
config: confirm:
description: description:
- The module, by default, will connect to the remote device and - The C(confirm) argument will configure a time out value for
retrieve the current configuration to use as a base for comparing the commit to be confirmed before it is automatically
against the contents of source. There are times when it is not rolled back. If the C(confirm) argument is set to False, this
desirable to have the task get the current configuration for argument is silently ignored. If the value for this argument
every task in a playbook. The I(config) argument allows the is set to 0, the commit is confirmed immediately.
implementer to pass in the configuruation to use as the base required: false
config for comparision. default: 0
comment:
description:
- The C(comment) argument specifies a text string to be used
when committing the configuration. If the C(confirm) argument
is set to False, this argument is silently ignored.
required: false
default: configured by junos_template
merge:
description:
- The C(merge) argument instructs the module to merge the contents
of C(src) with the configuration running on the remote device. If
both C(merge) and C(overwrite) are set to false, the configuration
is replaced.
required: false
default: true
overwrite:
description:
- The C(overwrite) argument will overwrite the entire configuration
on the remote device with the contents loaded from C(src). If
both C(merge) and C(overwrite) are set to false, the configuration
is replaced.
required: false
default: false
config_format:
description:
- The C(format) argument specifies the format of the configuration
template specified in C(src). If the format argument is not
specified, the module will attempt to infer the configuration
format based of file extension. Files that end in I(xml) will set
the format to xml. Files that end in I(set) will set the format
to set and all other files will default the format to text.
required: false required: false
default: null default: null
choices: ['text', 'xml', 'set']
requirements:
- junos-eznc
notes:
- This module requires the netconf system service be enabled on
the remote device being managed
""" """
EXAMPLES = """ EXAMPLES = """
- junos_template:
- name: push a configuration onto the device
junos_template:
src: config.j2 src: config.j2
comment: update system config
- name: forceable push a configuration onto the device - name: replace config hierarchy
junos_template:
src: config.j2 src: config.j2
force: yes replace: yes
- name: provide the base configuration for comparision
junos_template:
src: candidate_config.txt
config: current_config.txt
- name: overwrite the config
src: config.j2
overwrite: yes
""" """
RETURN = """ DEFAULT_COMMENT = 'configured by junos_template'
commands:
description: The set of commands that will be pushed to the remote device
returned: always
type: list
sample: [...]
"""
def compare(this, other):
parents = [item.text for item in this.parents]
for entry in other:
if this == entry:
return None
return this
def expand(obj, action='set'):
cmd = [action]
cmd.extend([p.text for p in obj.parents])
cmd.append(obj.text)
return ' '.join(cmd)
def flatten(data, obj):
for k, v in data.items():
obj.append(k)
flatten(v, obj)
return obj
def to_lines(config):
lines = list()
for item in config:
if item.raw.endswith(';'):
line = [p.text for p in item.parents]
line.append(item.text)
lines.append(' '.join(line))
return lines
def get_config(module):
config = module.params['config'] or list()
if not config and not module.params['force']:
config = module.config
return config
def main(): def main():
""" main entry point for module execution
"""
argument_spec = dict( argument_spec = dict(
src=dict(), src=dict(required=True, type='path'),
force=dict(default=False, type='bool'), confirm=dict(default=0, type='int'),
comment=dict(default=DEFAULT_COMMENT),
merge=dict(default=True, type='bool'),
overwrite=dict(default=False, type='bool'),
config_format=dict(choices=['text', 'set', 'xml']),
backup=dict(default=False, type='bool'), backup=dict(default=False, type='bool'),
config=dict(), transport=dict(default='netconf', choices=['netconf'])
) )
mutually_exclusive = [('config', 'backup'), ('config', 'force')] mutually_exclusive = [('merge', 'overwrite')]
module = get_module(argument_spec=argument_spec, module = get_module(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
supports_check_mode=True) supports_check_mode=True)
result = dict(changed=False) comment = module.params['comment']
confirm = module.params['confirm']
commit = not module.check_mode
parsed = module.parse_config(module.params['src']) merge = module.params['merge']
commands = to_lines(parsed) overwrite = module.params['overwrite']
contents = get_config(module) src = module.params['src']
result['_backup'] = module.config fmt = module.params['config_format']
parsed = module.parse_config(contents) if overwrite and fmt == 'set':
config = to_lines(parsed) module.fail_json(msg="overwrite cannot be used when format is "
"set per junos documentation")
candidate = list() if merge:
for item in commands: action = 'merge'
if item not in config: elif overwrite:
candidate.append('set %s' % item) action = 'overwrite'
else:
action = 'replace'
if candidate: results = dict(changed=False)
if not module.check_mode: results['_backup'] = str(module.get_config()).strip()
module.configure(candidate)
result['changed'] = True
result['updates'] = candidate diff = module.load_config(src, action=action, comment=comment,
return module.exit_json(**result) format=fmt, commit=commit, confirm=confirm)
if diff:
results['changed'] = True
results['diff'] = dict(prepared=diff)
module.exit_json(**results)
from ansible.module_utils.basic import * from ansible.module_utils.basic import *
from ansible.module_utils.shell import *
from ansible.module_utils.netcfg import *
from ansible.module_utils.junos import * from ansible.module_utils.junos import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()