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_firewall_multicast_address6 27short_description: Configure IPv6 multicast address 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 firewall feature and multicast_address6 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.8" 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 version_added: 2.9 76 state: 77 description: 78 - Indicates whether to create or remove the object. 79 This attribute was present already in previous version in a deeper level. 80 It has been moved out to this outer level. 81 type: str 82 required: false 83 choices: 84 - present 85 - absent 86 version_added: 2.9 87 firewall_multicast_address6: 88 description: 89 - Configure IPv6 multicast address. 90 default: null 91 type: dict 92 suboptions: 93 state: 94 description: 95 - B(Deprecated) 96 - Starting with Ansible 2.9 we recommend using the top-level 'state' parameter. 97 - HORIZONTALLINE 98 - Indicates whether to create or remove the object. 99 type: str 100 required: false 101 choices: 102 - present 103 - absent 104 color: 105 description: 106 - Color of icon on the GUI. 107 type: int 108 comment: 109 description: 110 - Comment. 111 type: str 112 ip6: 113 description: 114 - "IPv6 address prefix (format: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xxx)." 115 type: str 116 name: 117 description: 118 - IPv6 multicast address name. 119 required: true 120 type: str 121 tagging: 122 description: 123 - Config object tagging. 124 type: list 125 suboptions: 126 category: 127 description: 128 - Tag category. Source system.object-tagging.category. 129 type: str 130 name: 131 description: 132 - Tagging entry name. 133 required: true 134 type: str 135 tags: 136 description: 137 - Tags. 138 type: list 139 suboptions: 140 name: 141 description: 142 - Tag name. Source system.object-tagging.tags.name. 143 required: true 144 type: str 145 visibility: 146 description: 147 - Enable/disable visibility of the IPv6 multicast address on the GUI. 148 type: str 149 choices: 150 - enable 151 - disable 152''' 153 154EXAMPLES = ''' 155- hosts: localhost 156 vars: 157 host: "192.168.122.40" 158 username: "admin" 159 password: "" 160 vdom: "root" 161 ssl_verify: "False" 162 tasks: 163 - name: Configure IPv6 multicast address. 164 fortios_firewall_multicast_address6: 165 host: "{{ host }}" 166 username: "{{ username }}" 167 password: "{{ password }}" 168 vdom: "{{ vdom }}" 169 https: "False" 170 state: "present" 171 firewall_multicast_address6: 172 color: "3" 173 comment: "Comment." 174 ip6: "<your_own_value>" 175 name: "default_name_6" 176 tagging: 177 - 178 category: "<your_own_value> (source system.object-tagging.category)" 179 name: "default_name_9" 180 tags: 181 - 182 name: "default_name_11 (source system.object-tagging.tags.name)" 183 visibility: "enable" 184''' 185 186RETURN = ''' 187build: 188 description: Build number of the fortigate image 189 returned: always 190 type: str 191 sample: '1547' 192http_method: 193 description: Last method used to provision the content into FortiGate 194 returned: always 195 type: str 196 sample: 'PUT' 197http_status: 198 description: Last result given by FortiGate on last operation applied 199 returned: always 200 type: str 201 sample: "200" 202mkey: 203 description: Master key (id) used in the last call to FortiGate 204 returned: success 205 type: str 206 sample: "id" 207name: 208 description: Name of the table used to fulfill the request 209 returned: always 210 type: str 211 sample: "urlfilter" 212path: 213 description: Path of the table used to fulfill the request 214 returned: always 215 type: str 216 sample: "webfilter" 217revision: 218 description: Internal revision number 219 returned: always 220 type: str 221 sample: "17.0.2.10658" 222serial: 223 description: Serial number of the unit 224 returned: always 225 type: str 226 sample: "FGVMEVYYQT3AB5352" 227status: 228 description: Indication of the operation's result 229 returned: always 230 type: str 231 sample: "success" 232vdom: 233 description: Virtual domain used 234 returned: always 235 type: str 236 sample: "root" 237version: 238 description: Version of the FortiGate 239 returned: always 240 type: str 241 sample: "v5.6.3" 242 243''' 244 245from ansible.module_utils.basic import AnsibleModule 246from ansible.module_utils.connection import Connection 247from ansible.module_utils.network.fortios.fortios import FortiOSHandler 248from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG 249 250 251def login(data, fos): 252 host = data['host'] 253 username = data['username'] 254 password = data['password'] 255 ssl_verify = data['ssl_verify'] 256 257 fos.debug('on') 258 if 'https' in data and not data['https']: 259 fos.https('off') 260 else: 261 fos.https('on') 262 263 fos.login(host, username, password, verify=ssl_verify) 264 265 266def filter_firewall_multicast_address6_data(json): 267 option_list = ['color', 'comment', 'ip6', 268 'name', 'tagging', 'visibility'] 269 dictionary = {} 270 271 for attribute in option_list: 272 if attribute in json and json[attribute] is not None: 273 dictionary[attribute] = json[attribute] 274 275 return dictionary 276 277 278def underscore_to_hyphen(data): 279 if isinstance(data, list): 280 for elem in data: 281 elem = underscore_to_hyphen(elem) 282 elif isinstance(data, dict): 283 new_data = {} 284 for k, v in data.items(): 285 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 286 data = new_data 287 288 return data 289 290 291def firewall_multicast_address6(data, fos): 292 vdom = data['vdom'] 293 if 'state' in data and data['state']: 294 state = data['state'] 295 elif 'state' in data['firewall_multicast_address6'] and data['firewall_multicast_address6']: 296 state = data['firewall_multicast_address6']['state'] 297 else: 298 state = True 299 firewall_multicast_address6_data = data['firewall_multicast_address6'] 300 filtered_data = underscore_to_hyphen(filter_firewall_multicast_address6_data(firewall_multicast_address6_data)) 301 302 if state == "present": 303 return fos.set('firewall', 304 'multicast-address6', 305 data=filtered_data, 306 vdom=vdom) 307 308 elif state == "absent": 309 return fos.delete('firewall', 310 'multicast-address6', 311 mkey=filtered_data['name'], 312 vdom=vdom) 313 314 315def is_successful_status(status): 316 return status['status'] == "success" or \ 317 status['http_method'] == "DELETE" and status['http_status'] == 404 318 319 320def fortios_firewall(data, fos): 321 322 if data['firewall_multicast_address6']: 323 resp = firewall_multicast_address6(data, fos) 324 325 return not is_successful_status(resp), \ 326 resp['status'] == "success", \ 327 resp 328 329 330def main(): 331 fields = { 332 "host": {"required": False, "type": "str"}, 333 "username": {"required": False, "type": "str"}, 334 "password": {"required": False, "type": "str", "default": "", "no_log": True}, 335 "vdom": {"required": False, "type": "str", "default": "root"}, 336 "https": {"required": False, "type": "bool", "default": True}, 337 "ssl_verify": {"required": False, "type": "bool", "default": True}, 338 "state": {"required": False, "type": "str", 339 "choices": ["present", "absent"]}, 340 "firewall_multicast_address6": { 341 "required": False, "type": "dict", "default": None, 342 "options": { 343 "state": {"required": False, "type": "str", 344 "choices": ["present", "absent"]}, 345 "color": {"required": False, "type": "int"}, 346 "comment": {"required": False, "type": "str"}, 347 "ip6": {"required": False, "type": "str"}, 348 "name": {"required": True, "type": "str"}, 349 "tagging": {"required": False, "type": "list", 350 "options": { 351 "category": {"required": False, "type": "str"}, 352 "name": {"required": True, "type": "str"}, 353 "tags": {"required": False, "type": "list", 354 "options": { 355 "name": {"required": True, "type": "str"} 356 }} 357 }}, 358 "visibility": {"required": False, "type": "str", 359 "choices": ["enable", "disable"]} 360 361 } 362 } 363 } 364 365 module = AnsibleModule(argument_spec=fields, 366 supports_check_mode=False) 367 368 # legacy_mode refers to using fortiosapi instead of HTTPAPI 369 legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 370 'username' in module.params and module.params['username'] is not None and \ 371 'password' in module.params and module.params['password'] is not None 372 373 if not legacy_mode: 374 if module._socket_path: 375 connection = Connection(module._socket_path) 376 fos = FortiOSHandler(connection) 377 378 is_error, has_changed, result = fortios_firewall(module.params, fos) 379 else: 380 module.fail_json(**FAIL_SOCKET_MSG) 381 else: 382 try: 383 from fortiosapi import FortiOSAPI 384 except ImportError: 385 module.fail_json(msg="fortiosapi module is required") 386 387 fos = FortiOSAPI() 388 389 login(module.params, fos) 390 is_error, has_changed, result = fortios_firewall(module.params, fos) 391 fos.logout() 392 393 if not is_error: 394 module.exit_json(changed=has_changed, meta=result) 395 else: 396 module.fail_json(msg="Error in repo", meta=result) 397 398 399if __name__ == '__main__': 400 main() 401