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_report_dataset 27short_description: Report dataset configuration 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 report feature and dataset 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 report_dataset: 88 description: 89 - Report dataset configuration. 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 field: 105 description: 106 - Fields. 107 type: list 108 suboptions: 109 displayname: 110 description: 111 - Display name. 112 type: str 113 id: 114 description: 115 - Field ID (1 to number of columns in SQL result). 116 required: true 117 type: int 118 name: 119 description: 120 - Name. 121 type: str 122 type: 123 description: 124 - Field type. 125 type: str 126 choices: 127 - text 128 - integer 129 - double 130 name: 131 description: 132 - Name. 133 required: true 134 type: str 135 parameters: 136 description: 137 - Parameters. 138 type: list 139 suboptions: 140 data_type: 141 description: 142 - Data type. 143 type: str 144 choices: 145 - text 146 - integer 147 - double 148 - long-integer 149 - date-time 150 display_name: 151 description: 152 - Display name. 153 type: str 154 field: 155 description: 156 - SQL field name. 157 type: str 158 id: 159 description: 160 - Parameter ID (1 to number of columns in SQL result). 161 required: true 162 type: int 163 policy: 164 description: 165 - Used by monitor policy. 166 type: int 167 query: 168 description: 169 - SQL query statement. 170 type: str 171''' 172 173EXAMPLES = ''' 174- hosts: localhost 175 vars: 176 host: "192.168.122.40" 177 username: "admin" 178 password: "" 179 vdom: "root" 180 ssl_verify: "False" 181 tasks: 182 - name: Report dataset configuration. 183 fortios_report_dataset: 184 host: "{{ host }}" 185 username: "{{ username }}" 186 password: "{{ password }}" 187 vdom: "{{ vdom }}" 188 https: "False" 189 state: "present" 190 report_dataset: 191 field: 192 - 193 displayname: "<your_own_value>" 194 id: "5" 195 name: "default_name_6" 196 type: "text" 197 name: "default_name_8" 198 parameters: 199 - 200 data_type: "text" 201 display_name: "<your_own_value>" 202 field: "<your_own_value>" 203 id: "13" 204 policy: "14" 205 query: "<your_own_value>" 206''' 207 208RETURN = ''' 209build: 210 description: Build number of the fortigate image 211 returned: always 212 type: str 213 sample: '1547' 214http_method: 215 description: Last method used to provision the content into FortiGate 216 returned: always 217 type: str 218 sample: 'PUT' 219http_status: 220 description: Last result given by FortiGate on last operation applied 221 returned: always 222 type: str 223 sample: "200" 224mkey: 225 description: Master key (id) used in the last call to FortiGate 226 returned: success 227 type: str 228 sample: "id" 229name: 230 description: Name of the table used to fulfill the request 231 returned: always 232 type: str 233 sample: "urlfilter" 234path: 235 description: Path of the table used to fulfill the request 236 returned: always 237 type: str 238 sample: "webfilter" 239revision: 240 description: Internal revision number 241 returned: always 242 type: str 243 sample: "17.0.2.10658" 244serial: 245 description: Serial number of the unit 246 returned: always 247 type: str 248 sample: "FGVMEVYYQT3AB5352" 249status: 250 description: Indication of the operation's result 251 returned: always 252 type: str 253 sample: "success" 254vdom: 255 description: Virtual domain used 256 returned: always 257 type: str 258 sample: "root" 259version: 260 description: Version of the FortiGate 261 returned: always 262 type: str 263 sample: "v5.6.3" 264 265''' 266 267from ansible.module_utils.basic import AnsibleModule 268from ansible.module_utils.connection import Connection 269from ansible.module_utils.network.fortios.fortios import FortiOSHandler 270from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG 271 272 273def login(data, fos): 274 host = data['host'] 275 username = data['username'] 276 password = data['password'] 277 ssl_verify = data['ssl_verify'] 278 279 fos.debug('on') 280 if 'https' in data and not data['https']: 281 fos.https('off') 282 else: 283 fos.https('on') 284 285 fos.login(host, username, password, verify=ssl_verify) 286 287 288def filter_report_dataset_data(json): 289 option_list = ['field', 'name', 'parameters', 290 'policy', 'query'] 291 dictionary = {} 292 293 for attribute in option_list: 294 if attribute in json and json[attribute] is not None: 295 dictionary[attribute] = json[attribute] 296 297 return dictionary 298 299 300def underscore_to_hyphen(data): 301 if isinstance(data, list): 302 for elem in data: 303 elem = underscore_to_hyphen(elem) 304 elif isinstance(data, dict): 305 new_data = {} 306 for k, v in data.items(): 307 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 308 data = new_data 309 310 return data 311 312 313def report_dataset(data, fos): 314 vdom = data['vdom'] 315 if 'state' in data and data['state']: 316 state = data['state'] 317 elif 'state' in data['report_dataset'] and data['report_dataset']: 318 state = data['report_dataset']['state'] 319 else: 320 state = True 321 report_dataset_data = data['report_dataset'] 322 filtered_data = underscore_to_hyphen(filter_report_dataset_data(report_dataset_data)) 323 324 if state == "present": 325 return fos.set('report', 326 'dataset', 327 data=filtered_data, 328 vdom=vdom) 329 330 elif state == "absent": 331 return fos.delete('report', 332 'dataset', 333 mkey=filtered_data['name'], 334 vdom=vdom) 335 336 337def is_successful_status(status): 338 return status['status'] == "success" or \ 339 status['http_method'] == "DELETE" and status['http_status'] == 404 340 341 342def fortios_report(data, fos): 343 344 if data['report_dataset']: 345 resp = report_dataset(data, fos) 346 347 return not is_successful_status(resp), \ 348 resp['status'] == "success", \ 349 resp 350 351 352def main(): 353 fields = { 354 "host": {"required": False, "type": "str"}, 355 "username": {"required": False, "type": "str"}, 356 "password": {"required": False, "type": "str", "default": "", "no_log": True}, 357 "vdom": {"required": False, "type": "str", "default": "root"}, 358 "https": {"required": False, "type": "bool", "default": True}, 359 "ssl_verify": {"required": False, "type": "bool", "default": True}, 360 "state": {"required": False, "type": "str", 361 "choices": ["present", "absent"]}, 362 "report_dataset": { 363 "required": False, "type": "dict", "default": None, 364 "options": { 365 "state": {"required": False, "type": "str", 366 "choices": ["present", "absent"]}, 367 "field": {"required": False, "type": "list", 368 "options": { 369 "displayname": {"required": False, "type": "str"}, 370 "id": {"required": True, "type": "int"}, 371 "name": {"required": False, "type": "str"}, 372 "type": {"required": False, "type": "str", 373 "choices": ["text", "integer", "double"]} 374 }}, 375 "name": {"required": True, "type": "str"}, 376 "parameters": {"required": False, "type": "list", 377 "options": { 378 "data_type": {"required": False, "type": "str", 379 "choices": ["text", "integer", "double", 380 "long-integer", "date-time"]}, 381 "display_name": {"required": False, "type": "str"}, 382 "field": {"required": False, "type": "str"}, 383 "id": {"required": True, "type": "int"} 384 }}, 385 "policy": {"required": False, "type": "int"}, 386 "query": {"required": False, "type": "str"} 387 388 } 389 } 390 } 391 392 module = AnsibleModule(argument_spec=fields, 393 supports_check_mode=False) 394 395 # legacy_mode refers to using fortiosapi instead of HTTPAPI 396 legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 397 'username' in module.params and module.params['username'] is not None and \ 398 'password' in module.params and module.params['password'] is not None 399 400 if not legacy_mode: 401 if module._socket_path: 402 connection = Connection(module._socket_path) 403 fos = FortiOSHandler(connection) 404 405 is_error, has_changed, result = fortios_report(module.params, fos) 406 else: 407 module.fail_json(**FAIL_SOCKET_MSG) 408 else: 409 try: 410 from fortiosapi import FortiOSAPI 411 except ImportError: 412 module.fail_json(msg="fortiosapi module is required") 413 414 fos = FortiOSAPI() 415 416 login(module.params, fos) 417 is_error, has_changed, result = fortios_report(module.params, fos) 418 fos.logout() 419 420 if not is_error: 421 module.exit_json(changed=has_changed, meta=result) 422 else: 423 module.fail_json(msg="Error in repo", meta=result) 424 425 426if __name__ == '__main__': 427 main() 428