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_virtual_wire_pair
27short_description: Configure virtual wire pairs 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 virtual_wire_pair 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    state:
76        description:
77            - Indicates whether to create or remove the object.
78        type: str
79        required: true
80        choices:
81            - present
82            - absent
83    system_virtual_wire_pair:
84        description:
85            - Configure virtual wire pairs.
86        default: null
87        type: dict
88        suboptions:
89            member:
90                description:
91                    - Interfaces belong to the virtual-wire-pair.
92                type: list
93                suboptions:
94                    interface_name:
95                        description:
96                            - Interface name. Source system.interface.name.
97                        type: str
98            name:
99                description:
100                    - Virtual-wire-pair name. Must be a unique interface name.
101                required: true
102                type: str
103            vlan_filter:
104                description:
105                    - Set VLAN filters.
106                type: str
107            wildcard_vlan:
108                description:
109                    - Enable/disable wildcard VLAN.
110                type: str
111                choices:
112                    - enable
113                    - disable
114'''
115
116EXAMPLES = '''
117- hosts: localhost
118  vars:
119   host: "192.168.122.40"
120   username: "admin"
121   password: ""
122   vdom: "root"
123   ssl_verify: "False"
124  tasks:
125  - name: Configure virtual wire pairs.
126    fortios_system_virtual_wire_pair:
127      host:  "{{ host }}"
128      username: "{{ username }}"
129      password: "{{ password }}"
130      vdom:  "{{ vdom }}"
131      https: "False"
132      state: "present"
133      system_virtual_wire_pair:
134        member:
135         -
136            interface_name: "<your_own_value> (source system.interface.name)"
137        name: "default_name_5"
138        vlan_filter: "<your_own_value>"
139        wildcard_vlan: "enable"
140'''
141
142RETURN = '''
143build:
144  description: Build number of the fortigate image
145  returned: always
146  type: str
147  sample: '1547'
148http_method:
149  description: Last method used to provision the content into FortiGate
150  returned: always
151  type: str
152  sample: 'PUT'
153http_status:
154  description: Last result given by FortiGate on last operation applied
155  returned: always
156  type: str
157  sample: "200"
158mkey:
159  description: Master key (id) used in the last call to FortiGate
160  returned: success
161  type: str
162  sample: "id"
163name:
164  description: Name of the table used to fulfill the request
165  returned: always
166  type: str
167  sample: "urlfilter"
168path:
169  description: Path of the table used to fulfill the request
170  returned: always
171  type: str
172  sample: "webfilter"
173revision:
174  description: Internal revision number
175  returned: always
176  type: str
177  sample: "17.0.2.10658"
178serial:
179  description: Serial number of the unit
180  returned: always
181  type: str
182  sample: "FGVMEVYYQT3AB5352"
183status:
184  description: Indication of the operation's result
185  returned: always
186  type: str
187  sample: "success"
188vdom:
189  description: Virtual domain used
190  returned: always
191  type: str
192  sample: "root"
193version:
194  description: Version of the FortiGate
195  returned: always
196  type: str
197  sample: "v5.6.3"
198
199'''
200
201from ansible.module_utils.basic import AnsibleModule
202from ansible.module_utils.connection import Connection
203from ansible.module_utils.network.fortios.fortios import FortiOSHandler
204from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
205
206
207def login(data, fos):
208    host = data['host']
209    username = data['username']
210    password = data['password']
211    ssl_verify = data['ssl_verify']
212
213    fos.debug('on')
214    if 'https' in data and not data['https']:
215        fos.https('off')
216    else:
217        fos.https('on')
218
219    fos.login(host, username, password, verify=ssl_verify)
220
221
222def filter_system_virtual_wire_pair_data(json):
223    option_list = ['member', 'name', 'vlan_filter',
224                   'wildcard_vlan']
225    dictionary = {}
226
227    for attribute in option_list:
228        if attribute in json and json[attribute] is not None:
229            dictionary[attribute] = json[attribute]
230
231    return dictionary
232
233
234def underscore_to_hyphen(data):
235    if isinstance(data, list):
236        for elem in data:
237            elem = underscore_to_hyphen(elem)
238    elif isinstance(data, dict):
239        new_data = {}
240        for k, v in data.items():
241            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
242        data = new_data
243
244    return data
245
246
247def system_virtual_wire_pair(data, fos):
248    vdom = data['vdom']
249    state = data['state']
250    system_virtual_wire_pair_data = data['system_virtual_wire_pair']
251    filtered_data = underscore_to_hyphen(filter_system_virtual_wire_pair_data(system_virtual_wire_pair_data))
252
253    if state == "present":
254        return fos.set('system',
255                       'virtual-wire-pair',
256                       data=filtered_data,
257                       vdom=vdom)
258
259    elif state == "absent":
260        return fos.delete('system',
261                          'virtual-wire-pair',
262                          mkey=filtered_data['name'],
263                          vdom=vdom)
264
265
266def is_successful_status(status):
267    return status['status'] == "success" or \
268        status['http_method'] == "DELETE" and status['http_status'] == 404
269
270
271def fortios_system(data, fos):
272
273    if data['system_virtual_wire_pair']:
274        resp = system_virtual_wire_pair(data, fos)
275
276    return not is_successful_status(resp), \
277        resp['status'] == "success", \
278        resp
279
280
281def main():
282    fields = {
283        "host": {"required": False, "type": "str"},
284        "username": {"required": False, "type": "str"},
285        "password": {"required": False, "type": "str", "default": "", "no_log": True},
286        "vdom": {"required": False, "type": "str", "default": "root"},
287        "https": {"required": False, "type": "bool", "default": True},
288        "ssl_verify": {"required": False, "type": "bool", "default": True},
289        "state": {"required": True, "type": "str",
290                  "choices": ["present", "absent"]},
291        "system_virtual_wire_pair": {
292            "required": False, "type": "dict", "default": None,
293            "options": {
294                "member": {"required": False, "type": "list",
295                           "options": {
296                               "interface_name": {"required": False, "type": "str"}
297                           }},
298                "name": {"required": True, "type": "str"},
299                "vlan_filter": {"required": False, "type": "str"},
300                "wildcard_vlan": {"required": False, "type": "str",
301                                  "choices": ["enable", "disable"]}
302
303            }
304        }
305    }
306
307    module = AnsibleModule(argument_spec=fields,
308                           supports_check_mode=False)
309
310    # legacy_mode refers to using fortiosapi instead of HTTPAPI
311    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
312                  'username' in module.params and module.params['username'] is not None and \
313                  'password' in module.params and module.params['password'] is not None
314
315    if not legacy_mode:
316        if module._socket_path:
317            connection = Connection(module._socket_path)
318            fos = FortiOSHandler(connection)
319
320            is_error, has_changed, result = fortios_system(module.params, fos)
321        else:
322            module.fail_json(**FAIL_SOCKET_MSG)
323    else:
324        try:
325            from fortiosapi import FortiOSAPI
326        except ImportError:
327            module.fail_json(msg="fortiosapi module is required")
328
329        fos = FortiOSAPI()
330
331        login(module.params, fos)
332        is_error, has_changed, result = fortios_system(module.params, fos)
333        fos.logout()
334
335    if not is_error:
336        module.exit_json(changed=has_changed, meta=result)
337    else:
338        module.fail_json(msg="Error in repo", meta=result)
339
340
341if __name__ == '__main__':
342    main()
343