1#!/usr/bin/python
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019 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_csf
27short_description: Add this FortiGate to a Security Fabric or set up a new Security Fabric on this FortiGate 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 csf category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.5
33version_added: "2.9"
34author:
35    - Miguel Angel Munoz (@mamunozgonzalez)
36    - Nicolas Thomas (@thomnico)
37notes:
38    - Requires fortiosapi library developed by Fortinet
39    - Run as a local_action in your playbook
40requirements:
41    - fortiosapi>=0.9.8
42options:
43    host:
44        description:
45            - FortiOS or FortiGate IP address.
46        type: str
47        required: false
48    username:
49        description:
50            - FortiOS or FortiGate username.
51        type: str
52        required: false
53    password:
54        description:
55            - FortiOS or FortiGate password.
56        type: str
57        default: ""
58    vdom:
59        description:
60            - Virtual domain, among those defined previously. A vdom is a
61              virtual instance of the FortiGate that can be configured and
62              used as a different unit.
63        type: str
64        default: root
65    https:
66        description:
67            - Indicates if the requests towards FortiGate must use HTTPS protocol.
68        type: bool
69        default: true
70    ssl_verify:
71        description:
72            - Ensures FortiGate certificate must be verified by a proper CA.
73        type: bool
74        default: true
75    system_csf:
76        description:
77            - Add this FortiGate to a Security Fabric or set up a new Security Fabric on this FortiGate.
78        default: null
79        type: dict
80        suboptions:
81            configuration_sync:
82                description:
83                    - Configuration sync mode.
84                type: str
85                choices:
86                    - default
87                    - local
88            fabric_device:
89                description:
90                    - Fabric device configuration.
91                type: list
92                suboptions:
93                    device_ip:
94                        description:
95                            - Device IP.
96                        type: str
97                    device_type:
98                        description:
99                            - Device type.
100                        type: str
101                        choices:
102                            - fortimail
103                    login:
104                        description:
105                            - Device login name.
106                        type: str
107                    name:
108                        description:
109                            - Device name.
110                        required: true
111                        type: str
112                    password:
113                        description:
114                            - Device login password.
115                        type: str
116            fixed_key:
117                description:
118                    - Auto-generated fixed key used when this device is the root. (Will automatically be generated if not set.)
119                type: str
120            group_name:
121                description:
122                    - Security Fabric group name. All FortiGates in a Security Fabric must have the same group name.
123                type: str
124            group_password:
125                description:
126                    - Security Fabric group password. All FortiGates in a Security Fabric must have the same group password.
127                type: str
128            management_ip:
129                description:
130                    - Management IP address of this FortiGate. Used to log into this FortiGate from another FortiGate in the Security Fabric.
131                type: str
132            management_port:
133                description:
134                    - Overriding port for management connection (Overrides admin port).
135                type: int
136            status:
137                description:
138                    - Enable/disable Security Fabric.
139                type: str
140                choices:
141                    - enable
142                    - disable
143            trusted_list:
144                description:
145                    - Pre-authorized and blocked security fabric nodes.
146                type: list
147                suboptions:
148                    action:
149                        description:
150                            - Security fabric authorization action.
151                        type: str
152                        choices:
153                            - accept
154                            - deny
155                    downstream_authorization:
156                        description:
157                            - Trust authorizations by this node's administrator.
158                        type: str
159                        choices:
160                            - enable
161                            - disable
162                    ha_members:
163                        description:
164                            - HA members.
165                        type: str
166                    serial:
167                        description:
168                            - Serial.
169                        required: true
170                        type: str
171            upstream_ip:
172                description:
173                    - IP address of the FortiGate upstream from this FortiGate in the Security Fabric.
174                type: str
175            upstream_port:
176                description:
177                    - The port number to use to communicate with the FortiGate upstream from this FortiGate in the Security Fabric .
178                type: int
179'''
180
181EXAMPLES = '''
182- hosts: localhost
183  vars:
184   host: "192.168.122.40"
185   username: "admin"
186   password: ""
187   vdom: "root"
188   ssl_verify: "False"
189  tasks:
190  - name: Add this FortiGate to a Security Fabric or set up a new Security Fabric on this FortiGate.
191    fortios_system_csf:
192      host:  "{{ host }}"
193      username: "{{ username }}"
194      password: "{{ password }}"
195      vdom:  "{{ vdom }}"
196      https: "False"
197      system_csf:
198        configuration_sync: "default"
199        fabric_device:
200         -
201            device_ip: "<your_own_value>"
202            device_type: "fortimail"
203            login: "<your_own_value>"
204            name: "default_name_8"
205            password: "<your_own_value>"
206        fixed_key: "<your_own_value>"
207        group_name: "<your_own_value>"
208        group_password: "<your_own_value>"
209        management_ip: "<your_own_value>"
210        management_port: "14"
211        status: "enable"
212        trusted_list:
213         -
214            action: "accept"
215            downstream_authorization: "enable"
216            ha_members: "<your_own_value>"
217            serial: "<your_own_value>"
218        upstream_ip: "<your_own_value>"
219        upstream_port: "22"
220'''
221
222RETURN = '''
223build:
224  description: Build number of the fortigate image
225  returned: always
226  type: str
227  sample: '1547'
228http_method:
229  description: Last method used to provision the content into FortiGate
230  returned: always
231  type: str
232  sample: 'PUT'
233http_status:
234  description: Last result given by FortiGate on last operation applied
235  returned: always
236  type: str
237  sample: "200"
238mkey:
239  description: Master key (id) used in the last call to FortiGate
240  returned: success
241  type: str
242  sample: "id"
243name:
244  description: Name of the table used to fulfill the request
245  returned: always
246  type: str
247  sample: "urlfilter"
248path:
249  description: Path of the table used to fulfill the request
250  returned: always
251  type: str
252  sample: "webfilter"
253revision:
254  description: Internal revision number
255  returned: always
256  type: str
257  sample: "17.0.2.10658"
258serial:
259  description: Serial number of the unit
260  returned: always
261  type: str
262  sample: "FGVMEVYYQT3AB5352"
263status:
264  description: Indication of the operation's result
265  returned: always
266  type: str
267  sample: "success"
268vdom:
269  description: Virtual domain used
270  returned: always
271  type: str
272  sample: "root"
273version:
274  description: Version of the FortiGate
275  returned: always
276  type: str
277  sample: "v5.6.3"
278
279'''
280
281from ansible.module_utils.basic import AnsibleModule
282from ansible.module_utils.connection import Connection
283from ansible.module_utils.network.fortios.fortios import FortiOSHandler
284from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
285
286
287def login(data, fos):
288    host = data['host']
289    username = data['username']
290    password = data['password']
291    ssl_verify = data['ssl_verify']
292
293    fos.debug('on')
294    if 'https' in data and not data['https']:
295        fos.https('off')
296    else:
297        fos.https('on')
298
299    fos.login(host, username, password, verify=ssl_verify)
300
301
302def filter_system_csf_data(json):
303    option_list = ['configuration_sync', 'fabric_device', 'fixed_key',
304                   'group_name', 'group_password', 'management_ip',
305                   'management_port', 'status', 'trusted_list',
306                   'upstream_ip', 'upstream_port']
307    dictionary = {}
308
309    for attribute in option_list:
310        if attribute in json and json[attribute] is not None:
311            dictionary[attribute] = json[attribute]
312
313    return dictionary
314
315
316def underscore_to_hyphen(data):
317    if isinstance(data, list):
318        for elem in data:
319            elem = underscore_to_hyphen(elem)
320    elif isinstance(data, dict):
321        new_data = {}
322        for k, v in data.items():
323            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
324        data = new_data
325
326    return data
327
328
329def system_csf(data, fos):
330    vdom = data['vdom']
331    system_csf_data = data['system_csf']
332    filtered_data = underscore_to_hyphen(filter_system_csf_data(system_csf_data))
333
334    return fos.set('system',
335                   'csf',
336                   data=filtered_data,
337                   vdom=vdom)
338
339
340def is_successful_status(status):
341    return status['status'] == "success" or \
342        status['http_method'] == "DELETE" and status['http_status'] == 404
343
344
345def fortios_system(data, fos):
346
347    if data['system_csf']:
348        resp = system_csf(data, fos)
349
350    return not is_successful_status(resp), \
351        resp['status'] == "success", \
352        resp
353
354
355def main():
356    fields = {
357        "host": {"required": False, "type": "str"},
358        "username": {"required": False, "type": "str"},
359        "password": {"required": False, "type": "str", "default": "", "no_log": True},
360        "vdom": {"required": False, "type": "str", "default": "root"},
361        "https": {"required": False, "type": "bool", "default": True},
362        "ssl_verify": {"required": False, "type": "bool", "default": True},
363        "system_csf": {
364            "required": False, "type": "dict", "default": None,
365            "options": {
366                "configuration_sync": {"required": False, "type": "str",
367                                       "choices": ["default", "local"]},
368                "fabric_device": {"required": False, "type": "list",
369                                  "options": {
370                                      "device_ip": {"required": False, "type": "str"},
371                                      "device_type": {"required": False, "type": "str",
372                                                      "choices": ["fortimail"]},
373                                      "login": {"required": False, "type": "str"},
374                                      "name": {"required": True, "type": "str"},
375                                      "password": {"required": False, "type": "str", "no_log": True}
376                                  }},
377                "fixed_key": {"required": False, "type": "str"},
378                "group_name": {"required": False, "type": "str"},
379                "group_password": {"required": False, "type": "str", "no_log": True},
380                "management_ip": {"required": False, "type": "str"},
381                "management_port": {"required": False, "type": "int"},
382                "status": {"required": False, "type": "str",
383                           "choices": ["enable", "disable"]},
384                "trusted_list": {"required": False, "type": "list",
385                                 "options": {
386                                     "action": {"required": False, "type": "str",
387                                                "choices": ["accept", "deny"]},
388                                     "downstream_authorization": {"required": False, "type": "str",
389                                                                  "choices": ["enable", "disable"]},
390                                     "ha_members": {"required": False, "type": "str"},
391                                     "serial": {"required": True, "type": "str"}
392                                 }},
393                "upstream_ip": {"required": False, "type": "str"},
394                "upstream_port": {"required": False, "type": "int"}
395
396            }
397        }
398    }
399
400    module = AnsibleModule(argument_spec=fields,
401                           supports_check_mode=False)
402
403    # legacy_mode refers to using fortiosapi instead of HTTPAPI
404    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
405                  'username' in module.params and module.params['username'] is not None and \
406                  'password' in module.params and module.params['password'] is not None
407
408    if not legacy_mode:
409        if module._socket_path:
410            connection = Connection(module._socket_path)
411            fos = FortiOSHandler(connection)
412
413            is_error, has_changed, result = fortios_system(module.params, fos)
414        else:
415            module.fail_json(**FAIL_SOCKET_MSG)
416    else:
417        try:
418            from fortiosapi import FortiOSAPI
419        except ImportError:
420            module.fail_json(msg="fortiosapi module is required")
421
422        fos = FortiOSAPI()
423
424        login(module.params, fos)
425        is_error, has_changed, result = fortios_system(module.params, fos)
426        fos.logout()
427
428    if not is_error:
429        module.exit_json(changed=has_changed, meta=result)
430    else:
431        module.fail_json(msg="Error in repo", meta=result)
432
433
434if __name__ == '__main__':
435    main()
436