summaryrefslogtreecommitdiff
path: root/network/sros/sros_rollback.py
blob: 85d7bdc5067859ad5498161180e22107dd792e5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/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 = {'status': ['preview'],
                    'supported_by': 'community',
                    'version': '1.0'}

DOCUMENTATION = """
---
module: sros_rollback
version_added: "2.2"
author: "Peter Sprygada (@privateip)"
short_description: Configure Nokia SR OS rollback
description:
  - Configure the rollback feature on remote Nokia devices running
    the SR OS 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 SR OS
    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 SR OS
    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_checkpoints=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()