diff --git a/lib/ansible/modules/network/sros/sros_rollback.py b/lib/ansible/modules/network/sros/sros_rollback.py new file mode 100644 index 00000000000..d04437fb32f --- /dev/null +++ b/lib/ansible/modules/network/sros/sros_rollback.py @@ -0,0 +1,219 @@ +#!/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 . +# + +DOCUMENTATION = """ +--- +module: sros_rollback +version_added: "2.2" +author: "Peter Sprygada (@privateip)" +short_description: Configure Nokia SROS rollback +description: + - Configure the rollback feature on remote Nokia devices running + the SROS operating system. this module provides a stateful + implementation for managing the configuration of the rollback + feature +extends_documentation_fragment: sros +options: + rollback_location: + description: + - The I(rollback_location) specifies the location and filename + of the rollback checkpoint files. This argument supports any + valid local or remote URL as specified in SROS + required: false + default: null + remote_max_checkpoints: + description: + - The I(remote_max_checkpoints) argument configures the maximum + number of rollback files that can be transfered and saved to + a remote location. Valid values for this argument are in the + range of 1 to 50 + required: false + default: null + local_max_checkpoints: + description: + - The I(local_max_checkpoints) argument configures the maximum + number of rollback files that can be saved on the devices local + compact flash. Valid values for this argument are in the range + of 1 to 50 + required: false + default: null + rescue_location: + description: + - The I(rescue_location) specifies the location of the + rescue file. This argument supports any valid local + or remote URL as specified in SROS + required: false + default: null + state: + description: + - The I(state) argument specifies the state of the configuration + entries in the devices active configuration. When the state + value is set to C(true) the configuration is present in the + devices active configuration. When the state value is set to + C(false) the configuration values are removed from the devices + active configuration. + required: false + default: present + choices: ['present', 'absent'] +""" + +EXAMPLES = """ +# Note: examples below use the following provider dict to handle +# transport and authentication to the node. +vars: + cli: + host: "{{ inventory_hostname }}" + username: admin + password: admin + transport: cli + +- name: configure rollback location + sros_rollback: + rollback_location: "cb3:/ansible" + provider: "{{ cli }}" + +- name: remove all rollback configuration + sros_rollback: + state: absent + provider: "{{ cli }}" +""" + +RETURN = """ +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['...', '...'] +""" +from ansible.module_utils.basic import get_exception +from ansible.module_utils.sros import NetworkModule, NetworkError +from ansible.module_utils.netcfg import NetworkConfig, dumps + +def invoke(name, *args, **kwargs): + func = globals().get(name) + if func: + return func(*args, **kwargs) + +def sanitize_config(lines): + commands = list() + for line in lines: + for index, entry in enumerate(commands): + if line.startswith(entry): + del commands[index] + break + commands.append(line) + return commands + +def present(module, commands): + setters = set() + for key, value in module.argument_spec.iteritems(): + if module.params[key] is not None: + setter = value.get('setter') or 'set_%s' % key + if setter not in setters: + setters.add(setter) + invoke(setter, module, commands) + +def absent(module, commands): + config = module.config.get_config() + if 'rollback-location' in config: + commands.append('configure system rollback no rollback-location') + if 'rescue-location' in config: + commands.append('configure system rollback no rescue-location') + if 'remote-max-checkpoints' in config: + commands.append('configure system rollback no remote-max-checkpoints') + if 'local-max-checkpoints' in config: + commands.append('configure system rollback no remote-max-checkpoints') + +def set_rollback_location(module, commands): + value = module.params['rollback_location'] + commands.append('configure system rollback rollback-location "%s"' % value) + +def set_local_max_checkpoints(module, commands): + value = module.params['local_max_checkpoints'] + if not 1 <= value <= 50: + module.fail_json(msg='local_max_checkpoints must be between 1 and 50') + commands.append('configure system rollback local-max-checkpoints %s' % value) + +def set_remote_max_checkpoints(module, commands): + value = module.params['remote_max_checkpoints'] + if not 1 <= value <= 50: + module.fail_json(msg='remote_max_checkpoints must be between 1 and 50') + commands.append('configure system rollback remote-max-checkpoints %s' % value) + +def set_rescue_location(module, commands): + value = module.params['rescue_location'] + commands.append('configure system rollback rescue-location "%s"' % value) + +def get_config(module): + contents = module.config.get_config() + return NetworkConfig(device_os='sros', contents=contents) + +def load_config(module, commands, result): + candidate = NetworkConfig(device_os='sros', contents='\n'.join(commands)) + config = get_config(module) + configobjs = candidate.difference(config) + + if configobjs: + commands = dumps(configobjs, 'lines') + commands = sanitize_config(commands.split('\n')) + + result['updates'] = commands + + # send the configuration commands to the device and merge + # them with the current running config + if not module.check_mode: + module.config(commands) + + result['changed'] = True + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + rollback_location=dict(), + + local_max_checkpoints=dict(type='int'), + remote_max_checkpionts=dict(type='int'), + + rescue_location=dict(), + + state=dict(default='present', choices=['present', 'absent']) + ) + + module = NetworkModule(argument_spec=argument_spec, + connect_on_load=False, + supports_check_mode=True) + + state = module.params['state'] + + result = dict(changed=False) + + commands = list() + invoke(state, module, commands) + + try: + load_config(module, commands, result) + except NetworkError: + exc = get_exception() + module.fail_json(msg=str(exc), **exc.kwargs) + + module.exit_json(**result) + + +if __name__ == '__main__': + main()