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_system_ftm_push
27short_description: Configure FortiToken Mobile push services 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 system feature and ftm_push 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    system_ftm_push:
68        description:
69            - Configure FortiToken Mobile push services.
70        default: null
71        type: dict
72        suboptions:
73            server:
74                description:
75                    - IPv4 address or domain name of FortiToken Mobile push services server.
76                type: str
77            server_cert:
78                description:
79                    - Name of the server certificate to be used for SSL . Source certificate.local.name.
80                type: str
81            server_ip:
82                description:
83                    - 'IPv4 address of FortiToken Mobile push services server (format: xxx.xxx.xxx.xxx).'
84                type: str
85            server_port:
86                description:
87                    - Port to communicate with FortiToken Mobile push services server (1 - 65535).
88                type: int
89            status:
90                description:
91                    - Enable/disable the use of FortiToken Mobile push services.
92                type: str
93                choices:
94                    - enable
95                    - disable
96'''
97
98EXAMPLES = '''
99- hosts: fortigates
100  collections:
101    - fortinet.fortios
102  connection: httpapi
103  vars:
104   vdom: "root"
105   ansible_httpapi_use_ssl: yes
106   ansible_httpapi_validate_certs: no
107   ansible_httpapi_port: 443
108  tasks:
109  - name: Configure FortiToken Mobile push services.
110    fortios_system_ftm_push:
111      vdom:  "{{ vdom }}"
112      system_ftm_push:
113        server: "192.168.100.40"
114        server_cert: "<your_own_value> (source certificate.local.name)"
115        server_ip: "<your_own_value>"
116        server_port: "6"
117        status: "enable"
118
119'''
120
121RETURN = '''
122build:
123  description: Build number of the fortigate image
124  returned: always
125  type: str
126  sample: '1547'
127http_method:
128  description: Last method used to provision the content into FortiGate
129  returned: always
130  type: str
131  sample: 'PUT'
132http_status:
133  description: Last result given by FortiGate on last operation applied
134  returned: always
135  type: str
136  sample: "200"
137mkey:
138  description: Master key (id) used in the last call to FortiGate
139  returned: success
140  type: str
141  sample: "id"
142name:
143  description: Name of the table used to fulfill the request
144  returned: always
145  type: str
146  sample: "urlfilter"
147path:
148  description: Path of the table used to fulfill the request
149  returned: always
150  type: str
151  sample: "webfilter"
152revision:
153  description: Internal revision number
154  returned: always
155  type: str
156  sample: "17.0.2.10658"
157serial:
158  description: Serial number of the unit
159  returned: always
160  type: str
161  sample: "FGVMEVYYQT3AB5352"
162status:
163  description: Indication of the operation's result
164  returned: always
165  type: str
166  sample: "success"
167vdom:
168  description: Virtual domain used
169  returned: always
170  type: str
171  sample: "root"
172version:
173  description: Version of the FortiGate
174  returned: always
175  type: str
176  sample: "v5.6.3"
177
178'''
179from ansible.module_utils.basic import AnsibleModule
180from ansible.module_utils.connection import Connection
181from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
182from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
183from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
184from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
185from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
186from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
187from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
188
189
190def filter_system_ftm_push_data(json):
191    option_list = ['server', 'server_cert', 'server_ip',
192                   'server_port', 'status']
193    dictionary = {}
194
195    for attribute in option_list:
196        if attribute in json and json[attribute] is not None:
197            dictionary[attribute] = json[attribute]
198
199    return dictionary
200
201
202def underscore_to_hyphen(data):
203    if isinstance(data, list):
204        for i, elem in enumerate(data):
205            data[i] = underscore_to_hyphen(elem)
206    elif isinstance(data, dict):
207        new_data = {}
208        for k, v in data.items():
209            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
210        data = new_data
211
212    return data
213
214
215def system_ftm_push(data, fos):
216    vdom = data['vdom']
217    system_ftm_push_data = data['system_ftm_push']
218    filtered_data = underscore_to_hyphen(filter_system_ftm_push_data(system_ftm_push_data))
219
220    return fos.set('system',
221                   'ftm-push',
222                   data=filtered_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_system(data, fos):
232
233    if data['system_ftm_push']:
234        resp = system_ftm_push(data, fos)
235    else:
236        fos._module.fail_json(msg='missing task body: %s' % ('system_ftm_push'))
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        "status": {
248            "type": "string",
249            "options": [
250                {
251                    "value": "enable",
252                    "revisions": {
253                        "v6.0.0": True,
254                        "v7.0.0": True,
255                        "v6.0.5": True,
256                        "v6.4.4": True,
257                        "v6.4.0": True,
258                        "v6.4.1": True,
259                        "v6.2.0": True,
260                        "v6.2.3": True,
261                        "v6.2.5": True,
262                        "v6.2.7": True,
263                        "v6.0.11": True
264                    }
265                },
266                {
267                    "value": "disable",
268                    "revisions": {
269                        "v6.0.0": True,
270                        "v7.0.0": True,
271                        "v6.0.5": True,
272                        "v6.4.4": True,
273                        "v6.4.0": True,
274                        "v6.4.1": True,
275                        "v6.2.0": True,
276                        "v6.2.3": True,
277                        "v6.2.5": True,
278                        "v6.2.7": True,
279                        "v6.0.11": True
280                    }
281                }
282            ],
283            "revisions": {
284                "v6.0.0": True,
285                "v7.0.0": True,
286                "v6.0.5": True,
287                "v6.4.4": True,
288                "v6.4.0": True,
289                "v6.4.1": True,
290                "v6.2.0": True,
291                "v6.2.3": True,
292                "v6.2.5": True,
293                "v6.2.7": True,
294                "v6.0.11": True
295            }
296        },
297        "server_cert": {
298            "type": "string",
299            "revisions": {
300                "v6.4.4": True,
301                "v7.0.0": True,
302                "v6.4.0": True,
303                "v6.4.1": True
304            }
305        },
306        "server_port": {
307            "type": "integer",
308            "revisions": {
309                "v6.0.0": True,
310                "v7.0.0": True,
311                "v6.0.5": True,
312                "v6.4.4": True,
313                "v6.4.0": True,
314                "v6.4.1": True,
315                "v6.2.0": True,
316                "v6.2.3": True,
317                "v6.2.5": True,
318                "v6.2.7": True,
319                "v6.0.11": True
320            }
321        },
322        "server_ip": {
323            "type": "string",
324            "revisions": {
325                "v6.0.0": True,
326                "v7.0.0": True,
327                "v6.0.5": True,
328                "v6.4.4": True,
329                "v6.4.0": True,
330                "v6.4.1": True,
331                "v6.2.0": True,
332                "v6.2.3": True,
333                "v6.2.5": True,
334                "v6.2.7": True,
335                "v6.0.11": True
336            }
337        },
338        "server": {
339            "type": "string",
340            "revisions": {
341                "v7.0.0": True
342            }
343        }
344    },
345    "revisions": {
346        "v6.0.0": True,
347        "v7.0.0": True,
348        "v6.0.5": True,
349        "v6.4.4": True,
350        "v6.4.0": True,
351        "v6.4.1": True,
352        "v6.2.0": True,
353        "v6.2.3": True,
354        "v6.2.5": True,
355        "v6.2.7": True,
356        "v6.0.11": True
357    }
358}
359
360
361def main():
362    module_spec = schema_to_module_spec(versioned_schema)
363    mkeyname = None
364    fields = {
365        "access_token": {"required": False, "type": "str", "no_log": True},
366        "enable_log": {"required": False, "type": bool},
367        "vdom": {"required": False, "type": "str", "default": "root"},
368        "system_ftm_push": {
369            "required": False, "type": "dict", "default": None,
370            "options": {
371            }
372        }
373    }
374    for attribute_name in module_spec['options']:
375        fields["system_ftm_push"]['options'][attribute_name] = module_spec['options'][attribute_name]
376        if mkeyname and mkeyname == attribute_name:
377            fields["system_ftm_push"]['options'][attribute_name]['required'] = True
378
379    check_legacy_fortiosapi()
380    module = AnsibleModule(argument_spec=fields,
381                           supports_check_mode=False)
382
383    versions_check_result = None
384    if module._socket_path:
385        connection = Connection(module._socket_path)
386        if 'access_token' in module.params:
387            connection.set_option('access_token', module.params['access_token'])
388
389        if 'enable_log' in module.params:
390            connection.set_option('enable_log', module.params['enable_log'])
391        else:
392            connection.set_option('enable_log', False)
393        fos = FortiOSHandler(connection, module, mkeyname)
394        versions_check_result = check_schema_versioning(fos, versioned_schema, "system_ftm_push")
395
396        is_error, has_changed, result = fortios_system(module.params, fos)
397
398    else:
399        module.fail_json(**FAIL_SOCKET_MSG)
400
401    if versions_check_result and versions_check_result['matched'] is False:
402        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
403
404    if not is_error:
405        if versions_check_result and versions_check_result['matched'] is False:
406            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
407        else:
408            module.exit_json(changed=has_changed, meta=result)
409    else:
410        if versions_check_result and versions_check_result['matched'] is False:
411            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
412        else:
413            module.fail_json(msg="Error in repo", meta=result)
414
415
416if __name__ == '__main__':
417    main()
418