1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# (c) 2017, Ansible by Red Hat, inc
5#
6# This file is part of Ansible by Red Hat
7#
8# Ansible is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# Ansible is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
20#
21
22ANSIBLE_METADATA = {'metadata_version': '1.1',
23                    'status': ['preview'],
24                    'supported_by': 'network'}
25
26DOCUMENTATION = """
27---
28module: vyos_banner
29version_added: "2.4"
30author: "Trishna Guha (@trishnaguha)"
31short_description: Manage multiline banners on VyOS devices
32description:
33  - This will configure both pre-login and post-login banners on remote
34    devices running VyOS. It allows playbooks to add or remote
35    banner text from the active running configuration.
36notes:
37  - Tested against VyOS 1.1.8 (helium).
38  - This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
39options:
40  banner:
41    description:
42      - Specifies which banner that should be
43        configured on the remote device.
44    required: true
45    choices: ['pre-login', 'post-login']
46  text:
47    description:
48      - The banner text that should be
49        present in the remote device running configuration. This argument
50        accepts a multiline string, with no empty lines. Requires I(state=present).
51  state:
52    description:
53      - Specifies whether or not the configuration is present in the current
54        devices active running configuration.
55    default: present
56    choices: ['present', 'absent']
57extends_documentation_fragment: vyos
58"""
59
60EXAMPLES = """
61- name: configure the pre-login banner
62  vyos_banner:
63    banner: pre-login
64    text: |
65      this is my pre-login banner
66      that contains a multiline
67      string
68    state: present
69- name: remove the post-login banner
70  vyos_banner:
71    banner: post-login
72    state: absent
73"""
74
75RETURN = """
76commands:
77  description: The list of configuration mode commands to send to the device
78  returned: always
79  type: list
80  sample:
81    - banner pre-login
82    - this is my pre-login banner
83    - that contains a multiline
84    - string
85"""
86
87import re
88
89from ansible.module_utils.basic import AnsibleModule
90from ansible.module_utils.network.vyos.vyos import get_config, load_config
91from ansible.module_utils.network.vyos.vyos import vyos_argument_spec
92
93
94def spec_to_commands(updates, module):
95    commands = list()
96    want, have = updates
97    state = module.params['state']
98
99    if state == 'absent':
100        if have.get('state') != 'absent' or (have.get('state') != 'absent' and
101                                             'text' in have.keys() and have['text']):
102            commands.append('delete system login banner %s' % module.params['banner'])
103
104    elif state == 'present':
105        if want['text'] and want['text'].encode().decode('unicode_escape') != have.get('text'):
106            banner_cmd = 'set system login banner %s ' % module.params['banner']
107            banner_cmd += want['text'].strip()
108            commands.append(banner_cmd)
109
110    return commands
111
112
113def config_to_dict(module):
114    data = get_config(module)
115    output = None
116    obj = {'banner': module.params['banner'], 'state': 'absent'}
117
118    for line in data.split('\n'):
119        if line.startswith('set system login banner %s' % obj['banner']):
120            match = re.findall(r'%s (.*)' % obj['banner'], line, re.M)
121            output = match
122    if output:
123        obj['text'] = output[0].encode().decode('unicode_escape')
124        obj['state'] = 'present'
125
126    return obj
127
128
129def map_params_to_obj(module):
130    text = module.params['text']
131    if text:
132        text = "%r" % (str(text).strip())
133
134    return {
135        'banner': module.params['banner'],
136        'text': text,
137        'state': module.params['state']
138    }
139
140
141def main():
142    """ main entry point for module execution
143    """
144    argument_spec = dict(
145        banner=dict(required=True, choices=['pre-login', 'post-login']),
146        text=dict(),
147        state=dict(default='present', choices=['present', 'absent'])
148    )
149
150    argument_spec.update(vyos_argument_spec)
151
152    required_if = [('state', 'present', ('text',))]
153
154    module = AnsibleModule(argument_spec=argument_spec,
155                           required_if=required_if,
156                           supports_check_mode=True)
157
158    warnings = list()
159
160    result = {'changed': False}
161    if warnings:
162        result['warnings'] = warnings
163
164    want = map_params_to_obj(module)
165    have = config_to_dict(module)
166
167    commands = spec_to_commands((want, have), module)
168    result['commands'] = commands
169
170    if commands:
171        commit = not module.check_mode
172        load_config(module, commands, commit=commit)
173        result['changed'] = True
174
175    module.exit_json(**result)
176
177
178if __name__ == '__main__':
179    main()
180