1#!/usr/local/bin/python3.8
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019-2020 Fortinet, Inc.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18__metaclass__ = type
19
20ANSIBLE_METADATA = {'status': ['preview'],
21                    'supported_by': 'community',
22                    'metadata_version': '1.1'}
23
24DOCUMENTATION = '''
25---
26module: fortios_wireless_controller_spectral_info
27short_description: Wireless controller spectrum analysis in Fortinet's FortiOS and FortiGate.
28description:
29    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
30      user to set and modify wireless_controller feature and spectral_info category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.0
33version_added: "2.10"
34author:
35    - Link Zheng (@chillancezen)
36    - Jie Xue (@JieX19)
37    - Hongbin Lu (@fgtdev-hblu)
38    - Frank Shen (@frankshen01)
39    - Miguel Angel Munoz (@mamunozgonzalez)
40    - Nicolas Thomas (@thomnico)
41notes:
42    - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks
43
44requirements:
45    - ansible>=2.9.0
46options:
47    access_token:
48        description:
49            - Token-based authentication.
50              Generated from GUI of Fortigate.
51        type: str
52        required: false
53    enable_log:
54        description:
55            - Enable/Disable logging for task.
56        type: bool
57        required: false
58        default: false
59    vdom:
60        description:
61            - Virtual domain, among those defined previously. A vdom is a
62              virtual instance of the FortiGate that can be configured and
63              used as a different unit.
64        type: str
65        default: root
66
67    wireless_controller_spectral_info:
68        description:
69            - Wireless controller spectrum analysis.
70        default: null
71        type: dict
72        suboptions:
73            set_wtp_id:
74                description:
75                    - WTP ID.
76                type: str
77'''
78
79EXAMPLES = '''
80- hosts: fortigates
81  collections:
82    - fortinet.fortios
83  connection: httpapi
84  vars:
85   vdom: "root"
86   ansible_httpapi_use_ssl: yes
87   ansible_httpapi_validate_certs: no
88   ansible_httpapi_port: 443
89  tasks:
90  - name: Wireless controller spectrum analysis.
91    fortios_wireless_controller_spectral_info:
92      vdom:  "{{ vdom }}"
93      wireless_controller_spectral_info:
94        set_wtp_id: "<your_own_value>"
95
96'''
97
98RETURN = '''
99build:
100  description: Build number of the fortigate image
101  returned: always
102  type: str
103  sample: '1547'
104http_method:
105  description: Last method used to provision the content into FortiGate
106  returned: always
107  type: str
108  sample: 'PUT'
109http_status:
110  description: Last result given by FortiGate on last operation applied
111  returned: always
112  type: str
113  sample: "200"
114mkey:
115  description: Master key (id) used in the last call to FortiGate
116  returned: success
117  type: str
118  sample: "id"
119name:
120  description: Name of the table used to fulfill the request
121  returned: always
122  type: str
123  sample: "urlfilter"
124path:
125  description: Path of the table used to fulfill the request
126  returned: always
127  type: str
128  sample: "webfilter"
129revision:
130  description: Internal revision number
131  returned: always
132  type: str
133  sample: "17.0.2.10658"
134serial:
135  description: Serial number of the unit
136  returned: always
137  type: str
138  sample: "FGVMEVYYQT3AB5352"
139status:
140  description: Indication of the operation's result
141  returned: always
142  type: str
143  sample: "success"
144vdom:
145  description: Virtual domain used
146  returned: always
147  type: str
148  sample: "root"
149version:
150  description: Version of the FortiGate
151  returned: always
152  type: str
153  sample: "v5.6.3"
154
155'''
156from ansible.module_utils.basic import AnsibleModule
157from ansible.module_utils.connection import Connection
158from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
159from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
160from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
161from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
162from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
163from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
164from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
165
166
167def filter_wireless_controller_spectral_info_data(json):
168    option_list = ['set_wtp_id']
169    dictionary = {}
170
171    for attribute in option_list:
172        if attribute in json and json[attribute] is not None:
173            dictionary[attribute] = json[attribute]
174
175    return dictionary
176
177
178def underscore_to_hyphen(data):
179    if isinstance(data, list):
180        for i, elem in enumerate(data):
181            data[i] = underscore_to_hyphen(elem)
182    elif isinstance(data, dict):
183        new_data = {}
184        for k, v in data.items():
185            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
186        data = new_data
187
188    return data
189
190
191def valid_attr_to_invalid_attr(data):
192    specillist = {"[wtp_id]": "set_wtp_id"}
193
194    for k, v in specillist.items():
195        if v == data:
196            return k
197
198    return data
199
200
201def valid_attr_to_invalid_attrs(data):
202    if isinstance(data, list):
203        for elem in data:
204            elem = valid_attr_to_invalid_attrs(elem)
205    elif isinstance(data, dict):
206        new_data = {}
207        for k, v in data.items():
208            new_data[valid_attr_to_invalid_attr(k)] = valid_attr_to_invalid_attrs(v)
209        data = new_data
210
211    return data
212
213
214def wireless_controller_spectral_info(data, fos):
215    vdom = data['vdom']
216    wireless_controller_spectral_info_data = data['wireless_controller_spectral_info']
217    filtered_data = underscore_to_hyphen(filter_wireless_controller_spectral_info_data(wireless_controller_spectral_info_data))
218    converted_data = valid_attr_to_invalid_attrs(filtered_data)
219
220    return fos.set('wireless-controller',
221                   'spectral-info',
222                   data=converted_data,
223                   vdom=vdom)
224
225
226def is_successful_status(status):
227    return status['status'] == "success" or \
228        status['http_method'] == "DELETE" and status['http_status'] == 404
229
230
231def fortios_wireless_controller(data, fos):
232
233    if data['wireless_controller_spectral_info']:
234        resp = wireless_controller_spectral_info(data, fos)
235    else:
236        fos._module.fail_json(msg='missing task body: %s' % ('wireless_controller_spectral_info'))
237
238    return not is_successful_status(resp), \
239        resp['status'] == "success" and \
240        (resp['revision_changed'] if 'revision_changed' in resp else True), \
241        resp
242
243
244versioned_schema = {
245    "type": "dict",
246    "children": {
247        "[wtp_id]": {
248            "type": "string",
249            "revisions": {
250                "v7.0.0": True,
251                "v6.4.4": True,
252                "v6.4.0": True,
253                "v6.4.1": True,
254                "v6.2.0": True,
255                "v6.2.5": True,
256                "v6.2.7": True
257            }
258        }
259    },
260    "revisions": {
261        "v7.0.0": True,
262        "v6.4.4": True,
263        "v6.4.0": True,
264        "v6.4.1": True,
265        "v6.2.0": True,
266        "v6.2.5": True,
267        "v6.2.7": True
268    }
269}
270
271
272def main():
273    module_spec = schema_to_module_spec(versioned_schema)
274    mkeyname = None
275    fields = {
276        "access_token": {"required": False, "type": "str", "no_log": True},
277        "enable_log": {"required": False, "type": bool},
278        "vdom": {"required": False, "type": "str", "default": "root"},
279        "wireless_controller_spectral_info": {
280            "required": False, "type": "dict", "default": None,
281            "options": {
282            }
283        }
284    }
285    for attribute_name in module_spec['options']:
286        fields["wireless_controller_spectral_info"]['options'][attribute_name] = module_spec['options'][attribute_name]
287        if mkeyname and mkeyname == attribute_name:
288            fields["wireless_controller_spectral_info"]['options'][attribute_name]['required'] = True
289
290    check_legacy_fortiosapi()
291    module = AnsibleModule(argument_spec=fields,
292                           supports_check_mode=False)
293
294    versions_check_result = None
295    if module._socket_path:
296        connection = Connection(module._socket_path)
297        if 'access_token' in module.params:
298            connection.set_option('access_token', module.params['access_token'])
299
300        if 'enable_log' in module.params:
301            connection.set_option('enable_log', module.params['enable_log'])
302        else:
303            connection.set_option('enable_log', False)
304        fos = FortiOSHandler(connection, module, mkeyname)
305        versions_check_result = check_schema_versioning(fos, versioned_schema, "wireless_controller_spectral_info")
306
307        is_error, has_changed, result = fortios_wireless_controller(module.params, fos)
308
309    else:
310        module.fail_json(**FAIL_SOCKET_MSG)
311
312    if versions_check_result and versions_check_result['matched'] is False:
313        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
314
315    if not is_error:
316        if versions_check_result and versions_check_result['matched'] is False:
317            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
318        else:
319            module.exit_json(changed=has_changed, meta=result)
320    else:
321        if versions_check_result and versions_check_result['matched'] is False:
322            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
323        else:
324            module.fail_json(msg="Error in repo", meta=result)
325
326
327if __name__ == '__main__':
328    main()
329