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