From 3cd70f53cc13e99c85366473f4d8da6b5f43b875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Angel=20Mu=C3=B1oz=20Gonz=C3=A1lez?= Date: Tue, 20 Aug 2019 12:41:11 +0200 Subject: [PATCH] FortiOS modules for 2.9 - 4 (#60806) * FortiOS modules for 2.9 - 4 * Update ignore.txt * Updates from maintainers to legacy modules * Update fortios_firewall_ssl_setting.py * Update fortios_firewall_ssl_server.py --- .../fortios/fortios_firewall_proxy_address.py | 213 +++++-- .../fortios/fortios_firewall_proxy_addrgrp.py | 156 +++-- .../fortios/fortios_firewall_proxy_policy.py | 430 ++++++++----- .../fortios_firewall_schedule_group.py | 147 +++-- .../fortios_firewall_schedule_onetime.py | 156 +++-- .../fortios_firewall_schedule_recurring.py | 148 +++-- .../fortios_firewall_service_category.py | 145 +++-- .../fortios_firewall_service_custom.py | 254 +++++--- .../fortios/fortios_firewall_service_group.py | 149 +++-- .../fortios_firewall_shaper_per_ip_shaper.py | 199 +++--- .../fortios_firewall_shaper_traffic_shaper.py | 181 ++++-- .../fortios_firewall_shaping_policy.py | 274 +++++--- .../fortios_firewall_shaping_profile.py | 193 ++++-- .../fortios/fortios_firewall_sniffer.py | 305 +++++---- .../fortios/fortios_firewall_ssh_host_key.py | 159 +++-- .../fortios/fortios_firewall_ssh_local_ca.py | 164 +++-- .../fortios/fortios_firewall_ssh_local_key.py | 164 +++-- .../fortios/fortios_firewall_ssh_setting.py | 180 ++++-- .../fortios/fortios_firewall_ssl_server.py | 241 ++++--- .../fortios/fortios_firewall_ssl_setting.py | 220 ++++--- test/sanity/ignore.txt | 34 - .../test_fortios_firewall_proxy_address.py | 349 ++++++++++ .../test_fortios_firewall_proxy_addrgrp.py | 249 ++++++++ .../test_fortios_firewall_proxy_policy.py | 599 ++++++++++++++++++ .../test_fortios_firewall_schedule_group.py | 209 ++++++ .../test_fortios_firewall_schedule_onetime.py | 239 +++++++ ...est_fortios_firewall_schedule_recurring.py | 239 +++++++ .../test_fortios_firewall_service_category.py | 209 ++++++ .../test_fortios_firewall_service_custom.py | 409 ++++++++++++ .../test_fortios_firewall_service_group.py | 229 +++++++ ...t_fortios_firewall_shaper_per_ip_shaper.py | 269 ++++++++ ..._fortios_firewall_shaper_traffic_shaper.py | 269 ++++++++ .../test_fortios_firewall_shaping_policy.py | 299 +++++++++ .../test_fortios_firewall_shaping_profile.py | 229 +++++++ .../fortios/test_fortios_firewall_sniffer.py | 439 +++++++++++++ .../test_fortios_firewall_ssh_host_key.py | 269 ++++++++ .../test_fortios_firewall_ssh_local_ca.py | 239 +++++++ .../test_fortios_firewall_ssh_local_key.py | 239 +++++++ .../test_fortios_firewall_ssh_setting.py | 215 +++++++ .../test_fortios_firewall_ssl_server.py | 329 ++++++++++ .../test_fortios_firewall_ssl_setting.py | 231 +++++++ 41 files changed, 8416 insertions(+), 1454 deletions(-) create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_proxy_address.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_proxy_addrgrp.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_proxy_policy.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_schedule_group.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_schedule_onetime.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_schedule_recurring.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_service_category.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_service_custom.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_service_group.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_shaper_per_ip_shaper.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_shaper_traffic_shaper.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_shaping_policy.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_shaping_profile.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_sniffer.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssh_host_key.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssh_local_ca.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssh_local_key.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssh_setting.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssl_server.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_ssl_setting.py diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py index 441bab74e7c..fe62a698a06 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_proxy_address short_description: Web proxy address configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and proxy_address category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and proxy_address category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,95 +41,123 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_proxy_address: description: - Web proxy address configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - case-sensitivity: + case_sensitivity: description: - Enable to make the pattern case sensitive. + type: str choices: - disable - enable category: description: - FortiGuard category ID. + type: list suboptions: id: description: - Fortiguard category id. required: true + type: int color: description: - Integer value to determine the color of the icon in the GUI (1 - 32, default = 0, which sets value to 1). + type: int comment: description: - Optional comments. + type: str header: description: - HTTP header name as a regular expression. - header-group: + type: str + header_group: description: - HTTP header group. + type: list suboptions: - case-sensitivity: + case_sensitivity: description: - Case sensitivity in pattern. + type: str choices: - disable - enable header: description: - HTTP header regular expression. - header-name: + type: str + header_name: description: - HTTP header. + type: str id: description: - ID. required: true - header-name: + type: int + header_name: description: - Name of HTTP header. + type: str host: description: - Address object for the host. Source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name. - host-regex: + type: str + host_regex: description: - Host name as a regular expression. + type: str method: description: - HTTP request methods to be used. + type: str choices: - get - post @@ -146,40 +171,50 @@ options: description: - Address name. required: true + type: str path: description: - URL path as a regular expression. + type: str query: description: - Match the query part of the URL as a regular expression. + type: str referrer: description: - Enable/disable use of referrer field in the HTTP header to match the address. + type: str choices: - enable - disable tagging: description: - Config object tagging. + type: list suboptions: category: description: - Tag category. Source system.object-tagging.category. + type: str name: description: - Tagging entry name. required: true + type: str tags: description: - Tags. + type: list suboptions: name: description: - Tag name. Source system.object-tagging.tags.name. required: true + type: str type: description: - Proxy address type. + type: str choices: - host-regex - url @@ -192,6 +227,7 @@ options: ua: description: - Names of browsers to be used as user agent. + type: str choices: - chrome - ms @@ -201,9 +237,11 @@ options: uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable visibility of the object in the GUI. + type: str choices: - enable - disable @@ -216,6 +254,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Web proxy address configuration. fortios_firewall_proxy_address: @@ -224,24 +263,24 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_proxy_address: - state: "present" - case-sensitivity: "disable" + case_sensitivity: "disable" category: - id: "5" color: "6" comment: "Optional comments." header: "" - header-group: + header_group: - - case-sensitivity: "disable" + case_sensitivity: "disable" header: "" - header-name: "" + header_name: "" id: "13" - header-name: "" + header_name: "" host: "myhostname (source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name)" - host-regex: "myhostname" + host_regex: "myhostname" method: "get" name: "default_name_18" path: "" @@ -320,14 +359,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -335,13 +376,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_proxy_address_data(json): - option_list = ['case-sensitivity', 'category', 'color', - 'comment', 'header', 'header-group', - 'header-name', 'host', 'host-regex', + option_list = ['case_sensitivity', 'category', 'color', + 'comment', 'header', 'header_group', + 'header_name', 'host', 'host_regex', 'method', 'name', 'path', 'query', 'referrer', 'tagging', 'type', 'ua', 'uuid', @@ -355,49 +396,67 @@ def filter_firewall_proxy_address_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_proxy_address(data, fos): vdom = data['vdom'] + state = data['state'] firewall_proxy_address_data = data['firewall_proxy_address'] - filtered_data = filter_firewall_proxy_address_data(firewall_proxy_address_data) - if firewall_proxy_address_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_proxy_address_data(firewall_proxy_address_data)) + + if state == "present": return fos.set('firewall', 'proxy-address', data=filtered_data, vdom=vdom) - elif firewall_proxy_address_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'proxy-address', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_proxy_address'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_proxy_address']: + resp = firewall_proxy_address(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_proxy_address": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "case-sensitivity": {"required": False, "type": "str", + "case_sensitivity": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "category": {"required": False, "type": "list", "options": { @@ -406,17 +465,17 @@ def main(): "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, "header": {"required": False, "type": "str"}, - "header-group": {"required": False, "type": "list", + "header_group": {"required": False, "type": "list", "options": { - "case-sensitivity": {"required": False, "type": "str", + "case_sensitivity": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "header": {"required": False, "type": "str"}, - "header-name": {"required": False, "type": "str"}, + "header_name": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"} }}, - "header-name": {"required": False, "type": "str"}, + "header_name": {"required": False, "type": "str"}, "host": {"required": False, "type": "str"}, - "host-regex": {"required": False, "type": "str"}, + "host_regex": {"required": False, "type": "str"}, "method": {"required": False, "type": "str", "choices": ["get", "post", "put", "head", "connect", "trace", @@ -452,15 +511,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_addrgrp.py b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_addrgrp.py index 1184ddbc430..1a6c541c58e 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_addrgrp.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_addrgrp.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_proxy_addrgrp short_description: Web proxy address group configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and proxy_addrgrp category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and proxy_addrgrp category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,89 +41,115 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_proxy_addrgrp: description: - Web proxy address group configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent color: description: - Integer value to determine the color of the icon in the GUI (1 - 32, default = 0, which sets value to 1). + type: int comment: description: - Optional comments. + type: str member: description: - Members of address group. + type: list suboptions: name: description: - Address name. Source firewall.proxy-address.name firewall.proxy-addrgrp.name. required: true + type: str name: description: - Address group name. required: true + type: str tagging: description: - Config object tagging. + type: list suboptions: category: description: - Tag category. Source system.object-tagging.category. + type: str name: description: - Tagging entry name. required: true + type: str tags: description: - Tags. + type: list suboptions: name: description: - Tag name. Source system.object-tagging.tags.name. required: true + type: str type: description: - Source or destination address group type. + type: str choices: - src - dst uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable visibility of the object in the GUI. + type: str choices: - enable - disable @@ -139,6 +162,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Web proxy address group configuration. fortios_firewall_proxy_addrgrp: @@ -147,8 +171,8 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_proxy_addrgrp: - state: "present" color: "3" comment: "Optional comments." member: @@ -227,14 +251,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -242,7 +268,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_proxy_addrgrp_data(json): @@ -258,48 +284,66 @@ def filter_firewall_proxy_addrgrp_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_proxy_addrgrp(data, fos): vdom = data['vdom'] + state = data['state'] firewall_proxy_addrgrp_data = data['firewall_proxy_addrgrp'] - filtered_data = filter_firewall_proxy_addrgrp_data(firewall_proxy_addrgrp_data) - if firewall_proxy_addrgrp_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_proxy_addrgrp_data(firewall_proxy_addrgrp_data)) + + if state == "present": return fos.set('firewall', 'proxy-addrgrp', data=filtered_data, vdom=vdom) - elif firewall_proxy_addrgrp_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'proxy-addrgrp', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_proxy_addrgrp'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_proxy_addrgrp']: + resp = firewall_proxy_addrgrp(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_proxy_addrgrp": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, "member": {"required": False, "type": "list", @@ -328,15 +372,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py index 2a820709c65..50190585673 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_proxy_policy short_description: Configure proxy policies in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and proxy_policy category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and proxy_policy category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,163 +41,204 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_proxy_policy: description: - Configure proxy policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent action: description: - Accept or deny traffic matching the policy parameters. + type: str choices: - accept - deny - redirect - application-list: + application_list: description: - Name of an existing Application list. Source application.list.name. - av-profile: + type: str + av_profile: description: - Name of an existing Antivirus profile. Source antivirus.profile.name. + type: str comments: description: - Optional comments. + type: str disclaimer: description: - "Web proxy disclaimer setting: by domain, policy, or user." + type: str choices: - disable - domain - policy - user - dlp-sensor: + dlp_sensor: description: - Name of an existing DLP sensor. Source dlp.sensor.name. + type: str dstaddr: description: - Destination address objects. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name firewall.vip.name firewall.vipgrp.name firewall.vip46.name firewall.vipgrp46.name system.external-resource.name. required: true - dstaddr-negate: + type: str + dstaddr_negate: description: - When enabled, destination addresses match against any address EXCEPT the specified destination addresses. + type: str choices: - enable - disable dstaddr6: description: - IPv6 destination address objects. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name firewall.vip6.name firewall.vipgrp6.name firewall.vip64.name firewall.vipgrp64.name system.external-resource.name. required: true + type: str dstintf: description: - Destination interface names. + type: list suboptions: name: description: - Interface name. Source system.interface.name system.zone.name. required: true - global-label: + type: str + global_label: description: - Global web-based manager visible label. + type: str groups: description: - Names of group objects. + type: list suboptions: name: description: - Group name. Source user.group.name. required: true - http-tunnel-auth: + type: str + http_tunnel_auth: description: - Enable/disable HTTP tunnel authentication. + type: str choices: - enable - disable - icap-profile: + icap_profile: description: - Name of an existing ICAP profile. Source icap.profile.name. - internet-service: + type: str + internet_service: description: - Enable/disable use of Internet Services for this policy. If enabled, destination address and service are not used. + type: str choices: - enable - disable - internet-service-custom: + internet_service_custom: description: - Custom Internet Service name. + type: list suboptions: name: description: - Custom name. Source firewall.internet-service-custom.name. required: true - internet-service-id: + type: str + internet_service_id: description: - Internet Service ID. + type: list suboptions: id: description: - Internet Service ID. Source firewall.internet-service.id. required: true - internet-service-negate: + type: int + internet_service_negate: description: - When enabled, Internet Services match against any internet service EXCEPT the selected Internet Service. + type: str choices: - enable - disable - ips-sensor: + ips_sensor: description: - Name of an existing IPS sensor. Source ips.sensor.name. + type: str label: description: - VDOM-specific GUI visible label. + type: str logtraffic: description: - Enable/disable logging traffic through the policy. + type: str choices: - all - utm - disable - logtraffic-start: + logtraffic_start: description: - Enable/disable policy log traffic start. + type: str choices: - enable - disable @@ -208,29 +246,36 @@ options: description: - Policy ID. required: true + type: int poolname: description: - Name of IP pool object. + type: list suboptions: name: description: - IP pool name. Source firewall.ippool.name. required: true - profile-group: + type: str + profile_group: description: - Name of profile group. Source firewall.profile-group.name. - profile-protocol-options: + type: str + profile_protocol_options: description: - Name of an existing Protocol options profile. Source firewall.profile-protocol-options.name. - profile-type: + type: str + profile_type: description: - Determine whether the firewall policy allows security profile groups or single profiles only. + type: str choices: - single - group proxy: description: - Type of explicit proxy. + type: str choices: - explicit-web - transparent-web @@ -238,15 +283,18 @@ options: - ssh - ssh-tunnel - wanopt - redirect-url: + redirect_url: description: - Redirect URL for further explicit web proxy processing. - replacemsg-override-group: + type: str + replacemsg_override_group: description: - Authentication replacement message override group. Source system.replacemsg-group.name. - scan-botnet-connections: + type: str + scan_botnet_connections: description: - Enable/disable scanning of connections to Botnet servers. + type: str choices: - disable - block @@ -254,116 +302,143 @@ options: schedule: description: - Name of schedule object. Source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group.name. + type: str service: description: - Name of service objects. + type: list suboptions: name: description: - Service name. Source firewall.service.custom.name firewall.service.group.name. required: true - service-negate: + type: str + service_negate: description: - When enabled, services match against any service EXCEPT the specified destination services. + type: str choices: - enable - disable - session-ttl: + session_ttl: description: - TTL in seconds for sessions accepted by this policy (0 means use the system default session TTL). - spamfilter-profile: + type: int + spamfilter_profile: description: - Name of an existing Spam filter profile. Source spamfilter.profile.name. + type: str srcaddr: description: - - Source address objects (must be set when using Web proxy). + - Source address objects. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name system .external-resource.name. required: true - srcaddr-negate: + type: str + srcaddr_negate: description: - When enabled, source addresses match against any address EXCEPT the specified source addresses. + type: str choices: - enable - disable srcaddr6: description: - IPv6 source address objects. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name system.external-resource.name. required: true + type: str srcintf: description: - Source interface names. + type: list suboptions: name: description: - Interface name. Source system.interface.name system.zone.name. required: true - ssh-filter-profile: + type: str + ssh_filter_profile: description: - Name of an existing SSH filter profile. Source ssh-filter.profile.name. - ssl-ssh-profile: + type: str + ssl_ssh_profile: description: - Name of an existing SSL SSH profile. Source firewall.ssl-ssh-profile.name. + type: str status: description: - Enable/disable the active status of the policy. + type: str choices: - enable - disable transparent: description: - Enable to use the IP address of the client to connect to the server. + type: str choices: - enable - disable users: description: - Names of user objects. + type: list suboptions: name: description: - Group name. Source user.local.name. required: true - utm-status: + type: str + utm_status: description: - Enable the use of UTM profiles/sensors/lists. + type: str choices: - enable - disable uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). - waf-profile: + type: str + waf_profile: description: - Name of an existing Web application firewall profile. Source waf.profile.name. + type: str webcache: description: - Enable/disable web caching. + type: str choices: - enable - disable - webcache-https: + webcache_https: description: - Enable/disable web caching for HTTPS (Requires deep-inspection enabled in ssl-ssh-profile). + type: str choices: - disable - enable - webfilter-profile: + webfilter_profile: description: - Name of an existing Web filter profile. Source webfilter.profile.name. - webproxy-forward-server: + type: str + webproxy_forward_server: description: - Name of web proxy forward server. Source web-proxy.forward-server.name web-proxy.forward-server-group.name. - webproxy-profile: + type: str + webproxy_profile: description: - Name of web proxy profile. Source web-proxy.profile.name. + type: str ''' EXAMPLES = ''' @@ -373,6 +448,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure proxy policies. fortios_firewall_proxy_policy: @@ -381,19 +457,19 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_proxy_policy: - state: "present" action: "accept" - application-list: " (source application.list.name)" - av-profile: " (source antivirus.profile.name)" + application_list: " (source application.list.name)" + av_profile: " (source antivirus.profile.name)" comments: "" disclaimer: "disable" - dlp-sensor: " (source dlp.sensor.name)" + dlp_sensor: " (source dlp.sensor.name)" dstaddr: - name: "default_name_10 (source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name firewall.vip .name firewall.vipgrp.name firewall.vip46.name firewall.vipgrp46.name system.external-resource.name)" - dstaddr-negate: "enable" + dstaddr_negate: "enable" dstaddr6: - name: "default_name_13 (source firewall.address6.name firewall.addrgrp6.name firewall.vip6.name firewall.vipgrp6.name firewall.vip64.name firewall @@ -401,68 +477,68 @@ EXAMPLES = ''' dstintf: - name: "default_name_15 (source system.interface.name system.zone.name)" - global-label: "" + global_label: "" groups: - name: "default_name_18 (source user.group.name)" - http-tunnel-auth: "enable" - icap-profile: " (source icap.profile.name)" - internet-service: "enable" - internet-service-custom: + http_tunnel_auth: "enable" + icap_profile: " (source icap.profile.name)" + internet_service: "enable" + internet_service_custom: - name: "default_name_23 (source firewall.internet-service-custom.name)" - internet-service-id: + internet_service_id: - id: "25 (source firewall.internet-service.id)" - internet-service-negate: "enable" - ips-sensor: " (source ips.sensor.name)" + internet_service_negate: "enable" + ips_sensor: " (source ips.sensor.name)" label: "" logtraffic: "all" - logtraffic-start: "enable" + logtraffic_start: "enable" policyid: "31" poolname: - name: "default_name_33 (source firewall.ippool.name)" - profile-group: " (source firewall.profile-group.name)" - profile-protocol-options: " (source firewall.profile-protocol-options.name)" - profile-type: "single" + profile_group: " (source firewall.profile-group.name)" + profile_protocol_options: " (source firewall.profile-protocol-options.name)" + profile_type: "single" proxy: "explicit-web" - redirect-url: "" - replacemsg-override-group: " (source system.replacemsg-group.name)" - scan-botnet-connections: "disable" + redirect_url: "" + replacemsg_override_group: " (source system.replacemsg-group.name)" + scan_botnet_connections: "disable" schedule: " (source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group.name)" service: - name: "default_name_43 (source firewall.service.custom.name firewall.service.group.name)" - service-negate: "enable" - session-ttl: "45" - spamfilter-profile: " (source spamfilter.profile.name)" + service_negate: "enable" + session_ttl: "45" + spamfilter_profile: " (source spamfilter.profile.name)" srcaddr: - name: "default_name_48 (source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name system .external-resource.name)" - srcaddr-negate: "enable" + srcaddr_negate: "enable" srcaddr6: - name: "default_name_51 (source firewall.address6.name firewall.addrgrp6.name system.external-resource.name)" srcintf: - name: "default_name_53 (source system.interface.name system.zone.name)" - ssh-filter-profile: " (source ssh-filter.profile.name)" - ssl-ssh-profile: " (source firewall.ssl-ssh-profile.name)" + ssh_filter_profile: " (source ssh-filter.profile.name)" + ssl_ssh_profile: " (source firewall.ssl-ssh-profile.name)" status: "enable" transparent: "enable" users: - name: "default_name_59 (source user.local.name)" - utm-status: "enable" + utm_status: "enable" uuid: "" - waf-profile: " (source waf.profile.name)" + waf_profile: " (source waf.profile.name)" webcache: "enable" - webcache-https: "disable" - webfilter-profile: " (source webfilter.profile.name)" - webproxy-forward-server: " (source web-proxy.forward-server.name web-proxy.forward-server-group.name)" - webproxy-profile: " (source web-proxy.profile.name)" + webcache_https: "disable" + webfilter_profile: " (source webfilter.profile.name)" + webproxy_forward_server: " (source web-proxy.forward-server.name web-proxy.forward-server-group.name)" + webproxy_profile: " (source web-proxy.profile.name)" ''' RETURN = ''' @@ -525,14 +601,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -540,28 +618,28 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_proxy_policy_data(json): - option_list = ['action', 'application-list', 'av-profile', - 'comments', 'disclaimer', 'dlp-sensor', - 'dstaddr', 'dstaddr-negate', 'dstaddr6', - 'dstintf', 'global-label', 'groups', - 'http-tunnel-auth', 'icap-profile', 'internet-service', - 'internet-service-custom', 'internet-service-id', 'internet-service-negate', - 'ips-sensor', 'label', 'logtraffic', - 'logtraffic-start', 'policyid', 'poolname', - 'profile-group', 'profile-protocol-options', 'profile-type', - 'proxy', 'redirect-url', 'replacemsg-override-group', - 'scan-botnet-connections', 'schedule', 'service', - 'service-negate', 'session-ttl', 'spamfilter-profile', - 'srcaddr', 'srcaddr-negate', 'srcaddr6', - 'srcintf', 'ssh-filter-profile', 'ssl-ssh-profile', + option_list = ['action', 'application_list', 'av_profile', + 'comments', 'disclaimer', 'dlp_sensor', + 'dstaddr', 'dstaddr_negate', 'dstaddr6', + 'dstintf', 'global_label', 'groups', + 'http_tunnel_auth', 'icap_profile', 'internet_service', + 'internet_service_custom', 'internet_service_id', 'internet_service_negate', + 'ips_sensor', 'label', 'logtraffic', + 'logtraffic_start', 'policyid', 'poolname', + 'profile_group', 'profile_protocol_options', 'profile_type', + 'proxy', 'redirect_url', 'replacemsg_override_group', + 'scan_botnet_connections', 'schedule', 'service', + 'service_negate', 'session_ttl', 'spamfilter_profile', + 'srcaddr', 'srcaddr_negate', 'srcaddr6', + 'srcintf', 'ssh_filter_profile', 'ssl_ssh_profile', 'status', 'transparent', 'users', - 'utm-status', 'uuid', 'waf-profile', - 'webcache', 'webcache-https', 'webfilter-profile', - 'webproxy-forward-server', 'webproxy-profile'] + 'utm_status', 'uuid', 'waf_profile', + 'webcache', 'webcache_https', 'webfilter_profile', + 'webproxy_forward_server', 'webproxy_profile'] dictionary = {} for attribute in option_list: @@ -571,62 +649,80 @@ def filter_firewall_proxy_policy_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_proxy_policy(data, fos): vdom = data['vdom'] + state = data['state'] firewall_proxy_policy_data = data['firewall_proxy_policy'] - filtered_data = filter_firewall_proxy_policy_data(firewall_proxy_policy_data) - if firewall_proxy_policy_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_proxy_policy_data(firewall_proxy_policy_data)) + + if state == "present": return fos.set('firewall', 'proxy-policy', data=filtered_data, vdom=vdom) - elif firewall_proxy_policy_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'proxy-policy', mkey=filtered_data['policyid'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_proxy_policy'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_proxy_policy']: + resp = firewall_proxy_policy(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_proxy_policy": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "action": {"required": False, "type": "str", "choices": ["accept", "deny", "redirect"]}, - "application-list": {"required": False, "type": "str"}, - "av-profile": {"required": False, "type": "str"}, + "application_list": {"required": False, "type": "str"}, + "av_profile": {"required": False, "type": "str"}, "comments": {"required": False, "type": "str"}, "disclaimer": {"required": False, "type": "str", "choices": ["disable", "domain", "policy", "user"]}, - "dlp-sensor": {"required": False, "type": "str"}, + "dlp_sensor": {"required": False, "type": "str"}, "dstaddr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "dstaddr-negate": {"required": False, "type": "str", + "dstaddr_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "dstaddr6": {"required": False, "type": "list", "options": { @@ -636,62 +732,62 @@ def main(): "options": { "name": {"required": True, "type": "str"} }}, - "global-label": {"required": False, "type": "str"}, + "global_label": {"required": False, "type": "str"}, "groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "http-tunnel-auth": {"required": False, "type": "str", + "http_tunnel_auth": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "icap-profile": {"required": False, "type": "str"}, - "internet-service": {"required": False, "type": "str", + "icap_profile": {"required": False, "type": "str"}, + "internet_service": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "internet-service-custom": {"required": False, "type": "list", + "internet_service_custom": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-id": {"required": False, "type": "list", + "internet_service_id": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "internet-service-negate": {"required": False, "type": "str", + "internet_service_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ips-sensor": {"required": False, "type": "str"}, + "ips_sensor": {"required": False, "type": "str"}, "label": {"required": False, "type": "str"}, "logtraffic": {"required": False, "type": "str", "choices": ["all", "utm", "disable"]}, - "logtraffic-start": {"required": False, "type": "str", + "logtraffic_start": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "policyid": {"required": True, "type": "int"}, "poolname": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "profile-group": {"required": False, "type": "str"}, - "profile-protocol-options": {"required": False, "type": "str"}, - "profile-type": {"required": False, "type": "str", + "profile_group": {"required": False, "type": "str"}, + "profile_protocol_options": {"required": False, "type": "str"}, + "profile_type": {"required": False, "type": "str", "choices": ["single", "group"]}, "proxy": {"required": False, "type": "str", "choices": ["explicit-web", "transparent-web", "ftp", "ssh", "ssh-tunnel", "wanopt"]}, - "redirect-url": {"required": False, "type": "str"}, - "replacemsg-override-group": {"required": False, "type": "str"}, - "scan-botnet-connections": {"required": False, "type": "str", + "redirect_url": {"required": False, "type": "str"}, + "replacemsg_override_group": {"required": False, "type": "str"}, + "scan_botnet_connections": {"required": False, "type": "str", "choices": ["disable", "block", "monitor"]}, "schedule": {"required": False, "type": "str"}, "service": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "service-negate": {"required": False, "type": "str", + "service_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "session-ttl": {"required": False, "type": "int"}, - "spamfilter-profile": {"required": False, "type": "str"}, + "session_ttl": {"required": False, "type": "int"}, + "spamfilter_profile": {"required": False, "type": "str"}, "srcaddr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "srcaddr-negate": {"required": False, "type": "str", + "srcaddr_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "srcaddr6": {"required": False, "type": "list", "options": { @@ -701,8 +797,8 @@ def main(): "options": { "name": {"required": True, "type": "str"} }}, - "ssh-filter-profile": {"required": False, "type": "str"}, - "ssl-ssh-profile": {"required": False, "type": "str"}, + "ssh_filter_profile": {"required": False, "type": "str"}, + "ssl_ssh_profile": {"required": False, "type": "str"}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "transparent": {"required": False, "type": "str", @@ -711,17 +807,17 @@ def main(): "options": { "name": {"required": True, "type": "str"} }}, - "utm-status": {"required": False, "type": "str", + "utm_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "uuid": {"required": False, "type": "str"}, - "waf-profile": {"required": False, "type": "str"}, + "waf_profile": {"required": False, "type": "str"}, "webcache": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "webcache-https": {"required": False, "type": "str", + "webcache_https": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "webfilter-profile": {"required": False, "type": "str"}, - "webproxy-forward-server": {"required": False, "type": "str"}, - "webproxy-profile": {"required": False, "type": "str"} + "webfilter_profile": {"required": False, "type": "str"}, + "webproxy_forward_server": {"required": False, "type": "str"}, + "webproxy_profile": {"required": False, "type": "str"} } } @@ -729,15 +825,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_group.py b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_group.py index 13968f340a3..6793203816c 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_group.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_group.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_schedule_group short_description: Schedule group configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_schedule feature and group category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_schedule feature and group category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,55 +41,72 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_schedule_group: description: - Schedule group configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent color: description: - Color of icon on the GUI. + type: int member: description: - Schedules added to the schedule group. + type: list suboptions: name: description: - Schedule name. Source firewall.schedule.onetime.name firewall.schedule.recurring.name. required: true + type: str name: description: - Schedule group name. required: true + type: str ''' EXAMPLES = ''' @@ -102,6 +116,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Schedule group configuration. fortios_firewall_schedule_group: @@ -110,8 +125,8 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_schedule_group: - state: "present" color: "3" member: - @@ -179,14 +194,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -194,7 +211,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_schedule_group_data(json): @@ -208,48 +225,66 @@ def filter_firewall_schedule_group_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_schedule_group(data, fos): vdom = data['vdom'] + state = data['state'] firewall_schedule_group_data = data['firewall_schedule_group'] - filtered_data = filter_firewall_schedule_group_data(firewall_schedule_group_data) - if firewall_schedule_group_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_schedule_group_data(firewall_schedule_group_data)) + + if state == "present": return fos.set('firewall.schedule', 'group', data=filtered_data, vdom=vdom) - elif firewall_schedule_group_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.schedule', 'group', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_schedule(data, fos): - login(data) - methodlist = ['firewall_schedule_group'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_schedule_group']: + resp = firewall_schedule_group(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_schedule_group": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "color": {"required": False, "type": "int"}, "member": {"required": False, "type": "list", "options": { @@ -263,15 +298,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py index 545556b8146..1d0f0a18291 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_schedule_onetime short_description: Onetime schedule configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_schedule feature and onetime category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_schedule feature and onetime category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,56 +41,74 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_schedule_onetime: description: - Onetime schedule configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent color: description: - Color of icon on the GUI. + type: int end: description: - "Schedule end date and time, format hh:mm yyyy/mm/dd." - expiration-days: + type: str + expiration_days: description: - Write an event log message this many days before the schedule expires. + type: int name: description: - Onetime schedule name. required: true + type: str start: description: - "Schedule start date and time, format hh:mm yyyy/mm/dd." + type: str ''' EXAMPLES = ''' @@ -103,6 +118,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Onetime schedule configuration. fortios_firewall_schedule_onetime: @@ -111,11 +127,11 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_schedule_onetime: - state: "present" color: "3" end: "" - expiration-days: "5" + expiration_days: "5" name: "default_name_6" start: "" ''' @@ -180,14 +196,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -195,11 +213,11 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_schedule_onetime_data(json): - option_list = ['color', 'end', 'expiration-days', + option_list = ['color', 'end', 'expiration_days', 'name', 'start'] dictionary = {} @@ -210,51 +228,69 @@ def filter_firewall_schedule_onetime_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_schedule_onetime(data, fos): vdom = data['vdom'] + state = data['state'] firewall_schedule_onetime_data = data['firewall_schedule_onetime'] - filtered_data = filter_firewall_schedule_onetime_data(firewall_schedule_onetime_data) - if firewall_schedule_onetime_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_schedule_onetime_data(firewall_schedule_onetime_data)) + + if state == "present": return fos.set('firewall.schedule', 'onetime', data=filtered_data, vdom=vdom) - elif firewall_schedule_onetime_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.schedule', 'onetime', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_schedule(data, fos): - login(data) - methodlist = ['firewall_schedule_onetime'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_schedule_onetime']: + resp = firewall_schedule_onetime(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_schedule_onetime": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "color": {"required": False, "type": "int"}, "end": {"required": False, "type": "str"}, - "expiration-days": {"required": False, "type": "int"}, + "expiration_days": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"}, "start": {"required": False, "type": "str"} @@ -264,15 +300,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_recurring.py b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_recurring.py index 97d676aa181..bc350a1d357 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_schedule_recurring.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_schedule_recurring.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_schedule_recurring short_description: Recurring schedule configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_schedule feature and recurring category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_schedule feature and recurring category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,46 +41,61 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_schedule_recurring: description: - Recurring schedule configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent color: description: - Color of icon on the GUI. + type: int day: description: - One or more days of the week on which the schedule is valid. Separate the names of the days with a space. + type: str choices: - sunday - monday @@ -96,13 +108,16 @@ options: end: description: - "Time of day to end the schedule, format hh:mm." + type: str name: description: - Recurring schedule name. required: true + type: str start: description: - "Time of day to start the schedule, format hh:mm." + type: str ''' EXAMPLES = ''' @@ -112,6 +127,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Recurring schedule configuration. fortios_firewall_schedule_recurring: @@ -120,8 +136,8 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_schedule_recurring: - state: "present" color: "3" day: "sunday" end: "" @@ -189,14 +205,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -204,7 +222,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_schedule_recurring_data(json): @@ -219,48 +237,66 @@ def filter_firewall_schedule_recurring_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_schedule_recurring(data, fos): vdom = data['vdom'] + state = data['state'] firewall_schedule_recurring_data = data['firewall_schedule_recurring'] - filtered_data = filter_firewall_schedule_recurring_data(firewall_schedule_recurring_data) - if firewall_schedule_recurring_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_schedule_recurring_data(firewall_schedule_recurring_data)) + + if state == "present": return fos.set('firewall.schedule', 'recurring', data=filtered_data, vdom=vdom) - elif firewall_schedule_recurring_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.schedule', 'recurring', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_schedule(data, fos): - login(data) - methodlist = ['firewall_schedule_recurring'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_schedule_recurring']: + resp = firewall_schedule_recurring(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_schedule_recurring": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "color": {"required": False, "type": "int"}, "day": {"required": False, "type": "str", "choices": ["sunday", "monday", "tuesday", @@ -276,15 +312,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_schedule(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_service_category.py b/lib/ansible/modules/network/fortios/fortios_firewall_service_category.py index c41e5538aa2..2e4d237fc77 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_service_category.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_service_category.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_service_category short_description: Configure service categories in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_service feature and category category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_service feature and category category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,47 +41,62 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_service_category: description: - Configure service categories. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comment: description: - Comment. + type: str name: description: - Service category name. required: true + type: str ''' EXAMPLES = ''' @@ -94,6 +106,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure service categories. fortios_firewall_service_category: @@ -102,8 +115,8 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_service_category: - state: "present" comment: "Comment." name: "default_name_4" ''' @@ -168,14 +181,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -183,7 +198,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_service_category_data(json): @@ -197,48 +212,66 @@ def filter_firewall_service_category_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_service_category(data, fos): vdom = data['vdom'] + state = data['state'] firewall_service_category_data = data['firewall_service_category'] - filtered_data = filter_firewall_service_category_data(firewall_service_category_data) - if firewall_service_category_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_service_category_data(firewall_service_category_data)) + + if state == "present": return fos.set('firewall.service', 'category', data=filtered_data, vdom=vdom) - elif firewall_service_category_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.service', 'category', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_service(data, fos): - login(data) - methodlist = ['firewall_service_category'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_service_category']: + resp = firewall_service_category(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_service_category": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comment": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"} @@ -248,15 +281,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_service(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py b/lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py index 3b906dc7834..719b4dd2af1 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_service_custom short_description: Configure custom services in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_service feature and custom category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_service feature and custom category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,51 +41,67 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_service_custom: description: - Configure custom services. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - app-category: + app_category: description: - Application category ID. + type: list suboptions: id: description: - Application category id. required: true - app-service-type: + type: int + app_service_type: description: - Application service type. + type: str choices: - disable - app-id @@ -96,17 +109,21 @@ options: application: description: - Application ID. + type: list suboptions: id: description: - Application id. required: true + type: int category: description: - Service category. Source firewall.service.category.name. - check-reset-range: + type: str + check_reset_range: description: - Configure the type of ICMP error message verification. + type: str choices: - disable - strict @@ -114,15 +131,19 @@ options: color: description: - Color of icon on the GUI. + type: int comment: description: - Comment. + type: str fqdn: description: - Fully qualified domain name. + type: str helper: description: - Helper name. + type: str choices: - auto - disable @@ -147,19 +168,24 @@ options: icmpcode: description: - ICMP code. + type: int icmptype: description: - ICMP type. + type: int iprange: description: - Start and end of the IP range associated with service. + type: str name: description: - Custom service name. required: true + type: str protocol: description: - Protocol type based on IANA numbers. + type: str choices: - TCP/UDP/SCTP - ICMP @@ -171,42 +197,53 @@ options: - SOCKS-TCP - SOCKS-UDP - ALL - protocol-number: + protocol_number: description: - IP protocol number. + type: int proxy: description: - Enable/disable web proxy service. + type: str choices: - enable - disable - sctp-portrange: + sctp_portrange: description: - Multiple SCTP port ranges. - session-ttl: + type: str + session_ttl: description: - Session TTL (300 - 604800, 0 = default). - tcp-halfclose-timer: + type: int + tcp_halfclose_timer: description: - Wait time to close a TCP session waiting for an unanswered FIN packet (1 - 86400 sec, 0 = default). - tcp-halfopen-timer: + type: int + tcp_halfopen_timer: description: - Wait time to close a TCP session waiting for an unanswered open session packet (1 - 86400 sec, 0 = default). - tcp-portrange: + type: int + tcp_portrange: description: - Multiple TCP port ranges. - tcp-timewait-timer: + type: str + tcp_timewait_timer: description: - Set the length of the TCP TIME-WAIT state in seconds (1 - 300 sec, 0 = default). - udp-idle-timer: + type: int + udp_idle_timer: description: - UDP half close timeout (0 - 86400 sec, 0 = default). - udp-portrange: + type: int + udp_portrange: description: - Multiple UDP port ranges. + type: str visibility: description: - Enable/disable the visibility of the service on the GUI. + type: str choices: - enable - disable @@ -219,6 +256,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure custom services. fortios_firewall_service_custom: @@ -227,17 +265,17 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_service_custom: - state: "present" - app-category: + app_category: - id: "4" - app-service-type: "disable" + app_service_type: "disable" application: - id: "7" category: " (source firewall.service.category.name)" - check-reset-range: "disable" + check_reset_range: "disable" color: "10" comment: "Comment." fqdn: "" @@ -247,16 +285,16 @@ EXAMPLES = ''' iprange: "" name: "default_name_17" protocol: "TCP/UDP/SCTP" - protocol-number: "19" + protocol_number: "19" proxy: "enable" - sctp-portrange: "" - session-ttl: "22" - tcp-halfclose-timer: "23" - tcp-halfopen-timer: "24" - tcp-portrange: "" - tcp-timewait-timer: "26" - udp-idle-timer: "27" - udp-portrange: "" + sctp_portrange: "" + session_ttl: "22" + tcp_halfclose_timer: "23" + tcp_halfopen_timer: "24" + tcp_portrange: "" + tcp_timewait_timer: "26" + udp_idle_timer: "27" + udp_portrange: "" visibility: "enable" ''' @@ -320,14 +358,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -335,18 +375,18 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_service_custom_data(json): - option_list = ['app-category', 'app-service-type', 'application', - 'category', 'check-reset-range', 'color', + option_list = ['app_category', 'app_service_type', 'application', + 'category', 'check_reset_range', 'color', 'comment', 'fqdn', 'helper', 'icmpcode', 'icmptype', 'iprange', - 'name', 'protocol', 'protocol-number', - 'proxy', 'sctp-portrange', 'session-ttl', - 'tcp-halfclose-timer', 'tcp-halfopen-timer', 'tcp-portrange', - 'tcp-timewait-timer', 'udp-idle-timer', 'udp-portrange', + 'name', 'protocol', 'protocol_number', + 'proxy', 'sctp_portrange', 'session_ttl', + 'tcp_halfclose_timer', 'tcp_halfopen_timer', 'tcp_portrange', + 'tcp_timewait_timer', 'udp_idle_timer', 'udp_portrange', 'visibility'] dictionary = {} @@ -357,60 +397,78 @@ def filter_firewall_service_custom_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_service_custom(data, fos): vdom = data['vdom'] + state = data['state'] firewall_service_custom_data = data['firewall_service_custom'] - filtered_data = filter_firewall_service_custom_data(firewall_service_custom_data) - if firewall_service_custom_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_service_custom_data(firewall_service_custom_data)) + + if state == "present": return fos.set('firewall.service', 'custom', data=filtered_data, vdom=vdom) - elif firewall_service_custom_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.service', 'custom', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_service(data, fos): - login(data) - methodlist = ['firewall_service_custom'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_service_custom']: + resp = firewall_service_custom(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_service_custom": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "app-category": {"required": False, "type": "list", + "app_category": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "app-service-type": {"required": False, "type": "str", + "app_service_type": {"required": False, "type": "str", "choices": ["disable", "app-id", "app-category"]}, "application": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, "category": {"required": False, "type": "str"}, - "check-reset-range": {"required": False, "type": "str", + "check_reset_range": {"required": False, "type": "str", "choices": ["disable", "strict", "default"]}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, @@ -432,17 +490,17 @@ def main(): "IP", "HTTP", "FTP", "CONNECT", "SOCKS-TCP", "SOCKS-UDP", "ALL"]}, - "protocol-number": {"required": False, "type": "int"}, + "protocol_number": {"required": False, "type": "int"}, "proxy": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "sctp-portrange": {"required": False, "type": "str"}, - "session-ttl": {"required": False, "type": "int"}, - "tcp-halfclose-timer": {"required": False, "type": "int"}, - "tcp-halfopen-timer": {"required": False, "type": "int"}, - "tcp-portrange": {"required": False, "type": "str"}, - "tcp-timewait-timer": {"required": False, "type": "int"}, - "udp-idle-timer": {"required": False, "type": "int"}, - "udp-portrange": {"required": False, "type": "str"}, + "sctp_portrange": {"required": False, "type": "str"}, + "session_ttl": {"required": False, "type": "int"}, + "tcp_halfclose_timer": {"required": False, "type": "int"}, + "tcp_halfopen_timer": {"required": False, "type": "int"}, + "tcp_portrange": {"required": False, "type": "str"}, + "tcp_timewait_timer": {"required": False, "type": "int"}, + "udp_idle_timer": {"required": False, "type": "int"}, + "udp_portrange": {"required": False, "type": "str"}, "visibility": {"required": False, "type": "str", "choices": ["enable", "disable"]} @@ -452,15 +510,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_service(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_service_group.py b/lib/ansible/modules/network/fortios/fortios_firewall_service_group.py index 5ed8196e928..d724e640c4c 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_service_group.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_service_group.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_service_group short_description: Configure service groups in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_service feature and group category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_service feature and group category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,61 +41,80 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_service_group: description: - Configure service groups. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent color: description: - Color of icon on the GUI. + type: int comment: description: - Comment. + type: str member: description: - Service objects contained within the group. + type: list suboptions: name: description: - Address name. Source firewall.service.custom.name firewall.service.group.name. required: true + type: str name: description: - Address group name. required: true + type: str proxy: description: - Enable/disable web proxy service group. + type: str choices: - enable - disable @@ -111,6 +127,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure service groups. fortios_firewall_service_group: @@ -119,8 +136,8 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_service_group: - state: "present" color: "3" comment: "Comment." member: @@ -190,14 +207,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -205,7 +224,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_service_group_data(json): @@ -220,48 +239,66 @@ def filter_firewall_service_group_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_service_group(data, fos): vdom = data['vdom'] + state = data['state'] firewall_service_group_data = data['firewall_service_group'] - filtered_data = filter_firewall_service_group_data(firewall_service_group_data) - if firewall_service_group_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_service_group_data(firewall_service_group_data)) + + if state == "present": return fos.set('firewall.service', 'group', data=filtered_data, vdom=vdom) - elif firewall_service_group_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.service', 'group', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_service(data, fos): - login(data) - methodlist = ['firewall_service_group'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_service_group']: + resp = firewall_service_group(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_service_group": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, "member": {"required": False, "type": "list", @@ -278,15 +315,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_service(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_service(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py b/lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py index a65fbad8448..737e7759913 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_shaper_per_ip_shaper short_description: Configure per-IP traffic shaper in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_shaper feature and per_ip_shaper category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_shaper feature and per_ip_shaper category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,75 +41,96 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_shaper_per_ip_shaper: description: - Configure per-IP traffic shaper. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - bandwidth-unit: + bandwidth_unit: description: - Unit of measurement for maximum bandwidth for this shaper (Kbps, Mbps or Gbps). + type: str choices: - kbps - mbps - gbps - diffserv-forward: + diffserv_forward: description: - Enable/disable changing the Forward (original) DiffServ setting applied to traffic accepted by this shaper. + type: str choices: - enable - disable - diffserv-reverse: + diffserv_reverse: description: - Enable/disable changing the Reverse (reply) DiffServ setting applied to traffic accepted by this shaper. + type: str choices: - enable - disable - diffservcode-forward: + diffservcode_forward: description: - Forward (original) DiffServ setting to be applied to traffic accepted by this shaper. - diffservcode-rev: + type: str + diffservcode_rev: description: - Reverse (reply) DiffServ setting to be applied to traffic accepted by this shaper. - max-bandwidth: + type: str + max_bandwidth: description: - Upper bandwidth limit enforced by this shaper (0 - 16776000). 0 means no limit. Units depend on the bandwidth-unit setting. - max-concurrent-session: + type: int + max_concurrent_session: description: - Maximum number of concurrent sessions allowed by this shaper (0 - 2097000). 0 means no limit. + type: int name: description: - Traffic shaper name. required: true + type: str ''' EXAMPLES = ''' @@ -122,6 +140,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure per-IP traffic shaper. fortios_firewall_shaper_per_ip_shaper: @@ -130,15 +149,15 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_shaper_per_ip_shaper: - state: "present" - bandwidth-unit: "kbps" - diffserv-forward: "enable" - diffserv-reverse: "enable" - diffservcode-forward: "" - diffservcode-rev: "" - max-bandwidth: "8" - max-concurrent-session: "9" + bandwidth_unit: "kbps" + diffserv_forward: "enable" + diffserv_reverse: "enable" + diffservcode_forward: "" + diffservcode_rev: "" + max_bandwidth: "8" + max_concurrent_session: "9" name: "default_name_10" ''' @@ -202,14 +221,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -217,13 +238,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_shaper_per_ip_shaper_data(json): - option_list = ['bandwidth-unit', 'diffserv-forward', 'diffserv-reverse', - 'diffservcode-forward', 'diffservcode-rev', 'max-bandwidth', - 'max-concurrent-session', 'name'] + option_list = ['bandwidth_unit', 'diffserv_forward', 'diffserv_reverse', + 'diffservcode_forward', 'diffservcode_rev', 'max_bandwidth', + 'max_concurrent_session', 'name'] dictionary = {} for attribute in option_list: @@ -233,58 +254,76 @@ def filter_firewall_shaper_per_ip_shaper_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_shaper_per_ip_shaper(data, fos): vdom = data['vdom'] + state = data['state'] firewall_shaper_per_ip_shaper_data = data['firewall_shaper_per_ip_shaper'] - filtered_data = filter_firewall_shaper_per_ip_shaper_data(firewall_shaper_per_ip_shaper_data) - if firewall_shaper_per_ip_shaper_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_shaper_per_ip_shaper_data(firewall_shaper_per_ip_shaper_data)) + + if state == "present": return fos.set('firewall.shaper', 'per-ip-shaper', data=filtered_data, vdom=vdom) - elif firewall_shaper_per_ip_shaper_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.shaper', 'per-ip-shaper', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_shaper(data, fos): - login(data) - methodlist = ['firewall_shaper_per_ip_shaper'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_shaper_per_ip_shaper']: + resp = firewall_shaper_per_ip_shaper(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_shaper_per_ip_shaper": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "bandwidth-unit": {"required": False, "type": "str", + "bandwidth_unit": {"required": False, "type": "str", "choices": ["kbps", "mbps", "gbps"]}, - "diffserv-forward": {"required": False, "type": "str", + "diffserv_forward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "diffserv-reverse": {"required": False, "type": "str", + "diffserv_reverse": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "diffservcode-forward": {"required": False, "type": "str"}, - "diffservcode-rev": {"required": False, "type": "str"}, - "max-bandwidth": {"required": False, "type": "int"}, - "max-concurrent-session": {"required": False, "type": "int"}, + "diffservcode_forward": {"required": False, "type": "str"}, + "diffservcode_rev": {"required": False, "type": "str"}, + "max_bandwidth": {"required": False, "type": "int"}, + "max_concurrent_session": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"} } @@ -293,15 +332,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py b/lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py index 6e1e111382e..e9f23e9d2c2 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_shaper_traffic_shaper short_description: Configure shared traffic shaper in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_shaper feature and traffic_shaper category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_shaper feature and traffic_shaper category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,43 +41,57 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_shaper_traffic_shaper: description: - Configure shared traffic shaper. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - bandwidth-unit: + bandwidth_unit: description: - Unit of measurement for guaranteed and maximum bandwidth for this shaper (Kbps, Mbps or Gbps). + type: str choices: - kbps - mbps @@ -88,32 +99,39 @@ options: diffserv: description: - Enable/disable changing the DiffServ setting applied to traffic accepted by this shaper. + type: str choices: - enable - disable diffservcode: description: - DiffServ setting to be applied to traffic accepted by this shaper. - guaranteed-bandwidth: + type: str + guaranteed_bandwidth: description: - Amount of bandwidth guaranteed for this shaper (0 - 16776000). Units depend on the bandwidth-unit setting. - maximum-bandwidth: + type: int + maximum_bandwidth: description: - Upper bandwidth limit enforced by this shaper (0 - 16776000). 0 means no limit. Units depend on the bandwidth-unit setting. + type: int name: description: - Traffic shaper name. required: true - per-policy: + type: str + per_policy: description: - Enable/disable applying a separate shaper for each policy. For example, if enabled the guaranteed bandwidth is applied separately for each policy. + type: str choices: - disable - enable priority: description: - Higher priority traffic is more likely to be forwarded without delays and without compromising the guaranteed bandwidth. + type: str choices: - low - medium @@ -127,6 +145,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure shared traffic shaper. fortios_firewall_shaper_traffic_shaper: @@ -135,15 +154,15 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_shaper_traffic_shaper: - state: "present" - bandwidth-unit: "kbps" + bandwidth_unit: "kbps" diffserv: "enable" diffservcode: "" - guaranteed-bandwidth: "6" - maximum-bandwidth: "7" + guaranteed_bandwidth: "6" + maximum_bandwidth: "7" name: "default_name_8" - per-policy: "disable" + per_policy: "disable" priority: "low" ''' @@ -207,14 +226,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -222,13 +243,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_shaper_traffic_shaper_data(json): - option_list = ['bandwidth-unit', 'diffserv', 'diffservcode', - 'guaranteed-bandwidth', 'maximum-bandwidth', 'name', - 'per-policy', 'priority'] + option_list = ['bandwidth_unit', 'diffserv', 'diffservcode', + 'guaranteed_bandwidth', 'maximum_bandwidth', 'name', + 'per_policy', 'priority'] dictionary = {} for attribute in option_list: @@ -238,57 +259,75 @@ def filter_firewall_shaper_traffic_shaper_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_shaper_traffic_shaper(data, fos): vdom = data['vdom'] + state = data['state'] firewall_shaper_traffic_shaper_data = data['firewall_shaper_traffic_shaper'] - filtered_data = filter_firewall_shaper_traffic_shaper_data(firewall_shaper_traffic_shaper_data) - if firewall_shaper_traffic_shaper_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_shaper_traffic_shaper_data(firewall_shaper_traffic_shaper_data)) + + if state == "present": return fos.set('firewall.shaper', 'traffic-shaper', data=filtered_data, vdom=vdom) - elif firewall_shaper_traffic_shaper_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.shaper', 'traffic-shaper', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_shaper(data, fos): - login(data) - methodlist = ['firewall_shaper_traffic_shaper'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_shaper_traffic_shaper']: + resp = firewall_shaper_traffic_shaper(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_shaper_traffic_shaper": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "bandwidth-unit": {"required": False, "type": "str", + "bandwidth_unit": {"required": False, "type": "str", "choices": ["kbps", "mbps", "gbps"]}, "diffserv": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "diffservcode": {"required": False, "type": "str"}, - "guaranteed-bandwidth": {"required": False, "type": "int"}, - "maximum-bandwidth": {"required": False, "type": "int"}, + "guaranteed_bandwidth": {"required": False, "type": "int"}, + "maximum_bandwidth": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"}, - "per-policy": {"required": False, "type": "str", + "per_policy": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "priority": {"required": False, "type": "str", "choices": ["low", "medium", "high"]} @@ -299,15 +338,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_shaper(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py b/lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py index dd65e202aa7..54534e91e95 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_shaping_policy short_description: Configure shaping policies in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and shaping_policy category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and shaping_policy category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,206 +41,260 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_shaping_policy: description: - Configure shaping policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - app-category: + app_category: description: - IDs of one or more application categories that this shaper applies application control traffic shaping to. + type: list suboptions: id: description: - Category IDs. required: true + type: int application: description: - IDs of one or more applications that this shaper applies application control traffic shaping to. + type: list suboptions: id: description: - Application IDs. required: true - class-id: + type: int + class_id: description: - Traffic class ID. + type: int comment: description: - Comments. + type: str dstaddr: description: - IPv4 destination address and address group names. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str dstaddr6: description: - IPv6 destination address and address group names. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str dstintf: description: - One or more outgoing (egress) interfaces. + type: list suboptions: name: description: - Interface name. Source system.interface.name system.zone.name. required: true + type: str groups: description: - Apply this traffic shaping policy to user groups that have authenticated with the FortiGate. + type: list suboptions: name: description: - Group name. Source user.group.name. required: true + type: str id: description: - Shaping policy ID. required: true - internet-service: + type: int + internet_service: description: - Enable/disable use of Internet Services for this policy. If enabled, destination address and service are not used. + type: str choices: - enable - disable - internet-service-custom: + internet_service_custom: description: - Custom Internet Service name. + type: list suboptions: name: description: - Custom Internet Service name. Source firewall.internet-service-custom.name. required: true - internet-service-id: + type: str + internet_service_id: description: - Internet Service ID. + type: list suboptions: id: description: - Internet Service ID. Source firewall.internet-service.id. required: true - internet-service-src: + type: int + internet_service_src: description: - Enable/disable use of Internet Services in source for this policy. If enabled, source address is not used. + type: str choices: - enable - disable - internet-service-src-custom: + internet_service_src_custom: description: - Custom Internet Service source name. + type: list suboptions: name: description: - Custom Internet Service name. Source firewall.internet-service-custom.name. required: true - internet-service-src-id: + type: str + internet_service_src_id: description: - Internet Service source ID. + type: list suboptions: id: description: - Internet Service ID. Source firewall.internet-service.id. required: true - ip-version: + type: int + ip_version: description: - Apply this traffic shaping policy to IPv4 or IPv6 traffic. + type: str choices: - 4 - 6 - per-ip-shaper: + per_ip_shaper: description: - Per-IP traffic shaper to apply with this policy. Source firewall.shaper.per-ip-shaper.name. + type: str schedule: description: - Schedule name. Source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group.name. + type: str service: description: - Service and service group names. + type: list suboptions: name: description: - Service name. Source firewall.service.custom.name firewall.service.group.name. required: true + type: str srcaddr: description: - IPv4 source address and address group names. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str srcaddr6: description: - IPv6 source address and address group names. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str status: description: - Enable/disable this traffic shaping policy. + type: str choices: - enable - disable - traffic-shaper: + traffic_shaper: description: - Traffic shaper to apply to traffic forwarded by the firewall policy. Source firewall.shaper.traffic-shaper.name. - traffic-shaper-reverse: + type: str + traffic_shaper_reverse: description: - Traffic shaper to apply to response traffic received by the firewall policy. Source firewall.shaper.traffic-shaper.name. - url-category: + type: str + url_category: description: - IDs of one or more FortiGuard Web Filtering categories that this shaper applies traffic shaping to. + type: list suboptions: id: description: - URL category ID. required: true + type: int users: description: - Apply this traffic shaping policy to individual users that have authenticated with the FortiGate. + type: list suboptions: name: description: - User name. Source user.local.name. required: true + type: str ''' EXAMPLES = ''' @@ -253,6 +304,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure shaping policies. fortios_firewall_shaping_policy: @@ -261,15 +313,15 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_shaping_policy: - state: "present" - app-category: + app_category: - id: "4" application: - id: "6" - class-id: "7" + class_id: "7" comment: "Comments." dstaddr: - @@ -284,22 +336,22 @@ EXAMPLES = ''' - name: "default_name_16 (source user.group.name)" id: "17" - internet-service: "enable" - internet-service-custom: + internet_service: "enable" + internet_service_custom: - name: "default_name_20 (source firewall.internet-service-custom.name)" - internet-service-id: + internet_service_id: - id: "22 (source firewall.internet-service.id)" - internet-service-src: "enable" - internet-service-src-custom: + internet_service_src: "enable" + internet_service_src_custom: - name: "default_name_25 (source firewall.internet-service-custom.name)" - internet-service-src-id: + internet_service_src_id: - id: "27 (source firewall.internet-service.id)" - ip-version: "4" - per-ip-shaper: " (source firewall.shaper.per-ip-shaper.name)" + ip_version: "4" + per_ip_shaper: " (source firewall.shaper.per-ip-shaper.name)" schedule: " (source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group.name)" service: - @@ -311,9 +363,9 @@ EXAMPLES = ''' - name: "default_name_36 (source firewall.address6.name firewall.addrgrp6.name)" status: "enable" - traffic-shaper: " (source firewall.shaper.traffic-shaper.name)" - traffic-shaper-reverse: " (source firewall.shaper.traffic-shaper.name)" - url-category: + traffic_shaper: " (source firewall.shaper.traffic-shaper.name)" + traffic_shaper_reverse: " (source firewall.shaper.traffic-shaper.name)" + url_category: - id: "41" users: @@ -381,14 +433,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -396,19 +450,19 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_shaping_policy_data(json): - option_list = ['app-category', 'application', 'class-id', + option_list = ['app_category', 'application', 'class_id', 'comment', 'dstaddr', 'dstaddr6', 'dstintf', 'groups', 'id', - 'internet-service', 'internet-service-custom', 'internet-service-id', - 'internet-service-src', 'internet-service-src-custom', 'internet-service-src-id', - 'ip-version', 'per-ip-shaper', 'schedule', + 'internet_service', 'internet_service_custom', 'internet_service_id', + 'internet_service_src', 'internet_service_src_custom', 'internet_service_src_id', + 'ip_version', 'per_ip_shaper', 'schedule', 'service', 'srcaddr', 'srcaddr6', - 'status', 'traffic-shaper', 'traffic-shaper-reverse', - 'url-category', 'users'] + 'status', 'traffic_shaper', 'traffic_shaper_reverse', + 'url_category', 'users'] dictionary = {} for attribute in option_list: @@ -418,49 +472,67 @@ def filter_firewall_shaping_policy_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_shaping_policy(data, fos): vdom = data['vdom'] + state = data['state'] firewall_shaping_policy_data = data['firewall_shaping_policy'] - filtered_data = filter_firewall_shaping_policy_data(firewall_shaping_policy_data) - if firewall_shaping_policy_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_shaping_policy_data(firewall_shaping_policy_data)) + + if state == "present": return fos.set('firewall', 'shaping-policy', data=filtered_data, vdom=vdom) - elif firewall_shaping_policy_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'shaping-policy', mkey=filtered_data['id'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_shaping_policy'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_shaping_policy']: + resp = firewall_shaping_policy(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_shaping_policy": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "app-category": {"required": False, "type": "list", + "app_category": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, @@ -468,7 +540,7 @@ def main(): "options": { "id": {"required": True, "type": "int"} }}, - "class-id": {"required": False, "type": "int"}, + "class_id": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, "dstaddr": {"required": False, "type": "list", "options": { @@ -487,29 +559,29 @@ def main(): "name": {"required": True, "type": "str"} }}, "id": {"required": True, "type": "int"}, - "internet-service": {"required": False, "type": "str", + "internet_service": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "internet-service-custom": {"required": False, "type": "list", + "internet_service_custom": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-id": {"required": False, "type": "list", + "internet_service_id": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "internet-service-src": {"required": False, "type": "str", + "internet_service_src": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "internet-service-src-custom": {"required": False, "type": "list", + "internet_service_src_custom": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-src-id": {"required": False, "type": "list", + "internet_service_src_id": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "ip-version": {"required": False, "type": "str", + "ip_version": {"required": False, "type": "str", "choices": ["4", "6"]}, - "per-ip-shaper": {"required": False, "type": "str"}, + "per_ip_shaper": {"required": False, "type": "str"}, "schedule": {"required": False, "type": "str"}, "service": {"required": False, "type": "list", "options": { @@ -525,9 +597,9 @@ def main(): }}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "traffic-shaper": {"required": False, "type": "str"}, - "traffic-shaper-reverse": {"required": False, "type": "str"}, - "url-category": {"required": False, "type": "list", + "traffic_shaper": {"required": False, "type": "str"}, + "traffic_shaper_reverse": {"required": False, "type": "str"}, + "url_category": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, @@ -542,15 +614,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py b/lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py index 70a19e3802d..9ddc70e6353 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_shaping_profile short_description: Configure shaping profiles in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and shaping_profile category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and shaping_profile category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,70 +41,91 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_shaping_profile: description: - Configure shaping profiles. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comment: description: - Comment. - default-class-id: + type: str + default_class_id: description: - Default class ID to handle unclassified packets (including all local traffic). - profile-name: + type: int + profile_name: description: - Shaping profile name. - required: true - shaping-entries: + type: str + shaping_entries: description: - Define shaping entries of this shaping profile. + type: list suboptions: - class-id: + class_id: description: - Class ID. - guaranteed-bandwidth-percentage: + type: int + guaranteed_bandwidth_percentage: description: - Guaranteed bandwith in percentage. + type: int id: description: - ID number. required: true - maximum-bandwidth-percentage: + type: int + maximum_bandwidth_percentage: description: - Maximum bandwith in percentage. + type: int priority: description: - Priority. + type: str choices: - high - medium @@ -121,6 +139,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure shaping profiles. fortios_firewall_shaping_profile: @@ -129,17 +148,17 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_shaping_profile: - state: "present" comment: "Comment." - default-class-id: "4" - profile-name: "" - shaping-entries: + default_class_id: "4" + profile_name: "" + shaping_entries: - - class-id: "7" - guaranteed-bandwidth-percentage: "8" + class_id: "7" + guaranteed_bandwidth_percentage: "8" id: "9" - maximum-bandwidth-percentage: "10" + maximum_bandwidth_percentage: "10" priority: "high" ''' @@ -203,14 +222,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -218,12 +239,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_shaping_profile_data(json): - option_list = ['comment', 'default-class-id', 'profile-name', - 'shaping-entries'] + option_list = ['comment', 'default_class_id', 'profile_name', + 'shaping_entries'] dictionary = {} for attribute in option_list: @@ -233,57 +254,75 @@ def filter_firewall_shaping_profile_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_shaping_profile(data, fos): vdom = data['vdom'] + state = data['state'] firewall_shaping_profile_data = data['firewall_shaping_profile'] - filtered_data = filter_firewall_shaping_profile_data(firewall_shaping_profile_data) - if firewall_shaping_profile_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_shaping_profile_data(firewall_shaping_profile_data)) + + if state == "present": return fos.set('firewall', 'shaping-profile', data=filtered_data, vdom=vdom) - elif firewall_shaping_profile_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'shaping-profile', mkey=filtered_data['profile-name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_shaping_profile'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_shaping_profile']: + resp = firewall_shaping_profile(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_shaping_profile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comment": {"required": False, "type": "str"}, - "default-class-id": {"required": False, "type": "int"}, - "profile-name": {"required": True, "type": "str"}, - "shaping-entries": {"required": False, "type": "list", + "default_class_id": {"required": False, "type": "int"}, + "profile_name": {"required": False, "type": "str"}, + "shaping_entries": {"required": False, "type": "list", "options": { - "class-id": {"required": False, "type": "int"}, - "guaranteed-bandwidth-percentage": {"required": False, "type": "int"}, + "class_id": {"required": False, "type": "int"}, + "guaranteed_bandwidth_percentage": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, - "maximum-bandwidth-percentage": {"required": False, "type": "int"}, + "maximum_bandwidth_percentage": {"required": False, "type": "int"}, "priority": {"required": False, "type": "str", "choices": ["high", "medium", "low"]} }} @@ -294,15 +333,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py b/lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py index a4253bec448..50f785c9bc5 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_sniffer short_description: Configure sniffer in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and sniffer category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and sniffer category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,53 +41,69 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_sniffer: description: - Configure sniffer. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent anomaly: description: - Configuration method to edit Denial of Service (DoS) anomaly settings. + type: list suboptions: action: description: - Action taken when the threshold is reached. + type: str choices: - pass - block log: description: - Enable/disable anomaly logging. + type: str choices: - enable - disable @@ -98,151 +111,184 @@ options: description: - Anomaly name. required: true + type: str quarantine: description: - Quarantine method. + type: str choices: - none - attacker - quarantine-expiry: + quarantine_expiry: description: - Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m). Requires quarantine set to attacker. - quarantine-log: + type: str + quarantine_log: description: - Enable/disable quarantine logging. + type: str choices: - disable - enable status: description: - Enable/disable this anomaly. + type: str choices: - disable - enable threshold: description: - Anomaly threshold. Number of detected instances per minute that triggers the anomaly action. + type: int threshold(default): description: - Number of detected instances per minute which triggers action (1 - 2147483647, default = 1000). Note that each anomaly has a different threshold value assigned to it. - application-list: + type: int + application_list: description: - Name of an existing application list. Source application.list.name. - application-list-status: + type: str + application_list_status: description: - Enable/disable application control profile. + type: str choices: - enable - disable - av-profile: + av_profile: description: - Name of an existing antivirus profile. Source antivirus.profile.name. - av-profile-status: + type: str + av_profile_status: description: - Enable/disable antivirus profile. + type: str choices: - enable - disable - dlp-sensor: + dlp_sensor: description: - Name of an existing DLP sensor. Source dlp.sensor.name. - dlp-sensor-status: + type: str + dlp_sensor_status: description: - Enable/disable DLP sensor. + type: str choices: - enable - disable dsri: description: - Enable/disable DSRI. + type: str choices: - enable - disable host: description: - "Hosts to filter for in sniffer traffic (Format examples: 1.1.1.1, 2.2.2.0/24, 3.3.3.3/255.255.255.0, 4.4.4.0-4.4.4.240)." + type: str id: description: - Sniffer ID. required: true + type: int interface: description: - Interface name that traffic sniffing will take place on. Source system.interface.name. - ips-dos-status: + type: str + ips_dos_status: description: - Enable/disable IPS DoS anomaly detection. + type: str choices: - enable - disable - ips-sensor: + ips_sensor: description: - Name of an existing IPS sensor. Source ips.sensor.name. - ips-sensor-status: + type: str + ips_sensor_status: description: - Enable/disable IPS sensor. + type: str choices: - enable - disable ipv6: description: - Enable/disable sniffing IPv6 packets. + type: str choices: - enable - disable logtraffic: description: - Either log all sessions, only sessions that have a security profile applied, or disable all logging for this policy. + type: str choices: - all - utm - disable - max-packet-count: + max_packet_count: description: - Maximum packet count (1 - 1000000, default = 10000). - non-ip: + type: int + non_ip: description: - Enable/disable sniffing non-IP packets. + type: str choices: - enable - disable port: description: - "Ports to sniff (Format examples: 10, :20, 30:40, 50-, 100-200)." + type: str protocol: description: - Integer value for the protocol type as defined by IANA (0 - 255). - scan-botnet-connections: + type: str + scan_botnet_connections: description: - Enable/disable scanning of connections to Botnet servers. + type: str choices: - disable - block - monitor - spamfilter-profile: + spamfilter_profile: description: - Name of an existing spam filter profile. Source spamfilter.profile.name. - spamfilter-profile-status: + type: str + spamfilter_profile_status: description: - Enable/disable spam filter. + type: str choices: - enable - disable status: description: - Enable/disable the active status of the sniffer. + type: str choices: - enable - disable vlan: description: - List of VLANs to sniff. - webfilter-profile: + type: str + webfilter_profile: description: - Name of an existing web filter profile. Source webfilter.profile.name. - webfilter-profile-status: + type: str + webfilter_profile_status: description: - Enable/disable web filter profile. + type: str choices: - enable - disable @@ -255,6 +301,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure sniffer. fortios_firewall_sniffer: @@ -263,45 +310,45 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_sniffer: - state: "present" anomaly: - action: "pass" log: "enable" name: "default_name_6" quarantine: "none" - quarantine-expiry: "" - quarantine-log: "disable" + quarantine_expiry: "" + quarantine_log: "disable" status: "disable" threshold: "11" threshold(default): "12" - application-list: " (source application.list.name)" - application-list-status: "enable" - av-profile: " (source antivirus.profile.name)" - av-profile-status: "enable" - dlp-sensor: " (source dlp.sensor.name)" - dlp-sensor-status: "enable" + application_list: " (source application.list.name)" + application_list_status: "enable" + av_profile: " (source antivirus.profile.name)" + av_profile_status: "enable" + dlp_sensor: " (source dlp.sensor.name)" + dlp_sensor_status: "enable" dsri: "enable" host: "myhostname" id: "21" interface: " (source system.interface.name)" - ips-dos-status: "enable" - ips-sensor: " (source ips.sensor.name)" - ips-sensor-status: "enable" + ips_dos_status: "enable" + ips_sensor: " (source ips.sensor.name)" + ips_sensor_status: "enable" ipv6: "enable" logtraffic: "all" - max-packet-count: "28" - non-ip: "enable" + max_packet_count: "28" + non_ip: "enable" port: "" protocol: "" - scan-botnet-connections: "disable" - spamfilter-profile: " (source spamfilter.profile.name)" - spamfilter-profile-status: "enable" + scan_botnet_connections: "disable" + spamfilter_profile: " (source spamfilter.profile.name)" + spamfilter_profile_status: "enable" status: "enable" vlan: "" - webfilter-profile: " (source webfilter.profile.name)" - webfilter-profile-status: "enable" + webfilter_profile: " (source webfilter.profile.name)" + webfilter_profile_status: "enable" ''' RETURN = ''' @@ -364,14 +411,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -379,19 +428,19 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_sniffer_data(json): - option_list = ['anomaly', 'application-list', 'application-list-status', - 'av-profile', 'av-profile-status', 'dlp-sensor', - 'dlp-sensor-status', 'dsri', 'host', - 'id', 'interface', 'ips-dos-status', - 'ips-sensor', 'ips-sensor-status', 'ipv6', - 'logtraffic', 'max-packet-count', 'non-ip', - 'port', 'protocol', 'scan-botnet-connections', - 'spamfilter-profile', 'spamfilter-profile-status', 'status', - 'vlan', 'webfilter-profile', 'webfilter-profile-status'] + option_list = ['anomaly', 'application_list', 'application_list_status', + 'av_profile', 'av_profile_status', 'dlp_sensor', + 'dlp_sensor_status', 'dsri', 'host', + 'id', 'interface', 'ips_dos_status', + 'ips_sensor', 'ips_sensor_status', 'ipv6', + 'logtraffic', 'max_packet_count', 'non_ip', + 'port', 'protocol', 'scan_botnet_connections', + 'spamfilter_profile', 'spamfilter_profile_status', 'status', + 'vlan', 'webfilter_profile', 'webfilter_profile_status'] dictionary = {} for attribute in option_list: @@ -401,48 +450,66 @@ def filter_firewall_sniffer_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_sniffer(data, fos): vdom = data['vdom'] + state = data['state'] firewall_sniffer_data = data['firewall_sniffer'] - filtered_data = filter_firewall_sniffer_data(firewall_sniffer_data) - if firewall_sniffer_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_sniffer_data(firewall_sniffer_data)) + + if state == "present": return fos.set('firewall', 'sniffer', data=filtered_data, vdom=vdom) - elif firewall_sniffer_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'sniffer', mkey=filtered_data['id'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_sniffer'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_sniffer']: + resp = firewall_sniffer(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_sniffer": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "anomaly": {"required": False, "type": "list", "options": { "action": {"required": False, "type": "str", @@ -452,52 +519,52 @@ def main(): "name": {"required": True, "type": "str"}, "quarantine": {"required": False, "type": "str", "choices": ["none", "attacker"]}, - "quarantine-expiry": {"required": False, "type": "str"}, - "quarantine-log": {"required": False, "type": "str", + "quarantine_expiry": {"required": False, "type": "str"}, + "quarantine_log": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "status": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "threshold": {"required": False, "type": "int"}, "threshold(default)": {"required": False, "type": "int"} }}, - "application-list": {"required": False, "type": "str"}, - "application-list-status": {"required": False, "type": "str", + "application_list": {"required": False, "type": "str"}, + "application_list_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "av-profile": {"required": False, "type": "str"}, - "av-profile-status": {"required": False, "type": "str", + "av_profile": {"required": False, "type": "str"}, + "av_profile_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dlp-sensor": {"required": False, "type": "str"}, - "dlp-sensor-status": {"required": False, "type": "str", + "dlp_sensor": {"required": False, "type": "str"}, + "dlp_sensor_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "dsri": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "host": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"}, "interface": {"required": False, "type": "str"}, - "ips-dos-status": {"required": False, "type": "str", + "ips_dos_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ips-sensor": {"required": False, "type": "str"}, - "ips-sensor-status": {"required": False, "type": "str", + "ips_sensor": {"required": False, "type": "str"}, + "ips_sensor_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "ipv6": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "logtraffic": {"required": False, "type": "str", "choices": ["all", "utm", "disable"]}, - "max-packet-count": {"required": False, "type": "int"}, - "non-ip": {"required": False, "type": "str", + "max_packet_count": {"required": False, "type": "int"}, + "non_ip": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "port": {"required": False, "type": "str"}, "protocol": {"required": False, "type": "str"}, - "scan-botnet-connections": {"required": False, "type": "str", + "scan_botnet_connections": {"required": False, "type": "str", "choices": ["disable", "block", "monitor"]}, - "spamfilter-profile": {"required": False, "type": "str"}, - "spamfilter-profile-status": {"required": False, "type": "str", + "spamfilter_profile": {"required": False, "type": "str"}, + "spamfilter_profile_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "vlan": {"required": False, "type": "str"}, - "webfilter-profile": {"required": False, "type": "str"}, - "webfilter-profile-status": {"required": False, "type": "str", + "webfilter_profile": {"required": False, "type": "str"}, + "webfilter_profile_status": {"required": False, "type": "str", "choices": ["enable", "disable"]} } @@ -506,15 +573,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py index 71767fe257d..390897dc7b1 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssh_host_key short_description: SSH proxy host public keys in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_ssh feature and host_key category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_ssh feature and host_key category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,53 +41,70 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_ssh_host_key: description: - SSH proxy host public keys. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent hostname: description: - Hostname of the SSH server. + type: str ip: description: - IP address of the SSH server. + type: str name: description: - SSH public key name. required: true + type: str nid: description: - Set the nid of the ECDSA key. + type: str choices: - 256 - 384 @@ -98,18 +112,22 @@ options: port: description: - Port of the SSH server. - public-key: + type: int + public_key: description: - SSH public key. + type: str status: description: - Set the trust status of the public key. + type: str choices: - trusted - revoked type: description: - Set the type of the public key. + type: str choices: - RSA - DSA @@ -128,6 +146,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSH proxy host public keys. fortios_firewall_ssh_host_key: @@ -136,14 +155,14 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_ssh_host_key: - state: "present" hostname: "myhostname" ip: "" name: "default_name_5" nid: "256" port: "7" - public-key: "" + public_key: "" status: "trusted" type: "RSA" ''' @@ -208,14 +227,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -223,12 +244,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssh_host_key_data(json): option_list = ['hostname', 'ip', 'name', - 'nid', 'port', 'public-key', + 'nid', 'port', 'public_key', 'status', 'type'] dictionary = {} @@ -239,55 +260,73 @@ def filter_firewall_ssh_host_key_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssh_host_key(data, fos): vdom = data['vdom'] + state = data['state'] firewall_ssh_host_key_data = data['firewall_ssh_host_key'] - filtered_data = filter_firewall_ssh_host_key_data(firewall_ssh_host_key_data) - if firewall_ssh_host_key_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_ssh_host_key_data(firewall_ssh_host_key_data)) + + if state == "present": return fos.set('firewall.ssh', 'host-key', data=filtered_data, vdom=vdom) - elif firewall_ssh_host_key_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.ssh', 'host-key', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_ssh(data, fos): - login(data) - methodlist = ['firewall_ssh_host_key'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssh_host_key']: + resp = firewall_ssh_host_key(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_ssh_host_key": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "hostname": {"required": False, "type": "str"}, "ip": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, "nid": {"required": False, "type": "str", "choices": ["256", "384", "521"]}, "port": {"required": False, "type": "int"}, - "public-key": {"required": False, "type": "str"}, + "public_key": {"required": False, "type": "str"}, "status": {"required": False, "type": "str", "choices": ["trusted", "revoked"]}, "type": {"required": False, "type": "str", @@ -301,15 +340,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py index 4b3ce7332b0..6322f921b5f 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssh_local_ca short_description: SSH proxy local CA in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_ssh feature and local_ca category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_ssh feature and local_ca category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,56 +41,74 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_ssh_local_ca: description: - SSH proxy local CA. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent name: description: - SSH proxy local CA name. required: true + type: str password: description: - Password for SSH private key. - private-key: + type: str + private_key: description: - SSH proxy private key, encrypted with a password. - public-key: + type: str + public_key: description: - SSH proxy public key. + type: str source: description: - SSH proxy local CA source type. + type: str choices: - built-in - user @@ -106,6 +121,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSH proxy local CA. fortios_firewall_ssh_local_ca: @@ -114,12 +130,12 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_ssh_local_ca: - state: "present" name: "default_name_3" password: "" - private-key: "" - public-key: "" + private_key: "" + public_key: "" source: "built-in" ''' @@ -183,14 +199,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -198,12 +216,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssh_local_ca_data(json): - option_list = ['name', 'password', 'private-key', - 'public-key', 'source'] + option_list = ['name', 'password', 'private_key', + 'public_key', 'source'] dictionary = {} for attribute in option_list: @@ -213,52 +231,70 @@ def filter_firewall_ssh_local_ca_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssh_local_ca(data, fos): vdom = data['vdom'] + state = data['state'] firewall_ssh_local_ca_data = data['firewall_ssh_local_ca'] - filtered_data = filter_firewall_ssh_local_ca_data(firewall_ssh_local_ca_data) - if firewall_ssh_local_ca_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_ssh_local_ca_data(firewall_ssh_local_ca_data)) + + if state == "present": return fos.set('firewall.ssh', 'local-ca', data=filtered_data, vdom=vdom) - elif firewall_ssh_local_ca_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.ssh', 'local-ca', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_ssh(data, fos): - login(data) - methodlist = ['firewall_ssh_local_ca'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssh_local_ca']: + resp = firewall_ssh_local_ca(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_ssh_local_ca": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "name": {"required": True, "type": "str"}, "password": {"required": False, "type": "str"}, - "private-key": {"required": False, "type": "str"}, - "public-key": {"required": False, "type": "str"}, + "private_key": {"required": False, "type": "str"}, + "public_key": {"required": False, "type": "str"}, "source": {"required": False, "type": "str", "choices": ["built-in", "user"]} @@ -268,15 +304,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py index 6f29cfe81f3..5405c7618c6 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssh_local_key short_description: SSH proxy local keys in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_ssh feature and local_key category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_ssh feature and local_key category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,56 +41,74 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_ssh_local_key: description: - SSH proxy local keys. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent name: description: - SSH proxy local key name. required: true + type: str password: description: - Password for SSH private key. - private-key: + type: str + private_key: description: - SSH proxy private key, encrypted with a password. - public-key: + type: str + public_key: description: - SSH proxy public key. + type: str source: description: - SSH proxy local key source type. + type: str choices: - built-in - user @@ -106,6 +121,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSH proxy local keys. fortios_firewall_ssh_local_key: @@ -114,12 +130,12 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_ssh_local_key: - state: "present" name: "default_name_3" password: "" - private-key: "" - public-key: "" + private_key: "" + public_key: "" source: "built-in" ''' @@ -183,14 +199,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -198,12 +216,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssh_local_key_data(json): - option_list = ['name', 'password', 'private-key', - 'public-key', 'source'] + option_list = ['name', 'password', 'private_key', + 'public_key', 'source'] dictionary = {} for attribute in option_list: @@ -213,52 +231,70 @@ def filter_firewall_ssh_local_key_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssh_local_key(data, fos): vdom = data['vdom'] + state = data['state'] firewall_ssh_local_key_data = data['firewall_ssh_local_key'] - filtered_data = filter_firewall_ssh_local_key_data(firewall_ssh_local_key_data) - if firewall_ssh_local_key_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_ssh_local_key_data(firewall_ssh_local_key_data)) + + if state == "present": return fos.set('firewall.ssh', 'local-key', data=filtered_data, vdom=vdom) - elif firewall_ssh_local_key_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall.ssh', 'local-key', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_ssh(data, fos): - login(data) - methodlist = ['firewall_ssh_local_key'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssh_local_key']: + resp = firewall_ssh_local_key(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_ssh_local_key": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "name": {"required": True, "type": "str"}, "password": {"required": False, "type": "str"}, - "private-key": {"required": False, "type": "str"}, - "public-key": {"required": False, "type": "str"}, + "private_key": {"required": False, "type": "str"}, + "public_key": {"required": False, "type": "str"}, "source": {"required": False, "type": "str", "choices": ["built-in", "user"]} @@ -268,15 +304,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py index d6eb451f7e5..3a6f79f55bc 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssh_setting short_description: SSH proxy settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_ssh feature and setting category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_ssh feature and setting category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,64 +41,83 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 firewall_ssh_setting: description: - SSH proxy settings. default: null + type: dict suboptions: caname: description: - CA certificate used by SSH Inspection. Source firewall.ssh.local-ca.name. - host-trusted-checking: + type: str + host_trusted_checking: description: - Enable/disable host trusted checking. + type: str choices: - enable - disable - hostkey-dsa1024: + hostkey_dsa1024: description: - DSA certificate used by SSH proxy. Source firewall.ssh.local-key.name. - hostkey-ecdsa256: + type: str + hostkey_ecdsa256: description: - ECDSA nid256 certificate used by SSH proxy. Source firewall.ssh.local-key.name. - hostkey-ecdsa384: + type: str + hostkey_ecdsa384: description: - ECDSA nid384 certificate used by SSH proxy. Source firewall.ssh.local-key.name. - hostkey-ecdsa521: + type: str + hostkey_ecdsa521: description: - ECDSA nid384 certificate used by SSH proxy. Source firewall.ssh.local-key.name. - hostkey-ed25519: + type: str + hostkey_ed25519: description: - ED25519 hostkey used by SSH proxy. Source firewall.ssh.local-key.name. - hostkey-rsa2048: + type: str + hostkey_rsa2048: description: - RSA certificate used by SSH proxy. Source firewall.ssh.local-key.name. - untrusted-caname: + type: str + untrusted_caname: description: - Untrusted CA certificate used by SSH Inspection. Source firewall.ssh.local-ca.name. + type: str ''' EXAMPLES = ''' @@ -111,6 +127,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSH proxy settings. fortios_firewall_ssh_setting: @@ -121,14 +138,14 @@ EXAMPLES = ''' https: "False" firewall_ssh_setting: caname: " (source firewall.ssh.local-ca.name)" - host-trusted-checking: "enable" - hostkey-dsa1024: "myhostname (source firewall.ssh.local-key.name)" - hostkey-ecdsa256: "myhostname (source firewall.ssh.local-key.name)" - hostkey-ecdsa384: "myhostname (source firewall.ssh.local-key.name)" - hostkey-ecdsa521: "myhostname (source firewall.ssh.local-key.name)" - hostkey-ed25519: "myhostname (source firewall.ssh.local-key.name)" - hostkey-rsa2048: "myhostname (source firewall.ssh.local-key.name)" - untrusted-caname: " (source firewall.ssh.local-ca.name)" + host_trusted_checking: "enable" + hostkey_dsa1024: "myhostname (source firewall.ssh.local-key.name)" + hostkey_ecdsa256: "myhostname (source firewall.ssh.local-key.name)" + hostkey_ecdsa384: "myhostname (source firewall.ssh.local-key.name)" + hostkey_ecdsa521: "myhostname (source firewall.ssh.local-key.name)" + hostkey_ed25519: "myhostname (source firewall.ssh.local-key.name)" + hostkey_rsa2048: "myhostname (source firewall.ssh.local-key.name)" + untrusted_caname: " (source firewall.ssh.local-ca.name)" ''' RETURN = ''' @@ -191,14 +208,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -206,13 +225,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssh_setting_data(json): - option_list = ['caname', 'host-trusted-checking', 'hostkey-dsa1024', - 'hostkey-ecdsa256', 'hostkey-ecdsa384', 'hostkey-ecdsa521', - 'hostkey-ed25519', 'hostkey-rsa2048', 'untrusted-caname'] + option_list = ['caname', 'host_trusted_checking', 'hostkey_dsa1024', + 'hostkey_ecdsa256', 'hostkey_ecdsa384', 'hostkey_ecdsa521', + 'hostkey_ed25519', 'hostkey_rsa2048', 'untrusted_caname'] dictionary = {} for attribute in option_list: @@ -222,49 +241,66 @@ def filter_firewall_ssh_setting_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssh_setting(data, fos): vdom = data['vdom'] firewall_ssh_setting_data = data['firewall_ssh_setting'] - filtered_data = filter_firewall_ssh_setting_data(firewall_ssh_setting_data) + filtered_data = underscore_to_hyphen(filter_firewall_ssh_setting_data(firewall_ssh_setting_data)) + return fos.set('firewall.ssh', 'setting', data=filtered_data, vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_ssh(data, fos): - login(data) - methodlist = ['firewall_ssh_setting'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssh_setting']: + resp = firewall_ssh_setting(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "firewall_ssh_setting": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { "caname": {"required": False, "type": "str"}, - "host-trusted-checking": {"required": False, "type": "str", + "host_trusted_checking": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "hostkey-dsa1024": {"required": False, "type": "str"}, - "hostkey-ecdsa256": {"required": False, "type": "str"}, - "hostkey-ecdsa384": {"required": False, "type": "str"}, - "hostkey-ecdsa521": {"required": False, "type": "str"}, - "hostkey-ed25519": {"required": False, "type": "str"}, - "hostkey-rsa2048": {"required": False, "type": "str"}, - "untrusted-caname": {"required": False, "type": "str"} + "hostkey_dsa1024": {"required": False, "type": "str"}, + "hostkey_ecdsa256": {"required": False, "type": "str"}, + "hostkey_ecdsa384": {"required": False, "type": "str"}, + "hostkey_ecdsa521": {"required": False, "type": "str"}, + "hostkey_ed25519": {"required": False, "type": "str"}, + "hostkey_rsa2048": {"required": False, "type": "str"}, + "untrusted_caname": {"required": False, "type": "str"} } } @@ -272,15 +308,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_ssh(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py index ffd1de7ad84..4f24cab4dd3 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssl_server short_description: Configure SSL servers in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall feature and ssl_server category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall feature and ssl_server category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,113 +41,140 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 firewall_ssl_server: description: - Configure SSL servers. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - add-header-x-forwarded-proto: + add_header_x_forwarded_proto: description: - Enable/disable adding an X-Forwarded-Proto header to forwarded requests. + type: str choices: - enable - disable ip: description: - IPv4 address of the SSL server. - mapped-port: + type: str + mapped_port: description: - - Mapped server service port (1 - 65535, default = 80). + - Mapped server service port (1 - 65535). + type: int name: description: - Server name. required: true + type: str port: description: - - Server service port (1 - 65535, default = 443). - ssl-algorithm: + - Server service port (1 - 65535). + type: int + ssl_algorithm: description: - Relative strength of encryption algorithms accepted in negotiation. + type: str choices: - high - medium - low - ssl-cert: + ssl_cert: description: - - Name of certificate for SSL connections to this server (default = "Fortinet_CA_SSL"). Source vpn.certificate.local.name. - ssl-client-renegotiation: + - Name of certificate for SSL connections to this server. Source vpn.certificate.local.name. + type: str + ssl_client_renegotiation: description: - Allow or block client renegotiation by server. + type: str choices: - allow - deny - secure - ssl-dh-bits: + ssl_dh_bits: description: - - Bit-size of Diffie-Hellman (DH) prime used in DHE-RSA negotiation (default = 2048). + - Bit-size of Diffie-Hellman (DH) prime used in DHE-RSA negotiation. + type: str choices: - 768 - 1024 - 1536 - 2048 - ssl-max-version: + ssl_max_version: description: - Highest SSL/TLS version to negotiate. + type: str choices: - tls-1.0 - tls-1.1 - tls-1.2 - ssl-min-version: + ssl_min_version: description: - Lowest SSL/TLS version to negotiate. + type: str choices: - tls-1.0 - tls-1.1 - tls-1.2 - ssl-mode: + ssl_mode: description: - SSL/TLS mode for encryption and decryption of traffic. + type: str choices: - half - full - ssl-send-empty-frags: + ssl_send_empty_frags: description: - Enable/disable sending empty fragments to avoid attack on CBC IV. + type: str choices: - enable - disable - url-rewrite: + url_rewrite: description: - Enable/disable rewriting the URL. + type: str choices: - enable - disable @@ -163,6 +187,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure SSL servers. fortios_firewall_ssl_server: @@ -171,22 +196,22 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" firewall_ssl_server: - state: "present" - add-header-x-forwarded-proto: "enable" + add_header_x_forwarded_proto: "enable" ip: "" - mapped-port: "5" + mapped_port: "5" name: "default_name_6" port: "7" - ssl-algorithm: "high" - ssl-cert: " (source vpn.certificate.local.name)" - ssl-client-renegotiation: "allow" - ssl-dh-bits: "768" - ssl-max-version: "tls-1.0" - ssl-min-version: "tls-1.0" - ssl-mode: "half" - ssl-send-empty-frags: "enable" - url-rewrite: "enable" + ssl_algorithm: "high" + ssl_cert: " (source vpn.certificate.local.name)" + ssl_client_renegotiation: "allow" + ssl_dh_bits: "768" + ssl_max_version: "tls-1.0" + ssl_min_version: "tls-1.0" + ssl_mode: "half" + ssl_send_empty_frags: "enable" + url_rewrite: "enable" ''' RETURN = ''' @@ -249,14 +274,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -264,15 +291,15 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssl_server_data(json): - option_list = ['add-header-x-forwarded-proto', 'ip', 'mapped-port', - 'name', 'port', 'ssl-algorithm', - 'ssl-cert', 'ssl-client-renegotiation', 'ssl-dh-bits', - 'ssl-max-version', 'ssl-min-version', 'ssl-mode', - 'ssl-send-empty-frags', 'url-rewrite'] + option_list = ['add_header_x_forwarded_proto', 'ip', 'mapped_port', + 'name', 'port', 'ssl_algorithm', + 'ssl_cert', 'ssl_client_renegotiation', 'ssl_dh_bits', + 'ssl_max_version', 'ssl_min_version', 'ssl_mode', + 'ssl_send_empty_frags', 'url_rewrite'] dictionary = {} for attribute in option_list: @@ -282,71 +309,89 @@ def filter_firewall_ssl_server_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssl_server(data, fos): vdom = data['vdom'] + state = data['state'] firewall_ssl_server_data = data['firewall_ssl_server'] - filtered_data = filter_firewall_ssl_server_data(firewall_ssl_server_data) - if firewall_ssl_server_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_ssl_server_data(firewall_ssl_server_data)) + + if state == "present": return fos.set('firewall', 'ssl-server', data=filtered_data, vdom=vdom) - elif firewall_ssl_server_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'ssl-server', mkey=filtered_data['name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall(data, fos): - login(data) - methodlist = ['firewall_ssl_server'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssl_server']: + resp = firewall_ssl_server(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_ssl_server": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "add-header-x-forwarded-proto": {"required": False, "type": "str", + "add_header_x_forwarded_proto": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "ip": {"required": False, "type": "str"}, - "mapped-port": {"required": False, "type": "int"}, + "mapped_port": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"}, "port": {"required": False, "type": "int"}, - "ssl-algorithm": {"required": False, "type": "str", + "ssl_algorithm": {"required": False, "type": "str", "choices": ["high", "medium", "low"]}, - "ssl-cert": {"required": False, "type": "str"}, - "ssl-client-renegotiation": {"required": False, "type": "str", + "ssl_cert": {"required": False, "type": "str"}, + "ssl_client_renegotiation": {"required": False, "type": "str", "choices": ["allow", "deny", "secure"]}, - "ssl-dh-bits": {"required": False, "type": "str", + "ssl_dh_bits": {"required": False, "type": "str", "choices": ["768", "1024", "1536", "2048"]}, - "ssl-max-version": {"required": False, "type": "str", + "ssl_max_version": {"required": False, "type": "str", "choices": ["tls-1.0", "tls-1.1", "tls-1.2"]}, - "ssl-min-version": {"required": False, "type": "str", + "ssl_min_version": {"required": False, "type": "str", "choices": ["tls-1.0", "tls-1.1", "tls-1.2"]}, - "ssl-mode": {"required": False, "type": "str", + "ssl_mode": {"required": False, "type": "str", "choices": ["half", "full"]}, - "ssl-send-empty-frags": {"required": False, "type": "str", + "ssl_send_empty_frags": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "url-rewrite": {"required": False, "type": "str", + "url_rewrite": {"required": False, "type": "str", "choices": ["enable", "disable"]} } @@ -355,15 +400,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py index 4778f431f42..836c2c8087c 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_firewall_ssl_setting short_description: SSL proxy settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure firewall_ssl feature and setting category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify firewall_ssl feature and setting category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,80 +41,99 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip adress. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 firewall_ssl_setting: description: - SSL proxy settings. default: null + type: dict suboptions: - abbreviate-handshake: + abbreviate_handshake: description: - Enable/disable use of SSL abbreviated handshake. + type: str choices: - enable - disable - cert-cache-capacity: + cert_cache_capacity: description: - - Maximum capacity of the host certificate cache (0 - 500, default = 200). - cert-cache-timeout: + - Maximum capacity of the host certificate cache (0 - 500). + type: int + cert_cache_timeout: description: - - Time limit to keep certificate cache (1 - 120 min, default = 10). - kxp-queue-threshold: + - Time limit to keep certificate cache (1 - 120 min). + type: int + kxp_queue_threshold: description: - - Maximum length of the CP KXP queue. When the queue becomes full, the proxy switches cipher functions to the main CPU (0 - 512, default = - 16). - no-matching-cipher-action: + - Maximum length of the CP KXP queue. When the queue becomes full, the proxy switches cipher functions to the main CPU (0 - 512). + type: int + no_matching_cipher_action: description: - Bypass or drop the connection when no matching cipher is found. + type: str choices: - bypass - drop - proxy-connect-timeout: + proxy_connect_timeout: description: - - Time limit to make an internal connection to the appropriate proxy process (1 - 60 sec, default = 30). - session-cache-capacity: + - Time limit to make an internal connection to the appropriate proxy process (1 - 60 sec). + type: int + session_cache_capacity: description: - - Capacity of the SSL session cache (--Obsolete--) (1 - 1000, default = 500). - session-cache-timeout: + - Capacity of the SSL session cache (--Obsolete--) (1 - 1000). + type: int + session_cache_timeout: description: - - Time limit to keep SSL session state (1 - 60 min, default = 20). - ssl-dh-bits: + - Time limit to keep SSL session state (1 - 60 min). + type: int + ssl_dh_bits: description: - - Bit-size of Diffie-Hellman (DH) prime used in DHE-RSA negotiation (default = 2048). + - Bit-size of Diffie-Hellman (DH) prime used in DHE-RSA negotiation. + type: str choices: - 768 - 1024 - 1536 - 2048 - ssl-queue-threshold: + ssl_queue_threshold: description: - - Maximum length of the CP SSL queue. When the queue becomes full, the proxy switches cipher functions to the main CPU (0 - 512, default = - 32). - ssl-send-empty-frags: + - Maximum length of the CP SSL queue. When the queue becomes full, the proxy switches cipher functions to the main CPU (0 - 512). + type: int + ssl_send_empty_frags: description: - Enable/disable sending empty fragments to avoid attack on CBC IV (for SSL 3.0 and TLS 1.0 only). + type: str choices: - enable - disable @@ -130,6 +146,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSL proxy settings. fortios_firewall_ssl_setting: @@ -139,17 +156,17 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" firewall_ssl_setting: - abbreviate-handshake: "enable" - cert-cache-capacity: "4" - cert-cache-timeout: "5" - kxp-queue-threshold: "6" - no-matching-cipher-action: "bypass" - proxy-connect-timeout: "8" - session-cache-capacity: "9" - session-cache-timeout: "10" - ssl-dh-bits: "768" - ssl-queue-threshold: "12" - ssl-send-empty-frags: "enable" + abbreviate_handshake: "enable" + cert_cache_capacity: "4" + cert_cache_timeout: "5" + kxp_queue_threshold: "6" + no_matching_cipher_action: "bypass" + proxy_connect_timeout: "8" + session_cache_capacity: "9" + session_cache_timeout: "10" + ssl_dh_bits: "768" + ssl_queue_threshold: "12" + ssl_send_empty_frags: "enable" ''' RETURN = ''' @@ -212,14 +229,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -227,14 +246,14 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_ssl_setting_data(json): - option_list = ['abbreviate-handshake', 'cert-cache-capacity', 'cert-cache-timeout', - 'kxp-queue-threshold', 'no-matching-cipher-action', 'proxy-connect-timeout', - 'session-cache-capacity', 'session-cache-timeout', 'ssl-dh-bits', - 'ssl-queue-threshold', 'ssl-send-empty-frags'] + option_list = ['abbreviate_handshake', 'cert_cache_capacity', 'cert_cache_timeout', + 'kxp_queue_threshold', 'no_matching_cipher_action', 'proxy_connect_timeout', + 'session_cache_capacity', 'session_cache_timeout', 'ssl_dh_bits', + 'ssl_queue_threshold', 'ssl_send_empty_frags'] dictionary = {} for attribute in option_list: @@ -244,54 +263,71 @@ def filter_firewall_ssl_setting_data(json): return dictionary +def underscore_to_hyphen(data): + if isinstance(data, list): + for elem in data: + elem = underscore_to_hyphen(elem) + elif isinstance(data, dict): + new_data = {} + for k, v in data.items(): + new_data[k.replace('_', '-')] = underscore_to_hyphen(v) + data = new_data + + return data + + def firewall_ssl_setting(data, fos): vdom = data['vdom'] firewall_ssl_setting_data = data['firewall_ssl_setting'] - filtered_data = filter_firewall_ssl_setting_data(firewall_ssl_setting_data) + filtered_data = underscore_to_hyphen(filter_firewall_ssl_setting_data(firewall_ssl_setting_data)) + return fos.set('firewall.ssl', 'setting', data=filtered_data, vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_firewall_ssl(data, fos): - login(data) - methodlist = ['firewall_ssl_setting'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_ssl_setting']: + resp = firewall_ssl_setting(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "firewall_ssl_setting": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "abbreviate-handshake": {"required": False, "type": "str", + "abbreviate_handshake": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "cert-cache-capacity": {"required": False, "type": "int"}, - "cert-cache-timeout": {"required": False, "type": "int"}, - "kxp-queue-threshold": {"required": False, "type": "int"}, - "no-matching-cipher-action": {"required": False, "type": "str", + "cert_cache_capacity": {"required": False, "type": "int"}, + "cert_cache_timeout": {"required": False, "type": "int"}, + "kxp_queue_threshold": {"required": False, "type": "int"}, + "no_matching_cipher_action": {"required": False, "type": "str", "choices": ["bypass", "drop"]}, - "proxy-connect-timeout": {"required": False, "type": "int"}, - "session-cache-capacity": {"required": False, "type": "int"}, - "session-cache-timeout": {"required": False, "type": "int"}, - "ssl-dh-bits": {"required": False, "type": "str", + "proxy_connect_timeout": {"required": False, "type": "int"}, + "session_cache_capacity": {"required": False, "type": "int"}, + "session_cache_timeout": {"required": False, "type": "int"}, + "ssl_dh_bits": {"required": False, "type": "str", "choices": ["768", "1024", "1536", "2048"]}, - "ssl-queue-threshold": {"required": False, "type": "int"}, - "ssl-send-empty-frags": {"required": False, "type": "str", + "ssl_queue_threshold": {"required": False, "type": "int"}, + "ssl_send_empty_frags": {"required": False, "type": "str", "choices": ["enable", "disable"]} } @@ -300,15 +336,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_firewall_ssl(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() - is_error, has_changed, result = fortios_firewall_ssl(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_firewall_ssl(module.params, fos) + fos.logout() if not is_error: module.exit_json(changed=has_changed, meta=result) diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 8a0b6db580b..8089d597d68 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -3694,41 +3694,7 @@ lib/ansible/modules/network/fortios/fortios_config.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_firewall_policy.py validate-modules:E326 -lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_proxy_address.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_proxy_addrgrp.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_proxy_policy.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_schedule_group.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_schedule_onetime.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_schedule_recurring.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_service_category.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_service_custom.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_service_group.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_shaper_per_ip_shaper.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_shaper_traffic_shaper.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_shaping_policy.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_shaping_profile.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_host_key.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_ca.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_local_key.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssh_setting.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssl_server.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_ssl_setting.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py validate-modules:E337 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_proxy_address.py b/test/units/modules/network/fortios/test_fortios_firewall_proxy_address.py new file mode 100644 index 00000000000..c0e77cbb8d6 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_proxy_address.py @@ -0,0 +1,349 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_proxy_address +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_proxy_address.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_proxy_address_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_address': { + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'case-sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header-name': 'test_value_7', + 'host': 'myhostname8', + 'host-regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-address', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_address_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_address': { + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'case-sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header-name': 'test_value_7', + 'host': 'myhostname8', + 'host-regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-address', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_address_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_address': { + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-address', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_address_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_address': { + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-address', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_address_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_address': { + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'case-sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header-name': 'test_value_7', + 'host': 'myhostname8', + 'host-regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-address', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_proxy_address_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_address': { + 'random_attribute_not_valid': 'tag', + 'case_sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header_name': 'test_value_7', + 'host': 'myhostname8', + 'host_regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'case-sensitivity': 'disable', + 'color': '4', + 'comment': 'Optional comments.', + 'header': 'test_value_6', + 'header-name': 'test_value_7', + 'host': 'myhostname8', + 'host-regex': 'myhostname9', + 'method': 'get', + 'name': 'default_name_11', + 'path': 'test_value_12', + 'query': 'test_value_13', + 'referrer': 'enable', + 'type': 'host-regex', + 'ua': 'chrome', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-address', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_proxy_addrgrp.py b/test/units/modules/network/fortios/test_fortios_firewall_proxy_addrgrp.py new file mode 100644 index 00000000000..7bc4477485b --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_proxy_addrgrp.py @@ -0,0 +1,249 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_proxy_addrgrp +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_proxy_addrgrp.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_proxy_addrgrp_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_addrgrp': { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-addrgrp', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_addrgrp_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_addrgrp': { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-addrgrp', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_addrgrp_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_addrgrp': { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-addrgrp', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_addrgrp_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_addrgrp': { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-addrgrp', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_addrgrp_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_addrgrp': { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-addrgrp', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_proxy_addrgrp_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_addrgrp': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Optional comments.', + 'name': 'default_name_5', + 'type': 'src', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'proxy-addrgrp', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_proxy_policy.py b/test/units/modules/network/fortios/test_fortios_firewall_proxy_policy.py new file mode 100644 index 00000000000..72609465efc --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_proxy_policy.py @@ -0,0 +1,599 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_proxy_policy +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_proxy_policy.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_proxy_policy_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_policy': { + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'action': 'accept', + 'application-list': 'test_value_4', + 'av-profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp-sensor': 'test_value_8', + 'dstaddr-negate': 'enable', + 'global-label': 'test_value_10', + 'http-tunnel-auth': 'enable', + 'icap-profile': 'test_value_12', + 'internet-service': 'enable', + 'internet-service-negate': 'enable', + 'ips-sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic-start': 'enable', + 'policyid': '19', + 'profile-group': 'test_value_20', + 'profile-protocol-options': 'test_value_21', + 'profile-type': 'single', + 'proxy': 'explicit-web', + 'redirect-url': 'test_value_24', + 'replacemsg-override-group': 'test_value_25', + 'scan-botnet-connections': 'disable', + 'schedule': 'test_value_27', + 'service-negate': 'enable', + 'session-ttl': '29', + 'spamfilter-profile': 'test_value_30', + 'srcaddr-negate': 'enable', + 'ssh-filter-profile': 'test_value_32', + 'ssl-ssh-profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm-status': 'enable', + 'uuid': 'test_value_37', + 'waf-profile': 'test_value_38', + 'webcache': 'enable', + 'webcache-https': 'disable', + 'webfilter-profile': 'test_value_41', + 'webproxy-forward-server': 'test_value_42', + 'webproxy-profile': 'test_value_43' + } + + set_method_mock.assert_called_with('firewall', 'proxy-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_policy_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_policy': { + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'action': 'accept', + 'application-list': 'test_value_4', + 'av-profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp-sensor': 'test_value_8', + 'dstaddr-negate': 'enable', + 'global-label': 'test_value_10', + 'http-tunnel-auth': 'enable', + 'icap-profile': 'test_value_12', + 'internet-service': 'enable', + 'internet-service-negate': 'enable', + 'ips-sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic-start': 'enable', + 'policyid': '19', + 'profile-group': 'test_value_20', + 'profile-protocol-options': 'test_value_21', + 'profile-type': 'single', + 'proxy': 'explicit-web', + 'redirect-url': 'test_value_24', + 'replacemsg-override-group': 'test_value_25', + 'scan-botnet-connections': 'disable', + 'schedule': 'test_value_27', + 'service-negate': 'enable', + 'session-ttl': '29', + 'spamfilter-profile': 'test_value_30', + 'srcaddr-negate': 'enable', + 'ssh-filter-profile': 'test_value_32', + 'ssl-ssh-profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm-status': 'enable', + 'uuid': 'test_value_37', + 'waf-profile': 'test_value_38', + 'webcache': 'enable', + 'webcache-https': 'disable', + 'webfilter-profile': 'test_value_41', + 'webproxy-forward-server': 'test_value_42', + 'webproxy-profile': 'test_value_43' + } + + set_method_mock.assert_called_with('firewall', 'proxy-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_policy_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_policy': { + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-policy', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_proxy_policy_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_proxy_policy': { + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'proxy-policy', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_proxy_policy_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_policy': { + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'action': 'accept', + 'application-list': 'test_value_4', + 'av-profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp-sensor': 'test_value_8', + 'dstaddr-negate': 'enable', + 'global-label': 'test_value_10', + 'http-tunnel-auth': 'enable', + 'icap-profile': 'test_value_12', + 'internet-service': 'enable', + 'internet-service-negate': 'enable', + 'ips-sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic-start': 'enable', + 'policyid': '19', + 'profile-group': 'test_value_20', + 'profile-protocol-options': 'test_value_21', + 'profile-type': 'single', + 'proxy': 'explicit-web', + 'redirect-url': 'test_value_24', + 'replacemsg-override-group': 'test_value_25', + 'scan-botnet-connections': 'disable', + 'schedule': 'test_value_27', + 'service-negate': 'enable', + 'session-ttl': '29', + 'spamfilter-profile': 'test_value_30', + 'srcaddr-negate': 'enable', + 'ssh-filter-profile': 'test_value_32', + 'ssl-ssh-profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm-status': 'enable', + 'uuid': 'test_value_37', + 'waf-profile': 'test_value_38', + 'webcache': 'enable', + 'webcache-https': 'disable', + 'webfilter-profile': 'test_value_41', + 'webproxy-forward-server': 'test_value_42', + 'webproxy-profile': 'test_value_43' + } + + set_method_mock.assert_called_with('firewall', 'proxy-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_proxy_policy_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_proxy_policy': { + 'random_attribute_not_valid': 'tag', + 'action': 'accept', + 'application_list': 'test_value_4', + 'av_profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp_sensor': 'test_value_8', + 'dstaddr_negate': 'enable', + 'global_label': 'test_value_10', + 'http_tunnel_auth': 'enable', + 'icap_profile': 'test_value_12', + 'internet_service': 'enable', + 'internet_service_negate': 'enable', + 'ips_sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic_start': 'enable', + 'policyid': '19', + 'profile_group': 'test_value_20', + 'profile_protocol_options': 'test_value_21', + 'profile_type': 'single', + 'proxy': 'explicit-web', + 'redirect_url': 'test_value_24', + 'replacemsg_override_group': 'test_value_25', + 'scan_botnet_connections': 'disable', + 'schedule': 'test_value_27', + 'service_negate': 'enable', + 'session_ttl': '29', + 'spamfilter_profile': 'test_value_30', + 'srcaddr_negate': 'enable', + 'ssh_filter_profile': 'test_value_32', + 'ssl_ssh_profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm_status': 'enable', + 'uuid': 'test_value_37', + 'waf_profile': 'test_value_38', + 'webcache': 'enable', + 'webcache_https': 'disable', + 'webfilter_profile': 'test_value_41', + 'webproxy_forward_server': 'test_value_42', + 'webproxy_profile': 'test_value_43' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_proxy_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'action': 'accept', + 'application-list': 'test_value_4', + 'av-profile': 'test_value_5', + 'comments': 'test_value_6', + 'disclaimer': 'disable', + 'dlp-sensor': 'test_value_8', + 'dstaddr-negate': 'enable', + 'global-label': 'test_value_10', + 'http-tunnel-auth': 'enable', + 'icap-profile': 'test_value_12', + 'internet-service': 'enable', + 'internet-service-negate': 'enable', + 'ips-sensor': 'test_value_15', + 'label': 'test_value_16', + 'logtraffic': 'all', + 'logtraffic-start': 'enable', + 'policyid': '19', + 'profile-group': 'test_value_20', + 'profile-protocol-options': 'test_value_21', + 'profile-type': 'single', + 'proxy': 'explicit-web', + 'redirect-url': 'test_value_24', + 'replacemsg-override-group': 'test_value_25', + 'scan-botnet-connections': 'disable', + 'schedule': 'test_value_27', + 'service-negate': 'enable', + 'session-ttl': '29', + 'spamfilter-profile': 'test_value_30', + 'srcaddr-negate': 'enable', + 'ssh-filter-profile': 'test_value_32', + 'ssl-ssh-profile': 'test_value_33', + 'status': 'enable', + 'transparent': 'enable', + 'utm-status': 'enable', + 'uuid': 'test_value_37', + 'waf-profile': 'test_value_38', + 'webcache': 'enable', + 'webcache-https': 'disable', + 'webfilter-profile': 'test_value_41', + 'webproxy-forward-server': 'test_value_42', + 'webproxy-profile': 'test_value_43' + } + + set_method_mock.assert_called_with('firewall', 'proxy-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_schedule_group.py b/test/units/modules/network/fortios/test_fortios_firewall_schedule_group.py new file mode 100644 index 00000000000..5d0ffac12b8 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_schedule_group.py @@ -0,0 +1,209 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_schedule_group +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_schedule_group.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_schedule_group_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_group': { + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.schedule', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_group_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_group': { + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.schedule', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_group_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_group': { + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'group', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_group_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_group': { + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'group', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_group_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_group': { + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.schedule', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_schedule_group_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_group': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_group.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.schedule', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_schedule_onetime.py b/test/units/modules/network/fortios/test_fortios_firewall_schedule_onetime.py new file mode 100644 index 00000000000..ff6f09434a8 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_schedule_onetime.py @@ -0,0 +1,239 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_schedule_onetime +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_schedule_onetime.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_schedule_onetime_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_onetime': { + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'end': 'test_value_4', + 'expiration-days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'onetime', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_onetime_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_onetime': { + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'end': 'test_value_4', + 'expiration-days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'onetime', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_onetime_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_onetime': { + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'onetime', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_onetime_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_onetime': { + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'onetime', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_onetime_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_onetime': { + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'end': 'test_value_4', + 'expiration-days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'onetime', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_schedule_onetime_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_onetime': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'end': 'test_value_4', + 'expiration_days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_onetime.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'end': 'test_value_4', + 'expiration-days': '5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'onetime', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_schedule_recurring.py b/test/units/modules/network/fortios/test_fortios_firewall_schedule_recurring.py new file mode 100644 index 00000000000..8a1463a683e --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_schedule_recurring.py @@ -0,0 +1,239 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_schedule_recurring +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_schedule_recurring.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_schedule_recurring_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_recurring': { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'recurring', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_recurring_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_recurring': { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'recurring', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_recurring_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_recurring': { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'recurring', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_schedule_recurring_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_schedule_recurring': { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.schedule', 'recurring', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_schedule_recurring_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_recurring': { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'recurring', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_schedule_recurring_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_schedule_recurring': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_schedule_recurring.fortios_firewall_schedule(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'day': 'sunday', + 'end': 'test_value_5', + 'name': 'default_name_6', + 'start': 'test_value_7' + } + + set_method_mock.assert_called_with('firewall.schedule', 'recurring', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_service_category.py b/test/units/modules/network/fortios/test_fortios_firewall_service_category.py new file mode 100644 index 00000000000..2c896c3c4a9 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_service_category.py @@ -0,0 +1,209 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_service_category +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_service_category.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_service_category_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_category': { + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.service', 'category', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_category_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_category': { + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.service', 'category', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_category_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_category': { + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'category', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_category_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_category': { + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'category', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_category_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_category': { + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.service', 'category', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_service_category_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_category': { + 'random_attribute_not_valid': 'tag', + 'comment': 'Comment.', + 'name': 'default_name_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_category.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'name': 'default_name_4' + } + + set_method_mock.assert_called_with('firewall.service', 'category', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_service_custom.py b/test/units/modules/network/fortios/test_fortios_firewall_service_custom.py new file mode 100644 index 00000000000..15eae37fdb0 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_service_custom.py @@ -0,0 +1,409 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_service_custom +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_service_custom.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_service_custom_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_custom': {'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + expected_data = {'app-service-type': 'disable', + 'category': 'test_value_4', + 'check-reset-range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol-number': '15', + 'proxy': 'enable', + 'sctp-portrange': 'test_value_17', + 'session-ttl': '18', + 'tcp-halfclose-timer': '19', + 'tcp-halfopen-timer': '20', + 'tcp-portrange': 'test_value_21', + 'tcp-timewait-timer': '22', + 'udp-idle-timer': '23', + 'udp-portrange': 'test_value_24', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'custom', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_custom_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_custom': {'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + expected_data = {'app-service-type': 'disable', + 'category': 'test_value_4', + 'check-reset-range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol-number': '15', + 'proxy': 'enable', + 'sctp-portrange': 'test_value_17', + 'session-ttl': '18', + 'tcp-halfclose-timer': '19', + 'tcp-halfopen-timer': '20', + 'tcp-portrange': 'test_value_21', + 'tcp-timewait-timer': '22', + 'udp-idle-timer': '23', + 'udp-portrange': 'test_value_24', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'custom', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_custom_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_custom': {'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'custom', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_custom_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_custom': {'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'custom', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_custom_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_custom': {'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + expected_data = {'app-service-type': 'disable', + 'category': 'test_value_4', + 'check-reset-range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol-number': '15', + 'proxy': 'enable', + 'sctp-portrange': 'test_value_17', + 'session-ttl': '18', + 'tcp-halfclose-timer': '19', + 'tcp-halfopen-timer': '20', + 'tcp-portrange': 'test_value_21', + 'tcp-timewait-timer': '22', + 'udp-idle-timer': '23', + 'udp-portrange': 'test_value_24', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'custom', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_service_custom_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_custom': { + 'random_attribute_not_valid': 'tag', 'app_service_type': 'disable', + 'category': 'test_value_4', + 'check_reset_range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol_number': '15', + 'proxy': 'enable', + 'sctp_portrange': 'test_value_17', + 'session_ttl': '18', + 'tcp_halfclose_timer': '19', + 'tcp_halfopen_timer': '20', + 'tcp_portrange': 'test_value_21', + 'tcp_timewait_timer': '22', + 'udp_idle_timer': '23', + 'udp_portrange': 'test_value_24', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_custom.fortios_firewall_service(input_data, fos_instance) + + expected_data = {'app-service-type': 'disable', + 'category': 'test_value_4', + 'check-reset-range': 'disable', + 'color': '6', + 'comment': 'Comment.', + 'fqdn': 'test_value_8', + 'helper': 'auto', + 'icmpcode': '10', + 'icmptype': '11', + 'iprange': 'test_value_12', + 'name': 'default_name_13', + 'protocol': 'TCP/UDP/SCTP', + 'protocol-number': '15', + 'proxy': 'enable', + 'sctp-portrange': 'test_value_17', + 'session-ttl': '18', + 'tcp-halfclose-timer': '19', + 'tcp-halfopen-timer': '20', + 'tcp-portrange': 'test_value_21', + 'tcp-timewait-timer': '22', + 'udp-idle-timer': '23', + 'udp-portrange': 'test_value_24', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'custom', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_service_group.py b/test/units/modules/network/fortios/test_fortios_firewall_service_group.py new file mode 100644 index 00000000000..51b36bdba58 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_service_group.py @@ -0,0 +1,229 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_service_group +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_service_group.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_service_group_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_group': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_group_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_group': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_group_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_group': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'group', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_service_group_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_service_group': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.service', 'group', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_service_group_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_group': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_service_group_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_service_group': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_service_group.fortios_firewall_service(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'proxy': 'enable' + } + + set_method_mock.assert_called_with('firewall.service', 'group', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_shaper_per_ip_shaper.py b/test/units/modules/network/fortios/test_fortios_firewall_shaper_per_ip_shaper.py new file mode 100644 index 00000000000..54fc4a35137 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_shaper_per_ip_shaper.py @@ -0,0 +1,269 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_shaper_per_ip_shaper +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_shaper_per_ip_shaper.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_shaper_per_ip_shaper_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_per_ip_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv-forward': 'enable', + 'diffserv-reverse': 'enable', + 'diffservcode-forward': 'test_value_6', + 'diffservcode-rev': 'test_value_7', + 'max-bandwidth': '8', + 'max-concurrent-session': '9', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaper_per_ip_shaper_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_per_ip_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv-forward': 'enable', + 'diffserv-reverse': 'enable', + 'diffservcode-forward': 'test_value_6', + 'diffservcode-rev': 'test_value_7', + 'max-bandwidth': '8', + 'max-concurrent-session': '9', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaper_per_ip_shaper_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaper_per_ip_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaper_per_ip_shaper_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaper_per_ip_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaper_per_ip_shaper_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_per_ip_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv-forward': 'enable', + 'diffserv-reverse': 'enable', + 'diffservcode-forward': 'test_value_6', + 'diffservcode-rev': 'test_value_7', + 'max-bandwidth': '8', + 'max-concurrent-session': '9', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_shaper_per_ip_shaper_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_per_ip_shaper': { + 'random_attribute_not_valid': 'tag', + 'bandwidth_unit': 'kbps', + 'diffserv_forward': 'enable', + 'diffserv_reverse': 'enable', + 'diffservcode_forward': 'test_value_6', + 'diffservcode_rev': 'test_value_7', + 'max_bandwidth': '8', + 'max_concurrent_session': '9', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_per_ip_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv-forward': 'enable', + 'diffserv-reverse': 'enable', + 'diffservcode-forward': 'test_value_6', + 'diffservcode-rev': 'test_value_7', + 'max-bandwidth': '8', + 'max-concurrent-session': '9', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('firewall.shaper', 'per-ip-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_shaper_traffic_shaper.py b/test/units/modules/network/fortios/test_fortios_firewall_shaper_traffic_shaper.py new file mode 100644 index 00000000000..fb62200ae8a --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_shaper_traffic_shaper.py @@ -0,0 +1,269 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_shaper_traffic_shaper +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_shaper_traffic_shaper.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_shaper_traffic_shaper_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_traffic_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed-bandwidth': '6', + 'maximum-bandwidth': '7', + 'name': 'default_name_8', + 'per-policy': 'disable', + 'priority': 'low' + } + + set_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaper_traffic_shaper_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_traffic_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed-bandwidth': '6', + 'maximum-bandwidth': '7', + 'name': 'default_name_8', + 'per-policy': 'disable', + 'priority': 'low' + } + + set_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaper_traffic_shaper_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaper_traffic_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaper_traffic_shaper_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaper_traffic_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaper_traffic_shaper_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_traffic_shaper': { + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed-bandwidth': '6', + 'maximum-bandwidth': '7', + 'name': 'default_name_8', + 'per-policy': 'disable', + 'priority': 'low' + } + + set_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_shaper_traffic_shaper_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaper_traffic_shaper': { + 'random_attribute_not_valid': 'tag', + 'bandwidth_unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed_bandwidth': '6', + 'maximum_bandwidth': '7', + 'name': 'default_name_8', + 'per_policy': 'disable', + 'priority': 'low' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaper_traffic_shaper.fortios_firewall_shaper(input_data, fos_instance) + + expected_data = { + 'bandwidth-unit': 'kbps', + 'diffserv': 'enable', + 'diffservcode': 'test_value_5', + 'guaranteed-bandwidth': '6', + 'maximum-bandwidth': '7', + 'name': 'default_name_8', + 'per-policy': 'disable', + 'priority': 'low' + } + + set_method_mock.assert_called_with('firewall.shaper', 'traffic-shaper', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_shaping_policy.py b/test/units/modules/network/fortios/test_fortios_firewall_shaping_policy.py new file mode 100644 index 00000000000..d8812a76e57 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_shaping_policy.py @@ -0,0 +1,299 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_shaping_policy +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_shaping_policy.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_shaping_policy_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_policy': {'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'class-id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet-service': 'enable', + 'internet-service-src': 'enable', + 'ip-version': '4', + 'per-ip-shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic-shaper': 'test_value_12', + 'traffic-shaper-reverse': 'test_value_13', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaping_policy_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_policy': {'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'class-id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet-service': 'enable', + 'internet-service-src': 'enable', + 'ip-version': '4', + 'per-ip-shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic-shaper': 'test_value_12', + 'traffic-shaper-reverse': 'test_value_13', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaping_policy_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaping_policy': {'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'shaping-policy', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaping_policy_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaping_policy': {'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'shaping-policy', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaping_policy_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_policy': {'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'class-id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet-service': 'enable', + 'internet-service-src': 'enable', + 'ip-version': '4', + 'per-ip-shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic-shaper': 'test_value_12', + 'traffic-shaper-reverse': 'test_value_13', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_shaping_policy_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_policy': { + 'random_attribute_not_valid': 'tag', 'class_id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet_service': 'enable', + 'internet_service_src': 'enable', + 'ip_version': '4', + 'per_ip_shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic_shaper': 'test_value_12', + 'traffic_shaper_reverse': 'test_value_13', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'class-id': '3', + 'comment': 'Comments.', + 'id': '5', + 'internet-service': 'enable', + 'internet-service-src': 'enable', + 'ip-version': '4', + 'per-ip-shaper': 'test_value_9', + 'schedule': 'test_value_10', + 'status': 'enable', + 'traffic-shaper': 'test_value_12', + 'traffic-shaper-reverse': 'test_value_13', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-policy', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_shaping_profile.py b/test/units/modules/network/fortios/test_fortios_firewall_shaping_profile.py new file mode 100644 index 00000000000..d9522bc7b0c --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_shaping_profile.py @@ -0,0 +1,229 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_shaping_profile +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_shaping_profile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_shaping_profile_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_profile': { + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'default-class-id': '4', + 'profile-name': 'test_value_5', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-profile', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaping_profile_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_profile': { + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'default-class-id': '4', + 'profile-name': 'test_value_5', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-profile', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaping_profile_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaping_profile': { + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'shaping-profile', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_shaping_profile_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_shaping_profile': { + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'shaping-profile', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_shaping_profile_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_profile': { + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'default-class-id': '4', + 'profile-name': 'test_value_5', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-profile', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_shaping_profile_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_shaping_profile': { + 'random_attribute_not_valid': 'tag', + 'comment': 'Comment.', + 'default_class_id': '4', + 'profile_name': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_shaping_profile.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'default-class-id': '4', + 'profile-name': 'test_value_5', + + } + + set_method_mock.assert_called_with('firewall', 'shaping-profile', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_sniffer.py b/test/units/modules/network/fortios/test_fortios_firewall_sniffer.py new file mode 100644 index 00000000000..b69e26785c4 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_sniffer.py @@ -0,0 +1,439 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_sniffer +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_sniffer.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_sniffer_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_sniffer': {'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + expected_data = {'application-list': 'test_value_3', + 'application-list-status': 'enable', + 'av-profile': 'test_value_5', + 'av-profile-status': 'enable', + 'dlp-sensor': 'test_value_7', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips-dos-status': 'enable', + 'ips-sensor': 'test_value_14', + 'ips-sensor-status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max-packet-count': '18', + 'non-ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_23', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter-profile': 'test_value_27', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'sniffer', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_sniffer_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_sniffer': {'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + expected_data = {'application-list': 'test_value_3', + 'application-list-status': 'enable', + 'av-profile': 'test_value_5', + 'av-profile-status': 'enable', + 'dlp-sensor': 'test_value_7', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips-dos-status': 'enable', + 'ips-sensor': 'test_value_14', + 'ips-sensor-status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max-packet-count': '18', + 'non-ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_23', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter-profile': 'test_value_27', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'sniffer', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_sniffer_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_sniffer': {'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'sniffer', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_sniffer_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_sniffer': {'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'sniffer', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_sniffer_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_sniffer': {'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + expected_data = {'application-list': 'test_value_3', + 'application-list-status': 'enable', + 'av-profile': 'test_value_5', + 'av-profile-status': 'enable', + 'dlp-sensor': 'test_value_7', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips-dos-status': 'enable', + 'ips-sensor': 'test_value_14', + 'ips-sensor-status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max-packet-count': '18', + 'non-ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_23', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter-profile': 'test_value_27', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'sniffer', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_sniffer_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_sniffer': { + 'random_attribute_not_valid': 'tag', 'application_list': 'test_value_3', + 'application_list_status': 'enable', + 'av_profile': 'test_value_5', + 'av_profile_status': 'enable', + 'dlp_sensor': 'test_value_7', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips_dos_status': 'enable', + 'ips_sensor': 'test_value_14', + 'ips_sensor_status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max_packet_count': '18', + 'non_ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_23', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter_profile': 'test_value_27', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_sniffer.fortios_firewall(input_data, fos_instance) + + expected_data = {'application-list': 'test_value_3', + 'application-list-status': 'enable', + 'av-profile': 'test_value_5', + 'av-profile-status': 'enable', + 'dlp-sensor': 'test_value_7', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'host': 'myhostname10', + 'id': '11', + 'interface': 'test_value_12', + 'ips-dos-status': 'enable', + 'ips-sensor': 'test_value_14', + 'ips-sensor-status': 'enable', + 'ipv6': 'enable', + 'logtraffic': 'all', + 'max-packet-count': '18', + 'non-ip': 'enable', + 'port': 'test_value_20', + 'protocol': 'test_value_21', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_23', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'vlan': 'test_value_26', + 'webfilter-profile': 'test_value_27', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'sniffer', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssh_host_key.py b/test/units/modules/network/fortios/test_fortios_firewall_ssh_host_key.py new file mode 100644 index 00000000000..f403cd8a964 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssh_host_key.py @@ -0,0 +1,269 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssh_host_key +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssh_host_key.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssh_host_key_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_host_key': { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public-key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + } + + set_method_mock.assert_called_with('firewall.ssh', 'host-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_host_key_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_host_key': { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public-key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + } + + set_method_mock.assert_called_with('firewall.ssh', 'host-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_host_key_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_host_key': { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'host-key', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_host_key_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_host_key': { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'host-key', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_host_key_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_host_key': { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public-key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + } + + set_method_mock.assert_called_with('firewall.ssh', 'host-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssh_host_key_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_host_key': { + 'random_attribute_not_valid': 'tag', + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public_key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_host_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'hostname': 'myhostname3', + 'ip': 'test_value_4', + 'name': 'default_name_5', + 'nid': '256', + 'port': '7', + 'public-key': 'test_value_8', + 'status': 'trusted', + 'type': 'RSA' + } + + set_method_mock.assert_called_with('firewall.ssh', 'host-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_ca.py b/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_ca.py new file mode 100644 index 00000000000..8105cf00310 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_ca.py @@ -0,0 +1,239 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssh_local_ca +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssh_local_ca.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssh_local_ca_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_ca': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-ca', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_local_ca_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_ca': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-ca', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_local_ca_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_local_ca': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'local-ca', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_local_ca_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_local_ca': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'local-ca', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_local_ca_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_ca': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-ca', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssh_local_ca_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_ca': { + 'random_attribute_not_valid': 'tag', + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_ca.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-ca', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_key.py b/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_key.py new file mode 100644 index 00000000000..6b7d03e477e --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssh_local_key.py @@ -0,0 +1,239 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssh_local_key +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssh_local_key.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssh_local_key_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_key': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_local_key_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_key': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_local_key_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_local_key': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'local-key', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_local_key_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssh_local_key': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall.ssh', 'local-key', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_local_key_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_key': { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssh_local_key_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_local_key': { + 'random_attribute_not_valid': 'tag', + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private_key': 'test_value_5', + 'public_key': 'test_value_6', + 'source': 'built-in' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_local_key.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'password': 'test_value_4', + 'private-key': 'test_value_5', + 'public-key': 'test_value_6', + 'source': 'built-in' + } + + set_method_mock.assert_called_with('firewall.ssh', 'local-key', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssh_setting.py b/test/units/modules/network/fortios/test_fortios_firewall_ssh_setting.py new file mode 100644 index 00000000000..e4b55f1c527 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssh_setting.py @@ -0,0 +1,215 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssh_setting +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssh_setting.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssh_setting_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_setting': { + 'caname': 'test_value_3', + 'host_trusted_checking': 'enable', + 'hostkey_dsa1024': 'myhostname5', + 'hostkey_ecdsa256': 'myhostname6', + 'hostkey_ecdsa384': 'myhostname7', + 'hostkey_ecdsa521': 'myhostname8', + 'hostkey_ed25519': 'myhostname9', + 'hostkey_rsa2048': 'myhostname10', + 'untrusted_caname': 'test_value_11' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_setting.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'caname': 'test_value_3', + 'host-trusted-checking': 'enable', + 'hostkey-dsa1024': 'myhostname5', + 'hostkey-ecdsa256': 'myhostname6', + 'hostkey-ecdsa384': 'myhostname7', + 'hostkey-ecdsa521': 'myhostname8', + 'hostkey-ed25519': 'myhostname9', + 'hostkey-rsa2048': 'myhostname10', + 'untrusted-caname': 'test_value_11' + } + + set_method_mock.assert_called_with('firewall.ssh', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssh_setting_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_setting': { + 'caname': 'test_value_3', + 'host_trusted_checking': 'enable', + 'hostkey_dsa1024': 'myhostname5', + 'hostkey_ecdsa256': 'myhostname6', + 'hostkey_ecdsa384': 'myhostname7', + 'hostkey_ecdsa521': 'myhostname8', + 'hostkey_ed25519': 'myhostname9', + 'hostkey_rsa2048': 'myhostname10', + 'untrusted_caname': 'test_value_11' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_setting.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'caname': 'test_value_3', + 'host-trusted-checking': 'enable', + 'hostkey-dsa1024': 'myhostname5', + 'hostkey-ecdsa256': 'myhostname6', + 'hostkey-ecdsa384': 'myhostname7', + 'hostkey-ecdsa521': 'myhostname8', + 'hostkey-ed25519': 'myhostname9', + 'hostkey-rsa2048': 'myhostname10', + 'untrusted-caname': 'test_value_11' + } + + set_method_mock.assert_called_with('firewall.ssh', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssh_setting_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_setting': { + 'caname': 'test_value_3', + 'host_trusted_checking': 'enable', + 'hostkey_dsa1024': 'myhostname5', + 'hostkey_ecdsa256': 'myhostname6', + 'hostkey_ecdsa384': 'myhostname7', + 'hostkey_ecdsa521': 'myhostname8', + 'hostkey_ed25519': 'myhostname9', + 'hostkey_rsa2048': 'myhostname10', + 'untrusted_caname': 'test_value_11' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_setting.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'caname': 'test_value_3', + 'host-trusted-checking': 'enable', + 'hostkey-dsa1024': 'myhostname5', + 'hostkey-ecdsa256': 'myhostname6', + 'hostkey-ecdsa384': 'myhostname7', + 'hostkey-ecdsa521': 'myhostname8', + 'hostkey-ed25519': 'myhostname9', + 'hostkey-rsa2048': 'myhostname10', + 'untrusted-caname': 'test_value_11' + } + + set_method_mock.assert_called_with('firewall.ssh', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssh_setting_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssh_setting': { + 'random_attribute_not_valid': 'tag', + 'caname': 'test_value_3', + 'host_trusted_checking': 'enable', + 'hostkey_dsa1024': 'myhostname5', + 'hostkey_ecdsa256': 'myhostname6', + 'hostkey_ecdsa384': 'myhostname7', + 'hostkey_ecdsa521': 'myhostname8', + 'hostkey_ed25519': 'myhostname9', + 'hostkey_rsa2048': 'myhostname10', + 'untrusted_caname': 'test_value_11' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssh_setting.fortios_firewall_ssh(input_data, fos_instance) + + expected_data = { + 'caname': 'test_value_3', + 'host-trusted-checking': 'enable', + 'hostkey-dsa1024': 'myhostname5', + 'hostkey-ecdsa256': 'myhostname6', + 'hostkey-ecdsa384': 'myhostname7', + 'hostkey-ecdsa521': 'myhostname8', + 'hostkey-ed25519': 'myhostname9', + 'hostkey-rsa2048': 'myhostname10', + 'untrusted-caname': 'test_value_11' + } + + set_method_mock.assert_called_with('firewall.ssh', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssl_server.py b/test/units/modules/network/fortios/test_fortios_firewall_ssl_server.py new file mode 100644 index 00000000000..6e6625e1778 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssl_server.py @@ -0,0 +1,329 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssl_server +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssl_server.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssl_server_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_server': { + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'add-header-x-forwarded-proto': 'enable', + 'ip': 'test_value_4', + 'mapped-port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl-algorithm': 'high', + 'ssl-cert': 'test_value_9', + 'ssl-client-renegotiation': 'allow', + 'ssl-dh-bits': '768', + 'ssl-max-version': 'tls-1.0', + 'ssl-min-version': 'tls-1.0', + 'ssl-mode': 'half', + 'ssl-send-empty-frags': 'enable', + 'url-rewrite': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'ssl-server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssl_server_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_server': { + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'add-header-x-forwarded-proto': 'enable', + 'ip': 'test_value_4', + 'mapped-port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl-algorithm': 'high', + 'ssl-cert': 'test_value_9', + 'ssl-client-renegotiation': 'allow', + 'ssl-dh-bits': '768', + 'ssl-max-version': 'tls-1.0', + 'ssl-min-version': 'tls-1.0', + 'ssl-mode': 'half', + 'ssl-send-empty-frags': 'enable', + 'url-rewrite': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'ssl-server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssl_server_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssl_server': { + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'ssl-server', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssl_server_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'firewall_ssl_server': { + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'ssl-server', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssl_server_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_server': { + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'add-header-x-forwarded-proto': 'enable', + 'ip': 'test_value_4', + 'mapped-port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl-algorithm': 'high', + 'ssl-cert': 'test_value_9', + 'ssl-client-renegotiation': 'allow', + 'ssl-dh-bits': '768', + 'ssl-max-version': 'tls-1.0', + 'ssl-min-version': 'tls-1.0', + 'ssl-mode': 'half', + 'ssl-send-empty-frags': 'enable', + 'url-rewrite': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'ssl-server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssl_server_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_server': { + 'random_attribute_not_valid': 'tag', + 'add_header_x_forwarded_proto': 'enable', + 'ip': 'test_value_4', + 'mapped_port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl_algorithm': 'high', + 'ssl_cert': 'test_value_9', + 'ssl_client_renegotiation': 'allow', + 'ssl_dh_bits': '768', + 'ssl_max_version': 'tls-1.0', + 'ssl_min_version': 'tls-1.0', + 'ssl_mode': 'half', + 'ssl_send_empty_frags': 'enable', + 'url_rewrite': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_server.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'add-header-x-forwarded-proto': 'enable', + 'ip': 'test_value_4', + 'mapped-port': '5', + 'name': 'default_name_6', + 'port': '7', + 'ssl-algorithm': 'high', + 'ssl-cert': 'test_value_9', + 'ssl-client-renegotiation': 'allow', + 'ssl-dh-bits': '768', + 'ssl-max-version': 'tls-1.0', + 'ssl-min-version': 'tls-1.0', + 'ssl-mode': 'half', + 'ssl-send-empty-frags': 'enable', + 'url-rewrite': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'ssl-server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssl_setting.py b/test/units/modules/network/fortios/test_fortios_firewall_ssl_setting.py new file mode 100644 index 00000000000..363d47768c2 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_ssl_setting.py @@ -0,0 +1,231 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_firewall_ssl_setting +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssl_setting.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_ssl_setting_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_setting': { + 'abbreviate_handshake': 'enable', + 'cert_cache_capacity': '4', + 'cert_cache_timeout': '5', + 'kxp_queue_threshold': '6', + 'no_matching_cipher_action': 'bypass', + 'proxy_connect_timeout': '8', + 'session_cache_capacity': '9', + 'session_cache_timeout': '10', + 'ssl_dh_bits': '768', + 'ssl_queue_threshold': '12', + 'ssl_send_empty_frags': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_setting.fortios_firewall_ssl(input_data, fos_instance) + + expected_data = { + 'abbreviate-handshake': 'enable', + 'cert-cache-capacity': '4', + 'cert-cache-timeout': '5', + 'kxp-queue-threshold': '6', + 'no-matching-cipher-action': 'bypass', + 'proxy-connect-timeout': '8', + 'session-cache-capacity': '9', + 'session-cache-timeout': '10', + 'ssl-dh-bits': '768', + 'ssl-queue-threshold': '12', + 'ssl-send-empty-frags': 'enable' + } + + set_method_mock.assert_called_with('firewall.ssl', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_firewall_ssl_setting_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_setting': { + 'abbreviate_handshake': 'enable', + 'cert_cache_capacity': '4', + 'cert_cache_timeout': '5', + 'kxp_queue_threshold': '6', + 'no_matching_cipher_action': 'bypass', + 'proxy_connect_timeout': '8', + 'session_cache_capacity': '9', + 'session_cache_timeout': '10', + 'ssl_dh_bits': '768', + 'ssl_queue_threshold': '12', + 'ssl_send_empty_frags': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_setting.fortios_firewall_ssl(input_data, fos_instance) + + expected_data = { + 'abbreviate-handshake': 'enable', + 'cert-cache-capacity': '4', + 'cert-cache-timeout': '5', + 'kxp-queue-threshold': '6', + 'no-matching-cipher-action': 'bypass', + 'proxy-connect-timeout': '8', + 'session-cache-capacity': '9', + 'session-cache-timeout': '10', + 'ssl-dh-bits': '768', + 'ssl-queue-threshold': '12', + 'ssl-send-empty-frags': 'enable' + } + + set_method_mock.assert_called_with('firewall.ssl', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_firewall_ssl_setting_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_setting': { + 'abbreviate_handshake': 'enable', + 'cert_cache_capacity': '4', + 'cert_cache_timeout': '5', + 'kxp_queue_threshold': '6', + 'no_matching_cipher_action': 'bypass', + 'proxy_connect_timeout': '8', + 'session_cache_capacity': '9', + 'session_cache_timeout': '10', + 'ssl_dh_bits': '768', + 'ssl_queue_threshold': '12', + 'ssl_send_empty_frags': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_setting.fortios_firewall_ssl(input_data, fos_instance) + + expected_data = { + 'abbreviate-handshake': 'enable', + 'cert-cache-capacity': '4', + 'cert-cache-timeout': '5', + 'kxp-queue-threshold': '6', + 'no-matching-cipher-action': 'bypass', + 'proxy-connect-timeout': '8', + 'session-cache-capacity': '9', + 'session-cache-timeout': '10', + 'ssl-dh-bits': '768', + 'ssl-queue-threshold': '12', + 'ssl-send-empty-frags': 'enable' + } + + set_method_mock.assert_called_with('firewall.ssl', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_firewall_ssl_setting_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'firewall_ssl_setting': { + 'random_attribute_not_valid': 'tag', + 'abbreviate_handshake': 'enable', + 'cert_cache_capacity': '4', + 'cert_cache_timeout': '5', + 'kxp_queue_threshold': '6', + 'no_matching_cipher_action': 'bypass', + 'proxy_connect_timeout': '8', + 'session_cache_capacity': '9', + 'session_cache_timeout': '10', + 'ssl_dh_bits': '768', + 'ssl_queue_threshold': '12', + 'ssl_send_empty_frags': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_ssl_setting.fortios_firewall_ssl(input_data, fos_instance) + + expected_data = { + 'abbreviate-handshake': 'enable', + 'cert-cache-capacity': '4', + 'cert-cache-timeout': '5', + 'kxp-queue-threshold': '6', + 'no-matching-cipher-action': 'bypass', + 'proxy-connect-timeout': '8', + 'session-cache-capacity': '9', + 'session-cache-timeout': '10', + 'ssl-dh-bits': '768', + 'ssl-queue-threshold': '12', + 'ssl-send-empty-frags': 'enable' + } + + set_method_mock.assert_called_with('firewall.ssl', 'setting', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200