From ca28ae3be548fe824ff03e27e39e8c612d4463b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Angel=20Mu=C3=B1oz=20Gonz=C3=A1lez?= Date: Fri, 16 Aug 2019 17:04:37 +0200 Subject: [PATCH] FortiOS modules for 2.9 - 2 (#60598) * FortiOS modules for 2.9 - 2 * Fix long lines and ignore.txt --- ...ortios_endpoint_control_forticlient_ems.py | 210 +++-- ...t_control_forticlient_registration_sync.py | 161 ++-- .../fortios_endpoint_control_profile.py | 751 +++++++++++------- .../fortios_endpoint_control_settings.py | 227 ++++-- .../fortios_extender_controller_extender.py | 375 +++++---- .../fortios/fortios_firewall_DoS_policy.py | 176 ++-- .../fortios/fortios_firewall_DoS_policy6.py | 176 ++-- .../fortios/fortios_firewall_address.py | 269 ++++--- .../fortios/fortios_firewall_address6.py | 221 ++++-- .../fortios_firewall_address6_template.py | 175 ++-- .../fortios/fortios_firewall_addrgrp.py | 177 +++-- .../fortios/fortios_firewall_addrgrp6.py | 160 ++-- .../fortios/fortios_firewall_auth_portal.py | 146 ++-- .../fortios_firewall_central_snat_map.py | 197 +++-- .../fortios_firewall_dnstranslation.py | 148 ++-- .../fortios_firewall_identity_based_route.py | 152 ++-- .../fortios_firewall_interface_policy.py | 271 ++++--- .../fortios_firewall_interface_policy6.py | 271 ++++--- .../fortios_firewall_internet_service.py | 186 +++-- ...ortios_firewall_internet_service_custom.py | 216 +++-- test/sanity/ignore.txt | 35 - ...ortios_endpoint_control_forticlient_ems.py | 289 +++++++ ...t_control_forticlient_registration_sync.py | 209 +++++ .../test_fortios_endpoint_control_profile.py | 229 ++++++ .../test_fortios_endpoint_control_settings.py | 255 ++++++ ...st_fortios_extender_controller_extender.py | 559 +++++++++++++ .../test_fortios_firewall_DoS_policy.py | 219 +++++ .../test_fortios_firewall_DoS_policy6.py | 219 +++++ .../fortios/test_fortios_firewall_address.py | 439 ++++++++++ .../fortios/test_fortios_firewall_address6.py | 349 ++++++++ ...test_fortios_firewall_address6_template.py | 219 +++++ .../fortios/test_fortios_firewall_addrgrp.py | 249 ++++++ .../fortios/test_fortios_firewall_addrgrp6.py | 239 ++++++ .../test_fortios_firewall_auth_portal.py | 159 ++++ .../test_fortios_firewall_central_snat_map.py | 259 ++++++ .../test_fortios_firewall_dnstranslation.py | 229 ++++++ ...t_fortios_firewall_identity_based_route.py | 219 +++++ .../test_fortios_firewall_interface_policy.py | 399 ++++++++++ ...test_fortios_firewall_interface_policy6.py | 399 ++++++++++ .../test_fortios_firewall_internet_service.py | 269 +++++++ ...ortios_firewall_internet_service_custom.py | 219 +++++ 41 files changed, 8625 insertions(+), 1701 deletions(-) create mode 100644 test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_ems.py create mode 100644 test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_registration_sync.py create mode 100644 test/units/modules/network/fortios/test_fortios_endpoint_control_profile.py create mode 100644 test/units/modules/network/fortios/test_fortios_endpoint_control_settings.py create mode 100644 test/units/modules/network/fortios/test_fortios_extender_controller_extender.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_DoS_policy.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_DoS_policy6.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_address.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_address6.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_address6_template.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_addrgrp.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_addrgrp6.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_auth_portal.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_central_snat_map.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_dnstranslation.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_identity_based_route.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_interface_policy.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_interface_policy6.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_internet_service.py create mode 100644 test/units/modules/network/fortios/test_fortios_firewall_internet_service_custom.py diff --git a/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py b/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py index ed82fdd0071..c7947912a4e 100644 --- a/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py +++ b/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.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_endpoint_control_forticlient_ems short_description: Configure FortiClient Enterprise Management Server (EMS) entries in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure endpoint_control feature and forticlient_ems 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 device by allowing the + user to set and modify endpoint_control feature and forticlient_ems 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,77 +41,99 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 endpoint_control_forticlient_ems: description: - Configure FortiClient Enterprise Management Server (EMS) entries. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent address: description: - Firewall address name. Source firewall.address.name. - admin-password: + type: str + admin_password: description: - FortiClient EMS admin password. - admin-type: + type: str + admin_type: description: - FortiClient EMS admin type. + type: str choices: - Windows - LDAP - admin-username: + admin_username: description: - FortiClient EMS admin username. - https-port: + type: str + https_port: description: - "FortiClient EMS HTTPS access port number. (1 - 65535, default: 443)." - listen-port: + type: int + listen_port: description: - "FortiClient EMS telemetry listen port number. (1 - 65535, default: 8013)." + type: int name: description: - FortiClient Enterprise Management Server (EMS) name. required: true - rest-api-auth: + type: str + rest_api_auth: description: - FortiClient EMS REST API authentication. + type: str choices: - disable - userpass - serial-number: + serial_number: description: - FortiClient EMS Serial Number. - upload-port: + type: str + upload_port: description: - "FortiClient EMS telemetry upload port number. (1 - 65535, default: 8014)." + type: int ''' EXAMPLES = ''' @@ -124,6 +143,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiClient Enterprise Management Server (EMS) entries. fortios_endpoint_control_forticlient_ems: @@ -131,18 +151,19 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" endpoint_control_forticlient_ems: - state: "present" address: " (source firewall.address.name)" - admin-password: "" - admin-type: "Windows" - admin-username: "" - https-port: "7" - listen-port: "8" + admin_password: "" + admin_type: "Windows" + admin_username: "" + https_port: "7" + listen_port: "8" name: "default_name_9" - rest-api-auth: "disable" - serial-number: "" - upload-port: "12" + rest_api_auth: "disable" + serial_number: "" + upload_port: "12" ''' RETURN = ''' @@ -205,14 +226,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -220,14 +243,14 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_endpoint_control_forticlient_ems_data(json): - option_list = ['address', 'admin-password', 'admin-type', - 'admin-username', 'https-port', 'listen-port', - 'name', 'rest-api-auth', 'serial-number', - 'upload-port'] + option_list = ['address', 'admin_password', 'admin_type', + 'admin_username', 'https_port', 'listen_port', + 'name', 'rest_api_auth', 'serial_number', + 'upload_port'] dictionary = {} for attribute in option_list: @@ -237,60 +260,78 @@ def filter_endpoint_control_forticlient_ems_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 endpoint_control_forticlient_ems(data, fos): vdom = data['vdom'] + state = data['state'] endpoint_control_forticlient_ems_data = data['endpoint_control_forticlient_ems'] - filtered_data = filter_endpoint_control_forticlient_ems_data(endpoint_control_forticlient_ems_data) - if endpoint_control_forticlient_ems_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_endpoint_control_forticlient_ems_data(endpoint_control_forticlient_ems_data)) + + if state == "present": return fos.set('endpoint-control', 'forticlient-ems', data=filtered_data, vdom=vdom) - elif endpoint_control_forticlient_ems_data['state'] == "absent": + elif state == "absent": return fos.delete('endpoint-control', 'forticlient-ems', 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_endpoint_control(data, fos): - login(data) - methodlist = ['endpoint_control_forticlient_ems'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['endpoint_control_forticlient_ems']: + resp = endpoint_control_forticlient_ems(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "endpoint_control_forticlient_ems": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "address": {"required": False, "type": "str"}, - "admin-password": {"required": False, "type": "str"}, - "admin-type": {"required": False, "type": "str", + "admin_password": {"required": False, "type": "str"}, + "admin_type": {"required": False, "type": "str", "choices": ["Windows", "LDAP"]}, - "admin-username": {"required": False, "type": "str"}, - "https-port": {"required": False, "type": "int"}, - "listen-port": {"required": False, "type": "int"}, + "admin_username": {"required": False, "type": "str"}, + "https_port": {"required": False, "type": "int"}, + "listen_port": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"}, - "rest-api-auth": {"required": False, "type": "str", + "rest_api_auth": {"required": False, "type": "str", "choices": ["disable", "userpass"]}, - "serial-number": {"required": False, "type": "str"}, - "upload-port": {"required": False, "type": "int"} + "serial_number": {"required": False, "type": "str"}, + "upload_port": {"required": False, "type": "int"} } } @@ -298,15 +339,30 @@ 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 = '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_endpoint_control(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_endpoint_control(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_endpoint_control(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_endpoint_control_forticlient_registration_sync.py b/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py index b14a0ed60c3..7fbad5f40a4 100644 --- a/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py +++ b/lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.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_endpoint_control_forticlient_registration_sync short_description: Configure FortiClient registration synchronization settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure endpoint_control feature and forticlient_registration_sync 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 device by allowing the + user to set and modify endpoint_control feature and forticlient_registration_sync 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,60 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 endpoint_control_forticlient_registration_sync: description: - Configure FortiClient registration synchronization settings. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - peer-ip: + peer_ip: description: - IP address of the peer FortiGate for endpoint license synchronization. - peer-name: + type: str + peer_name: description: - Peer name. - required: true + type: str ''' EXAMPLES = ''' @@ -94,6 +104,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiClient registration synchronization settings. fortios_endpoint_control_forticlient_registration_sync: @@ -101,10 +112,11 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" endpoint_control_forticlient_registration_sync: - state: "present" - peer-ip: "" - peer-name: "" + peer_ip: "" + peer_name: "" ''' RETURN = ''' @@ -167,14 +179,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']: @@ -182,11 +196,11 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_endpoint_control_forticlient_registration_sync_data(json): - option_list = ['peer-ip', 'peer-name'] + option_list = ['peer_ip', 'peer_name'] dictionary = {} for attribute in option_list: @@ -196,50 +210,68 @@ def filter_endpoint_control_forticlient_registration_sync_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 endpoint_control_forticlient_registration_sync(data, fos): vdom = data['vdom'] + state = data['state'] endpoint_control_forticlient_registration_sync_data = data['endpoint_control_forticlient_registration_sync'] - filtered_data = filter_endpoint_control_forticlient_registration_sync_data(endpoint_control_forticlient_registration_sync_data) - if endpoint_control_forticlient_registration_sync_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_endpoint_control_forticlient_registration_sync_data(endpoint_control_forticlient_registration_sync_data)) + + if state == "present": return fos.set('endpoint-control', 'forticlient-registration-sync', data=filtered_data, vdom=vdom) - elif endpoint_control_forticlient_registration_sync_data['state'] == "absent": + elif state == "absent": return fos.delete('endpoint-control', 'forticlient-registration-sync', mkey=filtered_data['peer-name'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_endpoint_control(data, fos): - login(data) - methodlist = ['endpoint_control_forticlient_registration_sync'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['endpoint_control_forticlient_registration_sync']: + resp = endpoint_control_forticlient_registration_sync(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "endpoint_control_forticlient_registration_sync": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "peer-ip": {"required": False, "type": "str"}, - "peer-name": {"required": True, "type": "str"} + "peer_ip": {"required": False, "type": "str"}, + "peer_name": {"required": False, "type": "str"} } } @@ -247,15 +279,30 @@ 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 = '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_endpoint_control(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_endpoint_control(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_endpoint_control(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_endpoint_control_profile.py b/lib/ansible/modules/network/fortios/fortios_endpoint_control_profile.py index bcaaefafbdd..2ea9c150c38 100644 --- a/lib/ansible/modules/network/fortios/fortios_endpoint_control_profile.py +++ b/lib/ansible/modules/network/fortios/fortios_endpoint_control_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_endpoint_control_profile short_description: Configure FortiClient endpoint control profiles in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure endpoint_control feature and 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 device by allowing the + user to set and modify endpoint_control feature and 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,83 +41,105 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 endpoint_control_profile: description: - Configure FortiClient endpoint control profiles. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent description: description: - Description. - device-groups: + type: str + device_groups: description: - Device groups. + type: list suboptions: name: description: - Device group object from available options. Source user.device-group.name user.device-category.name. required: true - forticlient-android-settings: + type: str + forticlient_android_settings: description: - FortiClient settings for Android platform. + type: dict suboptions: - disable-wf-when-protected: + disable_wf_when_protected: description: - Enable/disable FortiClient web category filtering when protected by FortiGate. + type: str choices: - enable - disable - forticlient-advanced-vpn: + forticlient_advanced_vpn: description: - Enable/disable advanced FortiClient VPN configuration. + type: str choices: - enable - disable - forticlient-advanced-vpn-buffer: + forticlient_advanced_vpn_buffer: description: - Advanced FortiClient VPN configuration. - forticlient-vpn-provisioning: + type: str + forticlient_vpn_provisioning: description: - Enable/disable FortiClient VPN provisioning. + type: str choices: - enable - disable - forticlient-vpn-settings: + forticlient_vpn_settings: description: - FortiClient VPN settings. + type: list suboptions: - auth-method: + auth_method: description: - Authentication method. + type: str choices: - psk - certificate @@ -128,53 +147,65 @@ options: description: - VPN name. required: true - preshared-key: + type: str + preshared_key: description: - Pre-shared secret for PSK authentication. - remote-gw: + type: str + remote_gw: description: - IP address or FQDN of the remote VPN gateway. - sslvpn-access-port: + type: str + sslvpn_access_port: description: - SSL VPN access port (1 - 65535). - sslvpn-require-certificate: + type: int + sslvpn_require_certificate: description: - Enable/disable requiring SSL VPN client certificate. + type: str choices: - enable - disable type: description: - VPN type (IPsec or SSL VPN). + type: str choices: - ipsec - ssl - forticlient-wf: + forticlient_wf: description: - Enable/disable FortiClient web filtering. + type: str choices: - enable - disable - forticlient-wf-profile: + forticlient_wf_profile: description: - The FortiClient web filter profile to apply. Source webfilter.profile.name. - forticlient-ios-settings: + type: str + forticlient_ios_settings: description: - FortiClient settings for iOS platform. + type: dict suboptions: - client-vpn-provisioning: + client_vpn_provisioning: description: - FortiClient VPN provisioning. + type: str choices: - enable - disable - client-vpn-settings: + client_vpn_settings: description: - FortiClient VPN settings. + type: list suboptions: - auth-method: + auth_method: description: - Authentication method. + type: str choices: - psk - certificate @@ -182,153 +213,187 @@ options: description: - VPN name. required: true - preshared-key: + type: str + preshared_key: description: - Pre-shared secret for PSK authentication. - remote-gw: + type: str + remote_gw: description: - IP address or FQDN of the remote VPN gateway. - sslvpn-access-port: + type: str + sslvpn_access_port: description: - SSL VPN access port (1 - 65535). - sslvpn-require-certificate: + type: int + sslvpn_require_certificate: description: - Enable/disable requiring SSL VPN client certificate. + type: str choices: - enable - disable type: description: - VPN type (IPsec or SSL VPN). + type: str choices: - ipsec - ssl - vpn-configuration-content: + vpn_configuration_content: description: - Content of VPN configuration. - vpn-configuration-name: + type: str + vpn_configuration_name: description: - Name of VPN configuration. - configuration-content: + type: str + configuration_content: description: - Content of configuration profile. - configuration-name: + type: str + configuration_name: description: - Name of configuration profile. - disable-wf-when-protected: + type: str + disable_wf_when_protected: description: - Enable/disable FortiClient web category filtering when protected by FortiGate. + type: str choices: - enable - disable - distribute-configuration-profile: + distribute_configuration_profile: description: - Enable/disable configuration profile (.mobileconfig file) distribution. + type: str choices: - enable - disable - forticlient-wf: + forticlient_wf: description: - Enable/disable FortiClient web filtering. + type: str choices: - enable - disable - forticlient-wf-profile: + forticlient_wf_profile: description: - The FortiClient web filter profile to apply. Source webfilter.profile.name. - forticlient-winmac-settings: + type: str + forticlient_winmac_settings: description: - FortiClient settings for Windows/Mac platform. + type: dict suboptions: - av-realtime-protection: + av_realtime_protection: description: - Enable/disable FortiClient AntiVirus real-time protection. + type: str choices: - enable - disable - av-signature-up-to-date: + av_signature_up_to_date: description: - Enable/disable FortiClient AV signature updates. + type: str choices: - enable - disable - forticlient-application-firewall: + forticlient_application_firewall: description: - Enable/disable the FortiClient application firewall. + type: str choices: - enable - disable - forticlient-application-firewall-list: + forticlient_application_firewall_list: description: - FortiClient application firewall rule list. Source application.list.name. - forticlient-av: + type: str + forticlient_av: description: - Enable/disable FortiClient AntiVirus scanning. + type: str choices: - enable - disable - forticlient-ems-compliance: + forticlient_ems_compliance: description: - Enable/disable FortiClient Enterprise Management Server (EMS) compliance. + type: str choices: - enable - disable - forticlient-ems-compliance-action: + forticlient_ems_compliance_action: description: - FortiClient EMS compliance action. + type: str choices: - block - warning - forticlient-ems-entries: + forticlient_ems_entries: description: - FortiClient EMS entries. + type: list suboptions: name: description: - FortiClient EMS name. Source endpoint-control.forticlient-ems.name. required: true - forticlient-linux-ver: + type: str + forticlient_linux_ver: description: - Minimum FortiClient Linux version. - forticlient-log-upload: + type: str + forticlient_log_upload: description: - Enable/disable uploading FortiClient logs. + type: str choices: - enable - disable - forticlient-log-upload-level: + forticlient_log_upload_level: description: - Select the FortiClient logs to upload. + type: str choices: - traffic - vulnerability - event - forticlient-log-upload-server: + forticlient_log_upload_server: description: - IP address or FQDN of the server to which to upload FortiClient logs. - forticlient-mac-ver: + type: str + forticlient_mac_ver: description: - Minimum FortiClient Mac OS version. - forticlient-minimum-software-version: + type: str + forticlient_minimum_software_version: description: - Enable/disable requiring clients to run FortiClient with a minimum software version number. + type: str choices: - enable - disable - forticlient-operating-system: + forticlient_operating_system: description: - FortiClient operating system. + type: list suboptions: id: description: - Operating system entry ID. required: true - os-name: + type: int + os_name: description: - "Customize operating system name or Mac OS format:x.x.x" - os-type: + type: str + os_type: description: - Operating system type. + type: str choices: - custom - mac-os @@ -352,56 +417,70 @@ options: - centos-linux - redhat-linux - fedora-linux - forticlient-own-file: + forticlient_own_file: description: - Checking the path and filename of the FortiClient application. + type: list suboptions: file: description: - File path and name. + type: str id: description: - File ID. required: true - forticlient-registration-compliance-action: + type: int + forticlient_registration_compliance_action: description: - FortiClient registration compliance action. + type: str choices: - block - warning - forticlient-registry-entry: + forticlient_registry_entry: description: - FortiClient registry entry. + type: list suboptions: id: description: - Registry entry ID. required: true - registry-entry: + type: int + registry_entry: description: - Registry entry. - forticlient-running-app: + type: str + forticlient_running_app: description: - Use FortiClient to verify if the listed applications are running on the client. + type: list suboptions: - app-name: + app_name: description: - Application name. - app-sha256-signature: + type: str + app_sha256_signature: description: - App's SHA256 signature. - app-sha256-signature2: + type: str + app_sha256_signature2: description: - App's SHA256 Signature. - app-sha256-signature3: + type: str + app_sha256_signature3: description: - App's SHA256 Signature. - app-sha256-signature4: + type: str + app_sha256_signature4: description: - App's SHA256 Signature. - application-check-rule: + type: str + application_check_rule: description: - Application check rule. + type: str choices: - present - absent @@ -409,138 +488,167 @@ options: description: - Application ID. required: true - process-name: + type: int + process_name: description: - Process name. - process-name2: + type: str + process_name2: description: - Process name. - process-name3: + type: str + process_name3: description: - Process name. - process-name4: + type: str + process_name4: description: - Process name. - forticlient-security-posture: + type: str + forticlient_security_posture: description: - Enable/disable FortiClient security posture check options. + type: str choices: - enable - disable - forticlient-security-posture-compliance-action: + forticlient_security_posture_compliance_action: description: - FortiClient security posture compliance action. + type: str choices: - block - warning - forticlient-system-compliance: + forticlient_system_compliance: description: - Enable/disable enforcement of FortiClient system compliance. + type: str choices: - enable - disable - forticlient-system-compliance-action: + forticlient_system_compliance_action: description: - Block or warn clients not compliant with FortiClient requirements. + type: str choices: - block - warning - forticlient-vuln-scan: + forticlient_vuln_scan: description: - Enable/disable FortiClient vulnerability scanning. + type: str choices: - enable - disable - forticlient-vuln-scan-compliance-action: + forticlient_vuln_scan_compliance_action: description: - FortiClient vulnerability compliance action. + type: str choices: - block - warning - forticlient-vuln-scan-enforce: + forticlient_vuln_scan_enforce: description: - Configure the level of the vulnerability found that causes a FortiClient vulnerability compliance action. + type: str choices: - critical - high - medium - low - info - forticlient-vuln-scan-enforce-grace: + forticlient_vuln_scan_enforce_grace: description: - FortiClient vulnerability scan enforcement grace period (0 - 30 days, default = 1). - forticlient-vuln-scan-exempt: + type: int + forticlient_vuln_scan_exempt: description: - Enable/disable compliance exemption for vulnerabilities that cannot be patched automatically. + type: str choices: - enable - disable - forticlient-wf: + forticlient_wf: description: - Enable/disable FortiClient web filtering. + type: str choices: - enable - disable - forticlient-wf-profile: + forticlient_wf_profile: description: - The FortiClient web filter profile to apply. Source webfilter.profile.name. - forticlient-win-ver: + type: str + forticlient_win_ver: description: - Minimum FortiClient Windows version. - os-av-software-installed: + type: str + os_av_software_installed: description: - Enable/disable checking for OS recognized AntiVirus software. + type: str choices: - enable - disable - sandbox-address: + sandbox_address: description: - FortiSandbox address. - sandbox-analysis: + type: str + sandbox_analysis: description: - Enable/disable sending files to FortiSandbox for analysis. + type: str choices: - enable - disable - on-net-addr: + on_net_addr: description: - Addresses for on-net detection. + type: list suboptions: name: description: - Address object from available options. Source firewall.address.name firewall.addrgrp.name. required: true - profile-name: + type: str + profile_name: description: - Profile name. - required: true - replacemsg-override-group: + type: str + replacemsg_override_group: description: - Select an endpoint control replacement message override group from available options. Source system.replacemsg-group.name. - src-addr: + type: str + src_addr: description: - Source addresses. + type: list suboptions: name: description: - Address object from available options. Source firewall.address.name firewall.addrgrp.name. required: true - user-groups: + type: str + user_groups: description: - User groups. + type: list suboptions: name: description: - User group name. Source user.group.name. required: true + type: str users: description: - Users. + type: list suboptions: name: description: - User name. Source user.local.name. required: true + type: str ''' EXAMPLES = ''' @@ -550,6 +658,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiClient endpoint control profiles. fortios_endpoint_control_profile: @@ -557,115 +666,116 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" endpoint_control_profile: - state: "present" description: "" - device-groups: + device_groups: - name: "default_name_5 (source user.device-group.name user.device-category.name)" - forticlient-android-settings: - disable-wf-when-protected: "enable" - forticlient-advanced-vpn: "enable" - forticlient-advanced-vpn-buffer: "" - forticlient-vpn-provisioning: "enable" - forticlient-vpn-settings: + forticlient_android_settings: + disable_wf_when_protected: "enable" + forticlient_advanced_vpn: "enable" + forticlient_advanced_vpn_buffer: "" + forticlient_vpn_provisioning: "enable" + forticlient_vpn_settings: - - auth-method: "psk" + auth_method: "psk" name: "default_name_13" - preshared-key: "" - remote-gw: "" - sslvpn-access-port: "16" - sslvpn-require-certificate: "enable" + preshared_key: "" + remote_gw: "" + sslvpn_access_port: "16" + sslvpn_require_certificate: "enable" type: "ipsec" - forticlient-wf: "enable" - forticlient-wf-profile: " (source webfilter.profile.name)" - forticlient-ios-settings: - client-vpn-provisioning: "enable" - client-vpn-settings: + forticlient_wf: "enable" + forticlient_wf_profile: " (source webfilter.profile.name)" + forticlient_ios_settings: + client_vpn_provisioning: "enable" + client_vpn_settings: - - auth-method: "psk" + auth_method: "psk" name: "default_name_25" - preshared-key: "" - remote-gw: "" - sslvpn-access-port: "28" - sslvpn-require-certificate: "enable" + preshared_key: "" + remote_gw: "" + sslvpn_access_port: "28" + sslvpn_require_certificate: "enable" type: "ipsec" - vpn-configuration-content: "" - vpn-configuration-name: "" - configuration-content: "" - configuration-name: "" - disable-wf-when-protected: "enable" - distribute-configuration-profile: "enable" - forticlient-wf: "enable" - forticlient-wf-profile: " (source webfilter.profile.name)" - forticlient-winmac-settings: - av-realtime-protection: "enable" - av-signature-up-to-date: "enable" - forticlient-application-firewall: "enable" - forticlient-application-firewall-list: " (source application.list.name)" - forticlient-av: "enable" - forticlient-ems-compliance: "enable" - forticlient-ems-compliance-action: "block" - forticlient-ems-entries: + vpn_configuration_content: "" + vpn_configuration_name: "" + configuration_content: "" + configuration_name: "" + disable_wf_when_protected: "enable" + distribute_configuration_profile: "enable" + forticlient_wf: "enable" + forticlient_wf_profile: " (source webfilter.profile.name)" + forticlient_winmac_settings: + av_realtime_protection: "enable" + av_signature_up_to_date: "enable" + forticlient_application_firewall: "enable" + forticlient_application_firewall_list: " (source application.list.name)" + forticlient_av: "enable" + forticlient_ems_compliance: "enable" + forticlient_ems_compliance_action: "block" + forticlient_ems_entries: - name: "default_name_48 (source endpoint-control.forticlient-ems.name)" - forticlient-linux-ver: "" - forticlient-log-upload: "enable" - forticlient-log-upload-level: "traffic" - forticlient-log-upload-server: "" - forticlient-mac-ver: "" - forticlient-minimum-software-version: "enable" - forticlient-operating-system: + forticlient_linux_ver: "" + forticlient_log_upload: "enable" + forticlient_log_upload_level: "traffic" + forticlient_log_upload_server: "" + forticlient_mac_ver: "" + forticlient_minimum_software_version: "enable" + forticlient_operating_system: - id: "56" - os-name: "" - os-type: "custom" - forticlient-own-file: + os_name: "" + os_type: "custom" + forticlient_own_file: - file: "" id: "61" - forticlient-registration-compliance-action: "block" - forticlient-registry-entry: + forticlient_registration_compliance_action: "block" + forticlient_registry_entry: - id: "64" - registry-entry: "" - forticlient-running-app: + registry_entry: "" + forticlient_running_app: - - app-name: "" - app-sha256-signature: "" - app-sha256-signature2: "" - app-sha256-signature3: "" - app-sha256-signature4: "" - application-check-rule: "present" + app_name: "" + app_sha256_signature: "" + app_sha256_signature2: "" + app_sha256_signature3: "" + app_sha256_signature4: "" + application_check_rule: "present" id: "73" - process-name: "" - process-name2: "" - process-name3: "" - process-name4: "" - forticlient-security-posture: "enable" - forticlient-security-posture-compliance-action: "block" - forticlient-system-compliance: "enable" - forticlient-system-compliance-action: "block" - forticlient-vuln-scan: "enable" - forticlient-vuln-scan-compliance-action: "block" - forticlient-vuln-scan-enforce: "critical" - forticlient-vuln-scan-enforce-grace: "85" - forticlient-vuln-scan-exempt: "enable" - forticlient-wf: "enable" - forticlient-wf-profile: " (source webfilter.profile.name)" - forticlient-win-ver: "" - os-av-software-installed: "enable" - sandbox-address: "" - sandbox-analysis: "enable" - on-net-addr: + process_name: "" + process_name2: "" + process_name3: "" + process_name4: "" + forticlient_security_posture: "enable" + forticlient_security_posture_compliance_action: "block" + forticlient_system_compliance: "enable" + forticlient_system_compliance_action: "block" + forticlient_vuln_scan: "enable" + forticlient_vuln_scan_compliance_action: "block" + forticlient_vuln_scan_enforce: "critical" + forticlient_vuln_scan_enforce_grace: "85" + forticlient_vuln_scan_exempt: "enable" + forticlient_wf: "enable" + forticlient_wf_profile: " (source webfilter.profile.name)" + forticlient_win_ver: "" + os_av_software_installed: "enable" + sandbox_address: "" + sandbox_analysis: "enable" + on_net_addr: - name: "default_name_94 (source firewall.address.name firewall.addrgrp.name)" - profile-name: "" - replacemsg-override-group: " (source system.replacemsg-group.name)" - src-addr: + profile_name: "" + replacemsg_override_group: " (source system.replacemsg-group.name)" + src_addr: - name: "default_name_98 (source firewall.address.name firewall.addrgrp.name)" - user-groups: + user_groups: - name: "default_name_100 (source user.group.name)" users: @@ -733,14 +843,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']: @@ -748,14 +860,14 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_endpoint_control_profile_data(json): - option_list = ['description', 'device-groups', 'forticlient-android-settings', - 'forticlient-ios-settings', 'forticlient-winmac-settings', 'on-net-addr', - 'profile-name', 'replacemsg-override-group', 'src-addr', - 'user-groups', 'users'] + option_list = ['description', 'device_groups', 'forticlient_android_settings', + 'forticlient_ios_settings', 'forticlient_winmac_settings', 'on_net_addr', + 'profile_name', 'replacemsg_override_group', 'src_addr', + 'user_groups', 'users'] dictionary = {} for attribute in option_list: @@ -765,141 +877,159 @@ def filter_endpoint_control_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 endpoint_control_profile(data, fos): vdom = data['vdom'] + state = data['state'] endpoint_control_profile_data = data['endpoint_control_profile'] - filtered_data = filter_endpoint_control_profile_data(endpoint_control_profile_data) - if endpoint_control_profile_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_endpoint_control_profile_data(endpoint_control_profile_data)) + + if state == "present": return fos.set('endpoint-control', 'profile', data=filtered_data, vdom=vdom) - elif endpoint_control_profile_data['state'] == "absent": + elif state == "absent": return fos.delete('endpoint-control', '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_endpoint_control(data, fos): - login(data) - methodlist = ['endpoint_control_profile'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['endpoint_control_profile']: + resp = endpoint_control_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "endpoint_control_profile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "description": {"required": False, "type": "str"}, - "device-groups": {"required": False, "type": "list", + "device_groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "forticlient-android-settings": {"required": False, "type": "dict", + "forticlient_android_settings": {"required": False, "type": "dict", "options": { - "disable-wf-when-protected": {"required": False, "type": "str", + "disable_wf_when_protected": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-advanced-vpn": {"required": False, "type": "str", + "forticlient_advanced_vpn": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-advanced-vpn-buffer": {"required": False, "type": "str"}, - "forticlient-vpn-provisioning": {"required": False, "type": "str", + "forticlient_advanced_vpn_buffer": {"required": False, "type": "str"}, + "forticlient_vpn_provisioning": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-vpn-settings": {"required": False, "type": "list", + "forticlient_vpn_settings": {"required": False, "type": "list", "options": { - "auth-method": {"required": False, "type": "str", + "auth_method": {"required": False, "type": "str", "choices": ["psk", "certificate"]}, "name": {"required": True, "type": "str"}, - "preshared-key": {"required": False, "type": "str"}, - "remote-gw": {"required": False, "type": "str"}, - "sslvpn-access-port": {"required": False, "type": "int"}, - "sslvpn-require-certificate": {"required": False, "type": "str", + "preshared_key": {"required": False, "type": "str"}, + "remote_gw": {"required": False, "type": "str"}, + "sslvpn_access_port": {"required": False, "type": "int"}, + "sslvpn_require_certificate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "type": {"required": False, "type": "str", "choices": ["ipsec", "ssl"]} }}, - "forticlient-wf": {"required": False, "type": "str", + "forticlient_wf": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-wf-profile": {"required": False, "type": "str"} + "forticlient_wf_profile": {"required": False, "type": "str"} }}, - "forticlient-ios-settings": {"required": False, "type": "dict", + "forticlient_ios_settings": {"required": False, "type": "dict", "options": { - "client-vpn-provisioning": {"required": False, "type": "str", + "client_vpn_provisioning": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "client-vpn-settings": {"required": False, "type": "list", + "client_vpn_settings": {"required": False, "type": "list", "options": { - "auth-method": {"required": False, "type": "str", + "auth_method": {"required": False, "type": "str", "choices": ["psk", "certificate"]}, "name": {"required": True, "type": "str"}, - "preshared-key": {"required": False, "type": "str"}, - "remote-gw": {"required": False, "type": "str"}, - "sslvpn-access-port": {"required": False, "type": "int"}, - "sslvpn-require-certificate": {"required": False, "type": "str", + "preshared_key": {"required": False, "type": "str"}, + "remote_gw": {"required": False, "type": "str"}, + "sslvpn_access_port": {"required": False, "type": "int"}, + "sslvpn_require_certificate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "type": {"required": False, "type": "str", "choices": ["ipsec", "ssl"]}, - "vpn-configuration-content": {"required": False, "type": "str"}, - "vpn-configuration-name": {"required": False, "type": "str"} + "vpn_configuration_content": {"required": False, "type": "str"}, + "vpn_configuration_name": {"required": False, "type": "str"} }}, - "configuration-content": {"required": False, "type": "str"}, - "configuration-name": {"required": False, "type": "str"}, - "disable-wf-when-protected": {"required": False, "type": "str", + "configuration_content": {"required": False, "type": "str"}, + "configuration_name": {"required": False, "type": "str"}, + "disable_wf_when_protected": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "distribute-configuration-profile": {"required": False, "type": "str", + "distribute_configuration_profile": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-wf": {"required": False, "type": "str", + "forticlient_wf": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-wf-profile": {"required": False, "type": "str"} + "forticlient_wf_profile": {"required": False, "type": "str"} }}, - "forticlient-winmac-settings": {"required": False, "type": "dict", + "forticlient_winmac_settings": {"required": False, "type": "dict", "options": { - "av-realtime-protection": {"required": False, "type": "str", + "av_realtime_protection": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "av-signature-up-to-date": {"required": False, "type": "str", + "av_signature_up_to_date": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-application-firewall": {"required": False, "type": "str", + "forticlient_application_firewall": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-application-firewall-list": {"required": False, "type": "str"}, - "forticlient-av": {"required": False, "type": "str", + "forticlient_application_firewall_list": {"required": False, "type": "str"}, + "forticlient_av": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-ems-compliance": {"required": False, "type": "str", + "forticlient_ems_compliance": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-ems-compliance-action": {"required": False, "type": "str", + "forticlient_ems_compliance_action": {"required": False, "type": "str", "choices": ["block", "warning"]}, - "forticlient-ems-entries": {"required": False, "type": "list", + "forticlient_ems_entries": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "forticlient-linux-ver": {"required": False, "type": "str"}, - "forticlient-log-upload": {"required": False, "type": "str", + "forticlient_linux_ver": {"required": False, "type": "str"}, + "forticlient_log_upload": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-log-upload-level": {"required": False, "type": "str", + "forticlient_log_upload_level": {"required": False, "type": "str", "choices": ["traffic", "vulnerability", "event"]}, - "forticlient-log-upload-server": {"required": False, "type": "str"}, - "forticlient-mac-ver": {"required": False, "type": "str"}, - "forticlient-minimum-software-version": {"required": False, "type": "str", + "forticlient_log_upload_server": {"required": False, "type": "str"}, + "forticlient_mac_ver": {"required": False, "type": "str"}, + "forticlient_minimum_software_version": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-operating-system": {"required": False, "type": "list", + "forticlient_operating_system": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "os-name": {"required": False, "type": "str"}, - "os-type": {"required": False, "type": "str", + "os_name": {"required": False, "type": "str"}, + "os_type": {"required": False, "type": "str", "choices": ["custom", "mac-os", "win-7", "win-80", "win-81", "win-10", "win-2000", "win-home-svr", "win-svr-10", @@ -910,72 +1040,72 @@ def main(): "ubuntu-linux", "centos-linux", "redhat-linux", "fedora-linux"]} }}, - "forticlient-own-file": {"required": False, "type": "list", + "forticlient_own_file": {"required": False, "type": "list", "options": { "file": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"} }}, - "forticlient-registration-compliance-action": {"required": False, "type": "str", + "forticlient_registration_compliance_action": {"required": False, "type": "str", "choices": ["block", "warning"]}, - "forticlient-registry-entry": {"required": False, "type": "list", + "forticlient_registry_entry": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "registry-entry": {"required": False, "type": "str"} + "registry_entry": {"required": False, "type": "str"} }}, - "forticlient-running-app": {"required": False, "type": "list", + "forticlient_running_app": {"required": False, "type": "list", "options": { - "app-name": {"required": False, "type": "str"}, - "app-sha256-signature": {"required": False, "type": "str"}, - "app-sha256-signature2": {"required": False, "type": "str"}, - "app-sha256-signature3": {"required": False, "type": "str"}, - "app-sha256-signature4": {"required": False, "type": "str"}, - "application-check-rule": {"required": False, "type": "str", + "app_name": {"required": False, "type": "str"}, + "app_sha256_signature": {"required": False, "type": "str"}, + "app_sha256_signature2": {"required": False, "type": "str"}, + "app_sha256_signature3": {"required": False, "type": "str"}, + "app_sha256_signature4": {"required": False, "type": "str"}, + "application_check_rule": {"required": False, "type": "str", "choices": ["present", "absent"]}, "id": {"required": True, "type": "int"}, - "process-name": {"required": False, "type": "str"}, - "process-name2": {"required": False, "type": "str"}, - "process-name3": {"required": False, "type": "str"}, - "process-name4": {"required": False, "type": "str"} + "process_name": {"required": False, "type": "str"}, + "process_name2": {"required": False, "type": "str"}, + "process_name3": {"required": False, "type": "str"}, + "process_name4": {"required": False, "type": "str"} }}, - "forticlient-security-posture": {"required": False, "type": "str", + "forticlient_security_posture": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-security-posture-compliance-action": {"required": False, "type": "str", + "forticlient_security_posture_compliance_action": {"required": False, "type": "str", "choices": ["block", "warning"]}, - "forticlient-system-compliance": {"required": False, "type": "str", + "forticlient_system_compliance": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-system-compliance-action": {"required": False, "type": "str", + "forticlient_system_compliance_action": {"required": False, "type": "str", "choices": ["block", "warning"]}, - "forticlient-vuln-scan": {"required": False, "type": "str", + "forticlient_vuln_scan": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-vuln-scan-compliance-action": {"required": False, "type": "str", + "forticlient_vuln_scan_compliance_action": {"required": False, "type": "str", "choices": ["block", "warning"]}, - "forticlient-vuln-scan-enforce": {"required": False, "type": "str", + "forticlient_vuln_scan_enforce": {"required": False, "type": "str", "choices": ["critical", "high", "medium", "low", "info"]}, - "forticlient-vuln-scan-enforce-grace": {"required": False, "type": "int"}, - "forticlient-vuln-scan-exempt": {"required": False, "type": "str", + "forticlient_vuln_scan_enforce_grace": {"required": False, "type": "int"}, + "forticlient_vuln_scan_exempt": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-wf": {"required": False, "type": "str", + "forticlient_wf": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-wf-profile": {"required": False, "type": "str"}, - "forticlient-win-ver": {"required": False, "type": "str"}, - "os-av-software-installed": {"required": False, "type": "str", + "forticlient_wf_profile": {"required": False, "type": "str"}, + "forticlient_win_ver": {"required": False, "type": "str"}, + "os_av_software_installed": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "sandbox-address": {"required": False, "type": "str"}, - "sandbox-analysis": {"required": False, "type": "str", + "sandbox_address": {"required": False, "type": "str"}, + "sandbox_analysis": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "on-net-addr": {"required": False, "type": "list", + "on_net_addr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "profile-name": {"required": True, "type": "str"}, - "replacemsg-override-group": {"required": False, "type": "str"}, - "src-addr": {"required": False, "type": "list", + "profile_name": {"required": False, "type": "str"}, + "replacemsg_override_group": {"required": False, "type": "str"}, + "src_addr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "user-groups": {"required": False, "type": "list", + "user_groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, @@ -990,15 +1120,30 @@ 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 = '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_endpoint_control(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_endpoint_control(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_endpoint_control(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_endpoint_control_settings.py b/lib/ansible/modules/network/fortios/fortios_endpoint_control_settings.py index 6f6a4dfd31d..7a8f4de4038 100644 --- a/lib/ansible/modules/network/fortios/fortios_endpoint_control_settings.py +++ b/lib/ansible/modules/network/fortios/fortios_endpoint_control_settings.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_endpoint_control_settings short_description: Configure endpoint control settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure endpoint_control feature and settings 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 device by allowing the + user to set and modify endpoint_control feature and settings 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,91 +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: false + default: true + version_added: 2.9 endpoint_control_settings: description: - Configure endpoint control settings. default: null + type: dict suboptions: - download-custom-link: + download_custom_link: description: - Customized URL for downloading FortiClient. - download-location: + type: str + download_location: description: - FortiClient download location (FortiGuard or custom). + type: str choices: - fortiguard - custom - forticlient-avdb-update-interval: + forticlient_avdb_update_interval: description: - Period of time between FortiClient AntiVirus database updates (0 - 24 hours, default = 8). - forticlient-dereg-unsupported-client: + type: int + forticlient_dereg_unsupported_client: description: - Enable/disable deregistering unsupported FortiClient endpoints. + type: str choices: - enable - disable - forticlient-ems-rest-api-call-timeout: + forticlient_ems_rest_api_call_timeout: description: - FortiClient EMS call timeout in milliseconds (500 - 30000 milliseconds, default = 5000). - forticlient-keepalive-interval: + type: int + forticlient_keepalive_interval: description: - Interval between two KeepAlive messages from FortiClient (20 - 300 sec, default = 60). - forticlient-offline-grace: + type: int + forticlient_offline_grace: description: - Enable/disable grace period for offline registered clients. + type: str choices: - enable - disable - forticlient-offline-grace-interval: + forticlient_offline_grace_interval: description: - Grace period for offline registered FortiClient (60 - 600 sec, default = 120). - forticlient-reg-key: + type: int + forticlient_reg_key: description: - FortiClient registration key. - forticlient-reg-key-enforce: + type: str + forticlient_reg_key_enforce: description: - Enable/disable requiring or enforcing FortiClient registration keys. + type: str choices: - enable - disable - forticlient-reg-timeout: + forticlient_reg_timeout: description: - FortiClient registration license timeout (days, min = 1, max = 180, 0 means unlimited). - forticlient-sys-update-interval: + type: int + forticlient_sys_update_interval: description: - Interval between two system update messages from FortiClient (30 - 1440 min, default = 720). - forticlient-user-avatar: + type: int + forticlient_user_avatar: description: - Enable/disable uploading FortiClient user avatars. + type: str choices: - enable - disable - forticlient-warning-interval: + forticlient_warning_interval: description: - Period of time between FortiClient portal warnings (0 - 24 hours, default = 1). + type: int ''' EXAMPLES = ''' @@ -138,6 +159,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure endpoint control settings. fortios_endpoint_control_settings: @@ -145,21 +167,22 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" endpoint_control_settings: - download-custom-link: "" - download-location: "fortiguard" - forticlient-avdb-update-interval: "5" - forticlient-dereg-unsupported-client: "enable" - forticlient-ems-rest-api-call-timeout: "7" - forticlient-keepalive-interval: "8" - forticlient-offline-grace: "enable" - forticlient-offline-grace-interval: "10" - forticlient-reg-key: "" - forticlient-reg-key-enforce: "enable" - forticlient-reg-timeout: "13" - forticlient-sys-update-interval: "14" - forticlient-user-avatar: "enable" - forticlient-warning-interval: "16" + download_custom_link: "" + download_location: "fortiguard" + forticlient_avdb_update_interval: "5" + forticlient_dereg_unsupported_client: "enable" + forticlient_ems_rest_api_call_timeout: "7" + forticlient_keepalive_interval: "8" + forticlient_offline_grace: "enable" + forticlient_offline_grace_interval: "10" + forticlient_reg_key: "" + forticlient_reg_key_enforce: "enable" + forticlient_reg_timeout: "13" + forticlient_sys_update_interval: "14" + forticlient_user_avatar: "enable" + forticlient_warning_interval: "16" ''' RETURN = ''' @@ -222,14 +245,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -237,15 +262,15 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_endpoint_control_settings_data(json): - option_list = ['download-custom-link', 'download-location', 'forticlient-avdb-update-interval', - 'forticlient-dereg-unsupported-client', 'forticlient-ems-rest-api-call-timeout', 'forticlient-keepalive-interval', - 'forticlient-offline-grace', 'forticlient-offline-grace-interval', 'forticlient-reg-key', - 'forticlient-reg-key-enforce', 'forticlient-reg-timeout', 'forticlient-sys-update-interval', - 'forticlient-user-avatar', 'forticlient-warning-interval'] + option_list = ['download_custom_link', 'download_location', 'forticlient_avdb_update_interval', + 'forticlient_dereg_unsupported_client', 'forticlient_ems_rest_api_call_timeout', 'forticlient_keepalive_interval', + 'forticlient_offline_grace', 'forticlient_offline_grace_interval', 'forticlient_reg_key', + 'forticlient_reg_key_enforce', 'forticlient_reg_timeout', 'forticlient_sys_update_interval', + 'forticlient_user_avatar', 'forticlient_warning_interval'] dictionary = {} for attribute in option_list: @@ -255,58 +280,75 @@ def filter_endpoint_control_settings_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 endpoint_control_settings(data, fos): vdom = data['vdom'] endpoint_control_settings_data = data['endpoint_control_settings'] - filtered_data = filter_endpoint_control_settings_data(endpoint_control_settings_data) + filtered_data = underscore_to_hyphen(filter_endpoint_control_settings_data(endpoint_control_settings_data)) + return fos.set('endpoint-control', 'settings', 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_endpoint_control(data, fos): - login(data) - methodlist = ['endpoint_control_settings'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['endpoint_control_settings']: + resp = endpoint_control_settings(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "endpoint_control_settings": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "download-custom-link": {"required": False, "type": "str"}, - "download-location": {"required": False, "type": "str", + "download_custom_link": {"required": False, "type": "str"}, + "download_location": {"required": False, "type": "str", "choices": ["fortiguard", "custom"]}, - "forticlient-avdb-update-interval": {"required": False, "type": "int"}, - "forticlient-dereg-unsupported-client": {"required": False, "type": "str", + "forticlient_avdb_update_interval": {"required": False, "type": "int"}, + "forticlient_dereg_unsupported_client": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-ems-rest-api-call-timeout": {"required": False, "type": "int"}, - "forticlient-keepalive-interval": {"required": False, "type": "int"}, - "forticlient-offline-grace": {"required": False, "type": "str", + "forticlient_ems_rest_api_call_timeout": {"required": False, "type": "int"}, + "forticlient_keepalive_interval": {"required": False, "type": "int"}, + "forticlient_offline_grace": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-offline-grace-interval": {"required": False, "type": "int"}, - "forticlient-reg-key": {"required": False, "type": "str"}, - "forticlient-reg-key-enforce": {"required": False, "type": "str", + "forticlient_offline_grace_interval": {"required": False, "type": "int"}, + "forticlient_reg_key": {"required": False, "type": "str"}, + "forticlient_reg_key_enforce": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-reg-timeout": {"required": False, "type": "int"}, - "forticlient-sys-update-interval": {"required": False, "type": "int"}, - "forticlient-user-avatar": {"required": False, "type": "str", + "forticlient_reg_timeout": {"required": False, "type": "int"}, + "forticlient_sys_update_interval": {"required": False, "type": "int"}, + "forticlient_user_avatar": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forticlient-warning-interval": {"required": False, "type": "int"} + "forticlient_warning_interval": {"required": False, "type": "int"} } } @@ -314,15 +356,30 @@ 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 = '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_endpoint_control(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_endpoint_control(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_endpoint_control(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_extender_controller_extender.py b/lib/ansible/modules/network/fortios/fortios_extender_controller_extender.py index 8cbdd01faf6..8c03f95f0e6 100644 --- a/lib/ansible/modules/network/fortios/fortios_extender_controller_extender.py +++ b/lib/ansible/modules/network/fortios/fortios_extender_controller_extender.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_extender_controller_extender short_description: Extender controller configuration in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure extender_controller feature and extender 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 device by allowing the + user to set and modify extender_controller feature and extender 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,155 +41,195 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 extender_controller_extender: description: - Extender controller configuration. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - aaa-shared-secret: + aaa_shared_secret: description: - AAA shared secret. - access-point-name: + type: str + access_point_name: description: - Access point name(APN). + type: str admin: description: - FortiExtender Administration (enable or disable). + type: str choices: - disable - discovered - enable - at-dial-script: + at_dial_script: description: - Initialization AT commands specific to the MODEM. - billing-start-day: + type: str + billing_start_day: description: - Billing start day. - cdma-aaa-spi: + type: int + cdma_aaa_spi: description: - CDMA AAA SPI. - cdma-ha-spi: + type: str + cdma_ha_spi: description: - CDMA HA SPI. - cdma-nai: + type: str + cdma_nai: description: - NAI for CDMA MODEMS. - conn-status: + type: str + conn_status: description: - Connection status. + type: int description: description: - Description. - dial-mode: + type: str + dial_mode: description: - Dial mode (dial-on-demand or always-connect). + type: str choices: - dial-on-demand - always-connect - dial-status: + dial_status: description: - Dial status. - ext-name: + type: int + ext_name: description: - FortiExtender name. - ha-shared-secret: + type: str + ha_shared_secret: description: - HA shared secret. + type: str id: description: - FortiExtender serial number. required: true + type: str ifname: description: - FortiExtender interface name. - initiated-update: + type: str + initiated_update: description: - Allow/disallow network initiated updates to the MODEM. + type: str choices: - enable - disable mode: description: - FortiExtender mode. + type: str choices: - standalone - redundant - modem-passwd: + modem_passwd: description: - MODEM password. - modem-type: + type: str + modem_type: description: - MODEM type (CDMA, GSM/LTE or WIMAX). + type: str choices: - cdma - gsm/lte - wimax - multi-mode: + multi_mode: description: - MODEM mode of operation(3G,LTE,etc). + type: str choices: - auto - auto-3g - force-lte - force-3g - force-2g - ppp-auth-protocol: + ppp_auth_protocol: description: - PPP authentication protocol (PAP,CHAP or auto). + type: str choices: - auto - pap - chap - ppp-echo-request: + ppp_echo_request: description: - Enable/disable PPP echo request. + type: str choices: - enable - disable - ppp-password: + ppp_password: description: - PPP password. - ppp-username: + type: str + ppp_username: description: - PPP username. - primary-ha: + type: str + primary_ha: description: - Primary HA. - quota-limit-mb: + type: str + quota_limit_mb: description: - Monthly quota limit (MB). + type: int redial: description: - Number of redials allowed based on failed attempts. + type: str choices: - none - 1 @@ -205,43 +242,52 @@ options: - 8 - 9 - 10 - redundant-intf: + redundant_intf: description: - Redundant interface. + type: str roaming: description: - Enable/disable MODEM roaming. + type: str choices: - enable - disable role: description: - FortiExtender work role(Primary, Secondary, None). + type: str choices: - none - primary - secondary - secondary-ha: + secondary_ha: description: - Secondary HA. - sim-pin: + type: str + sim_pin: description: - SIM PIN. + type: str vdom: description: - VDOM - wimax-auth-protocol: + type: int + wimax_auth_protocol: description: - WiMax authentication protocol(TLS or TTLS). + type: str choices: - tls - ttls - wimax-carrier: + wimax_carrier: description: - WiMax carrier. - wimax-realm: + type: str + wimax_realm: description: - WiMax realm. + type: str ''' EXAMPLES = ''' @@ -251,6 +297,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Extender controller configuration. fortios_extender_controller_extender: @@ -258,45 +305,46 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" extender_controller_extender: - state: "present" - aaa-shared-secret: "" - access-point-name: "" + aaa_shared_secret: "" + access_point_name: "" admin: "disable" - at-dial-script: "" - billing-start-day: "7" - cdma-aaa-spi: "" - cdma-ha-spi: "" - cdma-nai: "" - conn-status: "11" + at_dial_script: "" + billing_start_day: "7" + cdma_aaa_spi: "" + cdma_ha_spi: "" + cdma_nai: "" + conn_status: "11" description: "" - dial-mode: "dial-on-demand" - dial-status: "14" - ext-name: "" - ha-shared-secret: "" + dial_mode: "dial-on-demand" + dial_status: "14" + ext_name: "" + ha_shared_secret: "" id: "17" ifname: "" - initiated-update: "enable" + initiated_update: "enable" mode: "standalone" - modem-passwd: "" - modem-type: "cdma" - multi-mode: "auto" - ppp-auth-protocol: "auto" - ppp-echo-request: "enable" - ppp-password: "" - ppp-username: "" - primary-ha: "" - quota-limit-mb: "29" + modem_passwd: "" + modem_type: "cdma" + multi_mode: "auto" + ppp_auth_protocol: "auto" + ppp_echo_request: "enable" + ppp_password: "" + ppp_username: "" + primary_ha: "" + quota_limit_mb: "29" redial: "none" - redundant-intf: "" + redundant_intf: "" roaming: "enable" role: "none" - secondary-ha: "" - sim-pin: "" + secondary_ha: "" + sim_pin: "" vdom: "36" - wimax-auth-protocol: "tls" - wimax-carrier: "" - wimax-realm: "" + wimax_auth_protocol: "tls" + wimax_carrier: "" + wimax_realm: "" ''' RETURN = ''' @@ -359,14 +407,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -374,23 +424,23 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_extender_controller_extender_data(json): - option_list = ['aaa-shared-secret', 'access-point-name', 'admin', - 'at-dial-script', 'billing-start-day', 'cdma-aaa-spi', - 'cdma-ha-spi', 'cdma-nai', 'conn-status', - 'description', 'dial-mode', 'dial-status', - 'ext-name', 'ha-shared-secret', 'id', - 'ifname', 'initiated-update', 'mode', - 'modem-passwd', 'modem-type', 'multi-mode', - 'ppp-auth-protocol', 'ppp-echo-request', 'ppp-password', - 'ppp-username', 'primary-ha', 'quota-limit-mb', - 'redial', 'redundant-intf', 'roaming', - 'role', 'secondary-ha', 'sim-pin', - 'vdom', 'wimax-auth-protocol', 'wimax-carrier', - 'wimax-realm'] + option_list = ['aaa_shared_secret', 'access_point_name', 'admin', + 'at_dial_script', 'billing_start_day', 'cdma_aaa_spi', + 'cdma_ha_spi', 'cdma_nai', 'conn_status', + 'description', 'dial_mode', 'dial_status', + 'ext_name', 'ha_shared_secret', 'id', + 'ifname', 'initiated_update', 'mode', + 'modem_passwd', 'modem_type', 'multi_mode', + 'ppp_auth_protocol', 'ppp_echo_request', 'ppp_password', + 'ppp_username', 'primary_ha', 'quota_limit_mb', + 'redial', 'redundant_intf', 'roaming', + 'role', 'secondary_ha', 'sim_pin', + 'vdom', 'wimax_auth_protocol', 'wimax_carrier', + 'wimax_realm'] dictionary = {} for attribute in option_list: @@ -400,101 +450,119 @@ def filter_extender_controller_extender_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 extender_controller_extender(data, fos): vdom = data['vdom'] + state = data['state'] extender_controller_extender_data = data['extender_controller_extender'] - filtered_data = filter_extender_controller_extender_data(extender_controller_extender_data) - if extender_controller_extender_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_extender_controller_extender_data(extender_controller_extender_data)) + + if state == "present": return fos.set('extender-controller', 'extender', data=filtered_data, vdom=vdom) - elif extender_controller_extender_data['state'] == "absent": + elif state == "absent": return fos.delete('extender-controller', 'extender', 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_extender_controller(data, fos): - login(data) - methodlist = ['extender_controller_extender'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['extender_controller_extender']: + resp = extender_controller_extender(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "extender_controller_extender": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "aaa-shared-secret": {"required": False, "type": "str"}, - "access-point-name": {"required": False, "type": "str"}, + "aaa_shared_secret": {"required": False, "type": "str"}, + "access_point_name": {"required": False, "type": "str"}, "admin": {"required": False, "type": "str", "choices": ["disable", "discovered", "enable"]}, - "at-dial-script": {"required": False, "type": "str"}, - "billing-start-day": {"required": False, "type": "int"}, - "cdma-aaa-spi": {"required": False, "type": "str"}, - "cdma-ha-spi": {"required": False, "type": "str"}, - "cdma-nai": {"required": False, "type": "str"}, - "conn-status": {"required": False, "type": "int"}, + "at_dial_script": {"required": False, "type": "str"}, + "billing_start_day": {"required": False, "type": "int"}, + "cdma_aaa_spi": {"required": False, "type": "str"}, + "cdma_ha_spi": {"required": False, "type": "str"}, + "cdma_nai": {"required": False, "type": "str"}, + "conn_status": {"required": False, "type": "int"}, "description": {"required": False, "type": "str"}, - "dial-mode": {"required": False, "type": "str", + "dial_mode": {"required": False, "type": "str", "choices": ["dial-on-demand", "always-connect"]}, - "dial-status": {"required": False, "type": "int"}, - "ext-name": {"required": False, "type": "str"}, - "ha-shared-secret": {"required": False, "type": "str"}, + "dial_status": {"required": False, "type": "int"}, + "ext_name": {"required": False, "type": "str"}, + "ha_shared_secret": {"required": False, "type": "str"}, "id": {"required": True, "type": "str"}, "ifname": {"required": False, "type": "str"}, - "initiated-update": {"required": False, "type": "str", + "initiated_update": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "mode": {"required": False, "type": "str", "choices": ["standalone", "redundant"]}, - "modem-passwd": {"required": False, "type": "str"}, - "modem-type": {"required": False, "type": "str", + "modem_passwd": {"required": False, "type": "str"}, + "modem_type": {"required": False, "type": "str", "choices": ["cdma", "gsm/lte", "wimax"]}, - "multi-mode": {"required": False, "type": "str", + "multi_mode": {"required": False, "type": "str", "choices": ["auto", "auto-3g", "force-lte", "force-3g", "force-2g"]}, - "ppp-auth-protocol": {"required": False, "type": "str", + "ppp_auth_protocol": {"required": False, "type": "str", "choices": ["auto", "pap", "chap"]}, - "ppp-echo-request": {"required": False, "type": "str", + "ppp_echo_request": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ppp-password": {"required": False, "type": "str"}, - "ppp-username": {"required": False, "type": "str"}, - "primary-ha": {"required": False, "type": "str"}, - "quota-limit-mb": {"required": False, "type": "int"}, + "ppp_password": {"required": False, "type": "str"}, + "ppp_username": {"required": False, "type": "str"}, + "primary_ha": {"required": False, "type": "str"}, + "quota_limit_mb": {"required": False, "type": "int"}, "redial": {"required": False, "type": "str", "choices": ["none", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]}, - "redundant-intf": {"required": False, "type": "str"}, + "redundant_intf": {"required": False, "type": "str"}, "roaming": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "role": {"required": False, "type": "str", "choices": ["none", "primary", "secondary"]}, - "secondary-ha": {"required": False, "type": "str"}, - "sim-pin": {"required": False, "type": "str"}, + "secondary_ha": {"required": False, "type": "str"}, + "sim_pin": {"required": False, "type": "str"}, "vdom": {"required": False, "type": "int"}, - "wimax-auth-protocol": {"required": False, "type": "str", + "wimax_auth_protocol": {"required": False, "type": "str", "choices": ["tls", "ttls"]}, - "wimax-carrier": {"required": False, "type": "str"}, - "wimax-realm": {"required": False, "type": "str"} + "wimax_carrier": {"required": False, "type": "str"}, + "wimax_realm": {"required": False, "type": "str"} } } @@ -502,15 +570,30 @@ 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 = '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_extender_controller(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_extender_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_extender_controller(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_DoS_policy.py b/lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy.py index e81fe0a3f71..a6dfe66921c 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_DoS_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_DoS_policy short_description: Configure IPv4 DoS 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 DoS_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 device by allowing the + user to set and modify firewall feature and DoS_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,53 +41,68 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_DoS_policy: description: - Configure IPv4 DoS policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent anomaly: description: - Anomaly name. + 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,71 +110,88 @@ 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. + type: int comments: description: - Comment. + type: str dstaddr: description: - Destination address name from available addresses. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str interface: description: - Incoming interface name from available interfaces. Source system.zone.name system.interface.name. + type: str policyid: description: - Policy ID. required: true + type: int service: description: - Service object from available options. + type: list suboptions: name: description: - Service name. Source firewall.service.custom.name firewall.service.group.name. required: true + type: str srcaddr: description: - Source address name from available addresses. + type: list suboptions: name: description: - Service name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str status: description: - Enable/disable this policy. + type: str choices: - enable - disable @@ -175,6 +204,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv4 DoS policies. fortios_firewall_DoS_policy: @@ -182,16 +212,17 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_DoS_policy: - 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" @@ -270,14 +301,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -285,7 +318,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_DoS_policy_data(json): @@ -301,48 +334,66 @@ def filter_firewall_DoS_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_DoS_policy(data, fos): vdom = data['vdom'] + state = data['state'] firewall_DoS_policy_data = data['firewall_DoS_policy'] - filtered_data = filter_firewall_DoS_policy_data(firewall_DoS_policy_data) - if firewall_DoS_policy_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_DoS_policy_data(firewall_DoS_policy_data)) + + if state == "present": return fos.set('firewall', 'DoS-policy', data=filtered_data, vdom=vdom) - elif firewall_DoS_policy_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'DoS-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_DoS_policy'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_DoS_policy']: + resp = firewall_DoS_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_DoS_policy": { - "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", @@ -352,8 +403,8 @@ 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"]}, @@ -384,15 +435,30 @@ 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 = '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_DoS_policy6.py b/lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py index bc7e4fa9a10..954042ee76f 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.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_DoS_policy6 short_description: Configure IPv6 DoS 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 DoS_policy6 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 device by allowing the + user to set and modify firewall feature and DoS_policy6 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,68 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_DoS_policy6: description: - Configure IPv6 DoS policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent anomaly: description: - Anomaly name. + 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,71 +110,88 @@ 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. + type: int comments: description: - Comment. + type: str dstaddr: description: - Destination address name from available addresses. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str interface: description: - Incoming interface name from available interfaces. Source system.zone.name system.interface.name. + type: str policyid: description: - Policy ID. required: true + type: int service: description: - Service object from available options. + type: list suboptions: name: description: - Service name. Source firewall.service.custom.name firewall.service.group.name. required: true + type: str srcaddr: description: - Source address name from available addresses. + type: list suboptions: name: description: - Service name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str status: description: - Enable/disable this policy. + type: str choices: - enable - disable @@ -175,6 +204,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv6 DoS policies. fortios_firewall_DoS_policy6: @@ -182,16 +212,17 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_DoS_policy6: - 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" @@ -270,14 +301,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -285,7 +318,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_DoS_policy6_data(json): @@ -301,48 +334,66 @@ def filter_firewall_DoS_policy6_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_DoS_policy6(data, fos): vdom = data['vdom'] + state = data['state'] firewall_DoS_policy6_data = data['firewall_DoS_policy6'] - filtered_data = filter_firewall_DoS_policy6_data(firewall_DoS_policy6_data) - if firewall_DoS_policy6_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_DoS_policy6_data(firewall_DoS_policy6_data)) + + if state == "present": return fos.set('firewall', 'DoS-policy6', data=filtered_data, vdom=vdom) - elif firewall_DoS_policy6_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'DoS-policy6', 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_DoS_policy6'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_DoS_policy6']: + resp = firewall_DoS_policy6(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_DoS_policy6": { - "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", @@ -352,8 +403,8 @@ 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"]}, @@ -384,15 +435,30 @@ 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 = '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_address.py b/lib/ansible/modules/network/fortios/fortios_firewall_address.py index 33b4d14366e..6329dc2310a 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_address.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_address.py @@ -1,6 +1,6 @@ #!/usr/bin/python from __future__ import (absolute_import, division, print_function) -# Copyright 2018 Fortinet, Inc. +# 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 @@ -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 @@ -27,12 +24,12 @@ ANSIBLE_METADATA = {'status': ['preview'], DOCUMENTATION = ''' --- module: fortios_firewall_address -short_description: Configure IPv4 addresses. +short_description: Configure IPv4 addresses 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 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 device by allowing the + user to set and modify firewall feature and 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,97 +41,126 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_address: description: - Configure IPv4 addresses. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - allow-routing: + allow_routing: description: - Enable/disable use of this address in the static route configuration. + type: str choices: - enable - disable - associated-interface: + associated_interface: description: - Network interface associated with address. Source system.interface.name system.zone.name. - cache-ttl: + type: str + cache_ttl: description: - Defines the minimal TTL of individual IP addresses in FQDN cache measured in seconds. + type: int color: description: - Color of icon on the GUI. + type: int comment: description: - Comment. + type: str country: description: - IP addresses associated to a specific country. - end-ip: + type: str + end_ip: description: - Final IP address (inclusive) in the range for the address. - epg-name: + type: str + epg_name: description: - Endpoint group name. + type: str filter: description: - Match criteria filter. + type: str fqdn: description: - Fully Qualified Domain Name address. + type: str list: description: - IP address list. + type: list suboptions: ip: description: - IP. required: true + type: str name: description: - Address name. required: true - obj-id: + type: str + obj_id: description: - Object ID for NSX. + type: str organization: description: - "Organization domain name (Syntax: organization/domain)." - policy-group: + type: str + policy_group: description: - Policy group name. + type: str sdn: description: - SDN. + type: str choices: - aci - aws @@ -143,43 +169,55 @@ options: - nsx - nuage - oci - sdn-tag: + - openstack + sdn_tag: description: - SDN Tag. - start-ip: + type: str + start_ip: description: - First IP address (inclusive) in the range for the address. + type: str subnet: description: - IP address and subnet mask of address. - subnet-name: + type: str + subnet_name: description: - Subnet name. + 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 tenant: description: - Tenant. + type: str type: description: - Type of address. + type: str choices: - ipmask - iprange @@ -191,18 +229,22 @@ options: uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable address visibility in the GUI. + type: str choices: - enable - disable wildcard: description: - IP address and wildcard netmask. - wildcard-fqdn: + type: str + wildcard_fqdn: description: - Fully Qualified Domain Name with wildcard characters. + type: str ''' EXAMPLES = ''' @@ -212,37 +254,39 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv4 addresses. fortios_firewall_address: - host: "{{ host }}" + host: "{{ host }}" username: "{{ username }}" password: "{{ password }}" - vdom: "{{ vdom }}" + vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_address: - state: "present" - allow-routing: "enable" - associated-interface: " (source system.interface.name system.zone.name)" - cache-ttl: "5" + allow_routing: "enable" + associated_interface: " (source system.interface.name system.zone.name)" + cache_ttl: "5" color: "6" comment: "Comment." country: "" - end-ip: "" - epg-name: "" + end_ip: "" + epg_name: "" filter: "" fqdn: "" list: - ip: "" name: "default_name_15" - obj-id: "" + obj_id: "" organization: "" - policy-group: "" + policy_group: "" sdn: "aci" - sdn-tag: "" - start-ip: "" + sdn_tag: "" + start_ip: "" subnet: "" - subnet-name: "" + subnet_name: "" tagging: - category: " (source system.object-tagging.category)" @@ -255,7 +299,7 @@ EXAMPLES = ''' uuid: "" visibility: "enable" wildcard: "" - wildcard-fqdn: "" + wildcard_fqdn: "" ''' RETURN = ''' @@ -278,7 +322,7 @@ mkey: description: Master key (id) used in the last call to FortiGate returned: success type: str - sample: "key1" + sample: "id" name: description: Name of the table used to fulfill the request returned: always @@ -318,14 +362,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -333,79 +379,97 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_address_data(json): - option_list = ['allow-routing', 'associated-interface', 'cache-ttl', + option_list = ['allow_routing', 'associated_interface', 'cache_ttl', 'color', 'comment', 'country', - 'end-ip', 'epg-name', 'filter', + 'end_ip', 'epg_name', 'filter', 'fqdn', 'list', 'name', - 'obj-id', 'organization', 'policy-group', - 'sdn', 'sdn-tag', 'start-ip', - 'subnet', 'subnet-name', 'tagging', + 'obj_id', 'organization', 'policy_group', + 'sdn', 'sdn_tag', 'start_ip', + 'subnet', 'subnet_name', 'tagging', 'tenant', 'type', 'uuid', - 'visibility', 'wildcard', 'wildcard-fqdn'] + 'visibility', 'wildcard', 'wildcard_fqdn'] dictionary = {} for attribute in option_list: - if attribute in json: + if attribute in json and json[attribute] is not None: dictionary[attribute] = json[attribute] 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_address(data, fos): vdom = data['vdom'] + state = data['state'] firewall_address_data = data['firewall_address'] - filtered_data = filter_firewall_address_data(firewall_address_data) - if firewall_address_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_address_data(firewall_address_data)) + + if state == "present": return fos.set('firewall', 'address', data=filtered_data, vdom=vdom) - elif firewall_address_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', '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_address'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_address']: + resp = firewall_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_address": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "allow-routing": {"required": False, "type": "str", + "allow_routing": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "associated-interface": {"required": False, "type": "str"}, - "cache-ttl": {"required": False, "type": "int"}, + "associated_interface": {"required": False, "type": "str"}, + "cache_ttl": {"required": False, "type": "int"}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, "country": {"required": False, "type": "str"}, - "end-ip": {"required": False, "type": "str"}, - "epg-name": {"required": False, "type": "str"}, + "end_ip": {"required": False, "type": "str"}, + "epg_name": {"required": False, "type": "str"}, "filter": {"required": False, "type": "str"}, "fqdn": {"required": False, "type": "str"}, "list": {"required": False, "type": "list", @@ -413,17 +477,17 @@ def main(): "ip": {"required": True, "type": "str"} }}, "name": {"required": True, "type": "str"}, - "obj-id": {"required": False, "type": "str"}, + "obj_id": {"required": False, "type": "str"}, "organization": {"required": False, "type": "str"}, - "policy-group": {"required": False, "type": "str"}, + "policy_group": {"required": False, "type": "str"}, "sdn": {"required": False, "type": "str", "choices": ["aci", "aws", "azure", "gcp", "nsx", "nuage", - "oci"]}, - "sdn-tag": {"required": False, "type": "str"}, - "start-ip": {"required": False, "type": "str"}, + "oci", "openstack"]}, + "sdn_tag": {"required": False, "type": "str"}, + "start_ip": {"required": False, "type": "str"}, "subnet": {"required": False, "type": "str"}, - "subnet-name": {"required": False, "type": "str"}, + "subnet_name": {"required": False, "type": "str"}, "tagging": {"required": False, "type": "list", "options": { "category": {"required": False, "type": "str"}, @@ -442,7 +506,7 @@ def main(): "visibility": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "wildcard": {"required": False, "type": "str"}, - "wildcard-fqdn": {"required": False, "type": "str"} + "wildcard_fqdn": {"required": False, "type": "str"} } } @@ -450,15 +514,30 @@ 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 = '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_address6.py b/lib/ansible/modules/network/fortios/fortios_firewall_address6.py index 20fd5c12910..48bf5895990 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_address6.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_address6.py @@ -1,6 +1,6 @@ #!/usr/bin/python from __future__ import (absolute_import, division, print_function) -# Copyright 2018 Fortinet, Inc. +# 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 @@ -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_address6 short_description: Configure IPv6 firewall addresses 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 address6 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 device by allowing the + user to set and modify firewall feature and address6 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,132 +41,169 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_address6: description: - Configure IPv6 firewall addresses. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - cache-ttl: + cache_ttl: description: - Minimal TTL of individual IPv6 addresses in FQDN cache. + type: int color: description: - Integer value to determine the color of the icon in the GUI (range 1 to 32, default = 0, which sets the value to 1). + type: int comment: description: - Comment. - end-ip: + type: str + end_ip: description: - "Final IP address (inclusive) in the range for the address (format: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx)." + type: str fqdn: description: - Fully qualified domain name. + type: str host: description: - Host Address. - host-type: + type: str + host_type: description: - Host type. + type: str choices: - any - specific ip6: description: - "IPv6 address prefix (format: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xxx)." + type: str list: description: - IP address list. + type: list suboptions: ip: description: - IP. required: true + type: str name: description: - Address name. required: true - obj-id: + type: str + obj_id: description: - Object ID for NSX. + type: str sdn: description: - SDN. + type: str choices: - nsx - start-ip: + start_ip: description: - "First IP address (inclusive) in the range for the address (format: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx)." - subnet-segment: + type: str + subnet_segment: description: - IPv6 subnet segments. + type: list suboptions: name: description: - Name. required: true + type: str type: description: - Subnet segment type. + type: str choices: - any - specific value: description: - Subnet segment value. + 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 template: description: - IPv6 address template. Source firewall.address6-template.name. + type: str type: description: - Type of IPv6 address object (default = ipprefix). + type: str choices: - ipprefix - iprange @@ -179,9 +213,11 @@ options: uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable the visibility of the object in the GUI. + type: str choices: - enable - disable @@ -194,6 +230,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv6 firewall addresses. fortios_firewall_address6: @@ -201,24 +238,25 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_address6: - state: "present" - cache-ttl: "3" + cache_ttl: "3" color: "4" comment: "Comment." - end-ip: "" + end_ip: "" fqdn: "" host: "" - host-type: "any" + host_type: "any" ip6: "" list: - ip: "" name: "default_name_13" - obj-id: "" + obj_id: "" sdn: "nsx" - start-ip: "" - subnet-segment: + start_ip: "" + subnet_segment: - name: "default_name_18" type: "any" @@ -256,7 +294,7 @@ mkey: description: Master key (id) used in the last call to FortiGate returned: success type: str - sample: "key1" + sample: "id" name: description: Name of the table used to fulfill the request returned: always @@ -296,14 +334,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -311,15 +351,15 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_address6_data(json): - option_list = ['cache-ttl', 'color', 'comment', - 'end-ip', 'fqdn', 'host', - 'host-type', 'ip6', 'list', - 'name', 'obj-id', 'sdn', - 'start-ip', 'subnet-segment', 'tagging', + option_list = ['cache_ttl', 'color', 'comment', + 'end_ip', 'fqdn', 'host', + 'host_type', 'ip6', 'list', + 'name', 'obj_id', 'sdn', + 'start_ip', 'subnet_segment', 'tagging', 'template', 'type', 'uuid', 'visibility'] dictionary = {} @@ -331,55 +371,73 @@ def filter_firewall_address6_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_address6(data, fos): vdom = data['vdom'] + state = data['state'] firewall_address6_data = data['firewall_address6'] - filtered_data = filter_firewall_address6_data(firewall_address6_data) - if firewall_address6_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_address6_data(firewall_address6_data)) + + if state == "present": return fos.set('firewall', 'address6', data=filtered_data, vdom=vdom) - elif firewall_address6_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'address6', 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_address6'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_address6']: + resp = firewall_address6(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_address6": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "cache-ttl": {"required": False, "type": "int"}, + "cache_ttl": {"required": False, "type": "int"}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, - "end-ip": {"required": False, "type": "str"}, + "end_ip": {"required": False, "type": "str"}, "fqdn": {"required": False, "type": "str"}, "host": {"required": False, "type": "str"}, - "host-type": {"required": False, "type": "str", + "host_type": {"required": False, "type": "str", "choices": ["any", "specific"]}, "ip6": {"required": False, "type": "str"}, "list": {"required": False, "type": "list", @@ -387,11 +445,11 @@ def main(): "ip": {"required": True, "type": "str"} }}, "name": {"required": True, "type": "str"}, - "obj-id": {"required": False, "type": "str"}, + "obj_id": {"required": False, "type": "str"}, "sdn": {"required": False, "type": "str", "choices": ["nsx"]}, - "start-ip": {"required": False, "type": "str"}, - "subnet-segment": {"required": False, "type": "list", + "start_ip": {"required": False, "type": "str"}, + "subnet_segment": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"}, "type": {"required": False, "type": "str", @@ -421,15 +479,30 @@ 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 = '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_address6_template.py b/lib/ansible/modules/network/fortios/fortios_firewall_address6_template.py index b0d0b52f87d..bcfa909a3c6 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_address6_template.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_address6_template.py @@ -1,6 +1,6 @@ #!/usr/bin/python from __future__ import (absolute_import, division, print_function) -# Copyright 2018 Fortinet, Inc. +# 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 @@ -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_address6_template short_description: Configure IPv6 address templates 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 address6_template 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 device by allowing the + user to set and modify firewall feature and address6_template 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,57 +41,74 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_address6_template: description: - Configure IPv6 address templates. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent ip6: description: - IPv6 address prefix. + type: str name: description: - IPv6 address template name. required: true - subnet-segment: + type: str + subnet_segment: description: - IPv6 subnet segments. + type: list suboptions: bits: description: - Number of bits. + type: int exclusive: description: - Enable/disable exclusive value. + type: str choices: - enable - disable @@ -102,23 +116,29 @@ options: description: - Subnet segment ID. required: true + type: int name: description: - Subnet segment name. + type: str values: description: - Subnet segment values. + type: list suboptions: name: description: - Subnet segment value name. required: true + type: str value: description: - Subnet segment value. - subnet-segment-count: + type: str + subnet_segment_count: description: - Number of IPv6 subnet segments. + type: int ''' EXAMPLES = ''' @@ -128,6 +148,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv6 address templates. fortios_firewall_address6_template: @@ -135,11 +156,12 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_address6_template: - state: "present" ip6: "" name: "default_name_4" - subnet-segment: + subnet_segment: - bits: "6" exclusive: "enable" @@ -149,7 +171,7 @@ EXAMPLES = ''' - name: "default_name_11" value: "" - subnet-segment-count: "13" + subnet_segment_count: "13" ''' RETURN = ''' @@ -172,7 +194,7 @@ mkey: description: Master key (id) used in the last call to FortiGate returned: success type: str - sample: "key1" + sample: "id" name: description: Name of the table used to fulfill the request returned: always @@ -212,14 +234,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,12 +251,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_address6_template_data(json): - option_list = ['ip6', 'name', 'subnet-segment', - 'subnet-segment-count'] + option_list = ['ip6', 'name', 'subnet_segment', + 'subnet_segment_count'] dictionary = {} for attribute in option_list: @@ -242,51 +266,69 @@ def filter_firewall_address6_template_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_address6_template(data, fos): vdom = data['vdom'] + state = data['state'] firewall_address6_template_data = data['firewall_address6_template'] - filtered_data = filter_firewall_address6_template_data(firewall_address6_template_data) - if firewall_address6_template_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_address6_template_data(firewall_address6_template_data)) + + if state == "present": return fos.set('firewall', 'address6-template', data=filtered_data, vdom=vdom) - elif firewall_address6_template_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'address6-template', 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_address6_template'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_address6_template']: + resp = firewall_address6_template(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_address6_template": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "ip6": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, - "subnet-segment": {"required": False, "type": "list", + "subnet_segment": {"required": False, "type": "list", "options": { "bits": {"required": False, "type": "int"}, "exclusive": {"required": False, "type": "str", @@ -299,7 +341,7 @@ def main(): "value": {"required": False, "type": "str"} }} }}, - "subnet-segment-count": {"required": False, "type": "int"} + "subnet_segment_count": {"required": False, "type": "int"} } } @@ -307,15 +349,30 @@ 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 = '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_addrgrp.py b/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp.py index b3d9bea4d73..ec0ea5c1a02 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp.py @@ -1,6 +1,6 @@ #!/usr/bin/python from __future__ import (absolute_import, division, print_function) -# Copyright 2018 Fortinet, Inc. +# 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 @@ -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 @@ -27,12 +24,12 @@ ANSIBLE_METADATA = {'status': ['preview'], DOCUMENTATION = ''' --- module: fortios_firewall_addrgrp -short_description: Configure IPv4 address groups. +short_description: Configure IPv4 address 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 feature and 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 device by allowing the + user to set and modify firewall feature and 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,114 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_addrgrp: description: - Configure IPv4 address groups. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - allow-routing: + allow_routing: description: - Enable/disable use of this group in the static route configuration. + type: str choices: - enable - disable color: description: - Color of icon on the GUI. + type: int comment: description: - Comment. + type: str member: description: - Address objects contained within the group. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.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 uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable address visibility in the GUI. + type: str choices: - enable - disable @@ -139,16 +161,18 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv4 address groups. fortios_firewall_addrgrp: - host: "{{ host }}" + host: "{{ host }}" username: "{{ username }}" password: "{{ password }}" - vdom: "{{ vdom }}" + vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_addrgrp: - state: "present" - allow-routing: "enable" + allow_routing: "enable" color: "4" comment: "Comment." member: @@ -186,7 +210,7 @@ mkey: description: Master key (id) used in the last call to FortiGate returned: success type: str - sample: "key1" + sample: "id" name: description: Name of the table used to fulfill the request returned: always @@ -226,14 +250,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -241,65 +267,83 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_addrgrp_data(json): - option_list = ['allow-routing', 'color', 'comment', + option_list = ['allow_routing', 'color', 'comment', 'member', 'name', 'tagging', 'uuid', 'visibility'] dictionary = {} for attribute in option_list: - if attribute in json: + if attribute in json and json[attribute] is not None: dictionary[attribute] = json[attribute] 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_addrgrp(data, fos): vdom = data['vdom'] + state = data['state'] firewall_addrgrp_data = data['firewall_addrgrp'] - filtered_data = filter_firewall_addrgrp_data(firewall_addrgrp_data) - if firewall_addrgrp_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_addrgrp_data(firewall_addrgrp_data)) + + if state == "present": return fos.set('firewall', 'addrgrp', data=filtered_data, vdom=vdom) - elif firewall_addrgrp_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', '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_addrgrp'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_addrgrp']: + resp = firewall_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_addrgrp": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "allow-routing": {"required": False, "type": "str", + "allow_routing": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "color": {"required": False, "type": "int"}, "comment": {"required": False, "type": "str"}, @@ -327,15 +371,30 @@ 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 = '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_addrgrp6.py b/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp6.py index 765b175bb01..2b485cd5e54 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp6.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_addrgrp6.py @@ -1,6 +1,6 @@ #!/usr/bin/python from __future__ import (absolute_import, division, print_function) -# Copyright 2018 Fortinet, Inc. +# 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 @@ -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_addrgrp6 short_description: Configure IPv6 address 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 feature and addrgrp6 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 device by allowing the + user to set and modify firewall feature and addrgrp6 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,83 +41,107 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_addrgrp6: description: - Configure IPv6 address groups. 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 the value to 1). + type: int comment: description: - Comment. + type: str member: description: - Address objects contained within the group. + type: list suboptions: name: description: - Address6/addrgrp6 name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str name: description: - IPv6 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 uuid: description: - Universally Unique Identifier (UUID; automatically assigned but can be manually reset). + type: str visibility: description: - Enable/disable address group6 visibility in the GUI. + type: str choices: - enable - disable @@ -133,6 +154,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv6 address groups. fortios_firewall_addrgrp6: @@ -140,8 +162,9 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_addrgrp6: - state: "present" color: "3" comment: "Comment." member: @@ -179,7 +202,7 @@ mkey: description: Master key (id) used in the last call to FortiGate returned: success type: str - sample: "key1" + sample: "id" name: description: Name of the table used to fulfill the request returned: always @@ -219,14 +242,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -234,7 +259,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_addrgrp6_data(json): @@ -250,48 +275,66 @@ def filter_firewall_addrgrp6_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_addrgrp6(data, fos): vdom = data['vdom'] + state = data['state'] firewall_addrgrp6_data = data['firewall_addrgrp6'] - filtered_data = filter_firewall_addrgrp6_data(firewall_addrgrp6_data) - if firewall_addrgrp6_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_addrgrp6_data(firewall_addrgrp6_data)) + + if state == "present": return fos.set('firewall', 'addrgrp6', data=filtered_data, vdom=vdom) - elif firewall_addrgrp6_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'addrgrp6', 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_addrgrp6'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_addrgrp6']: + resp = firewall_addrgrp6(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_addrgrp6": { - "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", @@ -318,15 +361,30 @@ 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 = '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_auth_portal.py b/lib/ansible/modules/network/fortios/fortios_firewall_auth_portal.py index 64de4e8e174..a7415a62b5d 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_auth_portal.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_auth_portal.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_auth_portal short_description: Configure firewall authentication portals 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 auth_portal 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 device by allowing the + user to set and modify firewall feature and auth_portal 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,66 @@ 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: false + default: true + version_added: 2.9 firewall_auth_portal: description: - Configure firewall authentication portals. default: null + type: dict suboptions: groups: description: - Firewall user groups permitted to authenticate through this portal. Separate group names with spaces. + type: list suboptions: name: description: - Group name. Source user.group.name. required: true - identity-based-route: + type: str + identity_based_route: description: - Name of the identity-based route that applies to this portal. Source firewall.identity-based-route.name. - portal-addr: + type: str + portal_addr: description: - Address (or FQDN) of the authentication portal. - portal-addr6: + type: str + portal_addr6: description: - IPv6 address (or FQDN) of authentication portal. + type: str ''' EXAMPLES = ''' @@ -98,6 +110,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure firewall authentication portals. fortios_firewall_auth_portal: @@ -105,13 +118,14 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" firewall_auth_portal: groups: - name: "default_name_4 (source user.group.name)" - identity-based-route: " (source firewall.identity-based-route.name)" - portal-addr: "" - portal-addr6: "" + identity_based_route: " (source firewall.identity-based-route.name)" + portal_addr: "" + portal_addr6: "" ''' RETURN = ''' @@ -174,14 +188,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -189,12 +205,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_auth_portal_data(json): - option_list = ['groups', 'identity-based-route', 'portal-addr', - 'portal-addr6'] + option_list = ['groups', 'identity_based_route', 'portal_addr', + 'portal_addr6'] dictionary = {} for attribute in option_list: @@ -204,46 +220,63 @@ def filter_firewall_auth_portal_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_auth_portal(data, fos): vdom = data['vdom'] firewall_auth_portal_data = data['firewall_auth_portal'] - filtered_data = filter_firewall_auth_portal_data(firewall_auth_portal_data) + filtered_data = underscore_to_hyphen(filter_firewall_auth_portal_data(firewall_auth_portal_data)) + return fos.set('firewall', 'auth-portal', 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(data, fos): - login(data) - methodlist = ['firewall_auth_portal'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_auth_portal']: + resp = firewall_auth_portal(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "firewall_auth_portal": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { "groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "identity-based-route": {"required": False, "type": "str"}, - "portal-addr": {"required": False, "type": "str"}, - "portal-addr6": {"required": False, "type": "str"} + "identity_based_route": {"required": False, "type": "str"}, + "portal_addr": {"required": False, "type": "str"}, + "portal_addr6": {"required": False, "type": "str"} } } @@ -251,15 +284,30 @@ 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 = '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_central_snat_map.py b/lib/ansible/modules/network/fortios/fortios_firewall_central_snat_map.py index 59e39440b22..b3faf5e62c4 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_central_snat_map.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_central_snat_map.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_central_snat_map short_description: Configure central SNAT 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 central_snat_map 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 device by allowing the + user to set and modify firewall feature and central_snat_map 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,105 +41,134 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_central_snat_map: description: - Configure central SNAT policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comments: description: - Comment. - dst-addr: + type: str + dst_addr: description: - Destination address name from available addresses. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str dstintf: description: - Destination interface name from available interfaces. + type: list suboptions: name: description: - Interface name. Source system.interface.name system.zone.name. required: true + type: str nat: description: - Enable/disable source NAT. + type: str choices: - disable - enable - nat-ippool: + nat_ippool: description: - Name of the IP pools to be used to translate addresses from available IP Pools. + type: list suboptions: name: description: - IP pool name. Source firewall.ippool.name. required: true - nat-port: + type: str + nat_port: description: - Translated port or port range (0 to 65535). - orig-addr: + type: str + orig_addr: description: - Original address. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true - orig-port: + type: str + orig_port: description: - Original TCP port (0 to 65535). + type: str policyid: description: - Policy ID. required: true + type: int protocol: description: - Integer value for the protocol type (0 - 255). + type: int srcintf: description: - Source interface name from available interfaces. + type: list suboptions: name: description: - Interface name. Source system.interface.name system.zone.name. required: true + type: str status: description: - Enable/disable the active status of this policy. + type: str choices: - enable - disable @@ -155,6 +181,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure central SNAT policies. fortios_firewall_central_snat_map: @@ -162,24 +189,25 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_central_snat_map: - state: "present" comments: "" - dst-addr: + dst_addr: - name: "default_name_5 (source firewall.address.name firewall.addrgrp.name)" dstintf: - name: "default_name_7 (source system.interface.name system.zone.name)" nat: "disable" - nat-ippool: + nat_ippool: - name: "default_name_10 (source firewall.ippool.name)" - nat-port: "" - orig-addr: + nat_port: "" + orig_addr: - name: "default_name_13 (source firewall.address.name firewall.addrgrp.name)" - orig-port: "" + orig_port: "" policyid: "15" protocol: "16" srcintf: @@ -248,14 +276,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -263,13 +293,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_central_snat_map_data(json): - option_list = ['comments', 'dst-addr', 'dstintf', - 'nat', 'nat-ippool', 'nat-port', - 'orig-addr', 'orig-port', 'policyid', + option_list = ['comments', 'dst_addr', 'dstintf', + 'nat', 'nat_ippool', 'nat_port', + 'orig_addr', 'orig_port', 'policyid', 'protocol', 'srcintf', 'status'] dictionary = {} @@ -280,50 +310,68 @@ def filter_firewall_central_snat_map_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_central_snat_map(data, fos): vdom = data['vdom'] + state = data['state'] firewall_central_snat_map_data = data['firewall_central_snat_map'] - filtered_data = filter_firewall_central_snat_map_data(firewall_central_snat_map_data) - if firewall_central_snat_map_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_central_snat_map_data(firewall_central_snat_map_data)) + + if state == "present": return fos.set('firewall', 'central-snat-map', data=filtered_data, vdom=vdom) - elif firewall_central_snat_map_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'central-snat-map', 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_central_snat_map'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_central_snat_map']: + resp = firewall_central_snat_map(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_central_snat_map": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comments": {"required": False, "type": "str"}, - "dst-addr": {"required": False, "type": "list", + "dst_addr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, @@ -333,16 +381,16 @@ def main(): }}, "nat": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "nat-ippool": {"required": False, "type": "list", + "nat_ippool": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "nat-port": {"required": False, "type": "str"}, - "orig-addr": {"required": False, "type": "list", + "nat_port": {"required": False, "type": "str"}, + "orig_addr": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "orig-port": {"required": False, "type": "str"}, + "orig_port": {"required": False, "type": "str"}, "policyid": {"required": True, "type": "int"}, "protocol": {"required": False, "type": "int"}, "srcintf": {"required": False, "type": "list", @@ -358,15 +406,30 @@ 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 = '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_dnstranslation.py b/lib/ansible/modules/network/fortios/fortios_firewall_dnstranslation.py index a8f574e6b98..60b6639bfb4 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_dnstranslation.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_dnstranslation.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_dnstranslation short_description: Configure DNS translation 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 dnstranslation 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 device by allowing the + user to set and modify firewall feature and dnstranslation 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,71 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_dnstranslation: description: - Configure DNS translation. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent dst: description: - IPv4 address or subnet on the external network to substitute for the resolved address in DNS query replies. Can be single IP address or subnet on the external network, but number of addresses must equal number of mapped IP addresses in src. + type: str id: description: - ID. required: true + type: int netmask: description: - If src and dst are subnets rather than single IP addresses, enter the netmask for both src and dst. + type: str src: description: - IPv4 address or subnet on the internal network to compare with the resolved address in DNS query replies. If the resolved address matches, the resolved address is substituted with dst. + type: str ''' EXAMPLES = ''' @@ -102,6 +115,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure DNS translation. fortios_firewall_dnstranslation: @@ -109,8 +123,9 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_dnstranslation: - state: "present" dst: "" id: "4" netmask: "" @@ -177,14 +192,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']: @@ -192,7 +209,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_dnstranslation_data(json): @@ -207,48 +224,66 @@ def filter_firewall_dnstranslation_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_dnstranslation(data, fos): vdom = data['vdom'] + state = data['state'] firewall_dnstranslation_data = data['firewall_dnstranslation'] - filtered_data = filter_firewall_dnstranslation_data(firewall_dnstranslation_data) - if firewall_dnstranslation_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_dnstranslation_data(firewall_dnstranslation_data)) + + if state == "present": return fos.set('firewall', 'dnstranslation', data=filtered_data, vdom=vdom) - elif firewall_dnstranslation_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'dnstranslation', 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_dnstranslation'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_dnstranslation']: + resp = firewall_dnstranslation(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_dnstranslation": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "dst": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"}, "netmask": {"required": False, "type": "str"}, @@ -260,15 +295,30 @@ 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 = '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_identity_based_route.py b/lib/ansible/modules/network/fortios/fortios_firewall_identity_based_route.py index df33add6532..55115ff7a7c 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_identity_based_route.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_identity_based_route.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_identity_based_route short_description: Configure identity based routing 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 identity_based_route 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 device by allowing the + user to set and modify firewall feature and identity_based_route 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,69 +41,89 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_identity_based_route: description: - Configure identity based routing. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comments: description: - Comments. + type: str name: description: - Name. required: true + type: str rule: description: - Rule. + type: list suboptions: device: description: - Outgoing interface for the rule. Source system.interface.name. + type: str gateway: description: - "IPv4 address of the gateway (Format: xxx.xxx.xxx.xxx , Default: 0.0.0.0)." + type: str groups: description: - Select one or more group(s) from available groups that are allowed to use this route. Separate group names with a space. + type: list suboptions: name: description: - Group name. Source user.group.name. required: true + type: str id: description: - Rule ID. required: true + type: int ''' EXAMPLES = ''' @@ -116,6 +133,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure identity based routing. fortios_firewall_identity_based_route: @@ -123,8 +141,9 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_identity_based_route: - state: "present" comments: "" name: "default_name_4" rule: @@ -197,14 +216,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']: @@ -212,7 +233,7 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_identity_based_route_data(json): @@ -226,48 +247,66 @@ def filter_firewall_identity_based_route_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_identity_based_route(data, fos): vdom = data['vdom'] + state = data['state'] firewall_identity_based_route_data = data['firewall_identity_based_route'] - filtered_data = filter_firewall_identity_based_route_data(firewall_identity_based_route_data) - if firewall_identity_based_route_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_identity_based_route_data(firewall_identity_based_route_data)) + + if state == "present": return fos.set('firewall', 'identity-based-route', data=filtered_data, vdom=vdom) - elif firewall_identity_based_route_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'identity-based-route', 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_identity_based_route'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_identity_based_route']: + resp = firewall_identity_based_route(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_identity_based_route": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comments": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, "rule": {"required": False, "type": "list", @@ -287,15 +326,30 @@ 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 = '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_interface_policy.py b/lib/ansible/modules/network/fortios/fortios_firewall_interface_policy.py index 15b78babf8c..dd0c7fe11c1 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_interface_policy.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_interface_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_interface_policy short_description: Configure IPv4 interface 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 interface_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 device by allowing the + user to set and modify firewall feature and interface_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,108 +41,136 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_interface_policy: description: - Configure IPv4 interface policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - address-type: + address_type: description: - Policy address type (IPv4 or IPv6). + type: str choices: - ipv4 - ipv6 - application-list: + application_list: description: - Application list name. Source application.list.name. - application-list-status: + type: str + application_list_status: description: - Enable/disable application control. + type: str choices: - enable - disable - av-profile: + av_profile: description: - Antivirus profile. Source antivirus.profile.name. - av-profile-status: + type: str + av_profile_status: description: - Enable/disable antivirus. + type: str choices: - enable - disable comments: description: - Comments. - dlp-sensor: + type: str + dlp_sensor: description: - DLP sensor name. Source dlp.sensor.name. - dlp-sensor-status: + type: str + dlp_sensor_status: description: - Enable/disable DLP. + type: str choices: - enable - disable dsri: description: - Enable/disable DSRI. + type: str choices: - enable - disable dstaddr: description: - Address object to limit traffic monitoring to network traffic sent to the specified address or range. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str interface: description: - Monitored interface name from available interfaces. Source system.zone.name system.interface.name. - ips-sensor: + type: str + ips_sensor: description: - IPS sensor name. Source ips.sensor.name. - ips-sensor-status: + type: str + ips_sensor_status: description: - Enable/disable IPS. + type: str choices: - enable - disable label: description: - Label. + type: str logtraffic: description: - "Logging type to be used in this policy (Options: all | utm | disable, Default: utm)." + type: str choices: - all - utm @@ -154,9 +179,11 @@ options: description: - Policy ID. required: true - scan-botnet-connections: + type: int + scan_botnet_connections: description: - Enable/disable scanning for connections to Botnet servers. + type: str choices: - disable - block @@ -164,40 +191,49 @@ options: service: description: - Service object from available options. + type: list suboptions: name: description: - Service name. Source firewall.service.custom.name firewall.service.group.name. required: true - spamfilter-profile: + type: str + spamfilter_profile: description: - Antispam profile. Source spamfilter.profile.name. - spamfilter-profile-status: + type: str + spamfilter_profile_status: description: - Enable/disable antispam. + type: str choices: - enable - disable srcaddr: description: - Address object to limit traffic monitoring to network traffic sent from the specified address or range. + type: list suboptions: name: description: - Address name. Source firewall.address.name firewall.addrgrp.name. required: true + type: str status: description: - Enable/disable this policy. + type: str choices: - enable - disable - webfilter-profile: + webfilter_profile: description: - Web filter profile. Source webfilter.profile.name. - webfilter-profile-status: + type: str + webfilter_profile_status: description: - Enable/disable web filtering. + type: str choices: - enable - disable @@ -210,6 +246,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv4 interface policies. fortios_firewall_interface_policy: @@ -217,38 +254,39 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_interface_policy: - state: "present" - address-type: "ipv4" - application-list: " (source application.list.name)" - application-list-status: "enable" - av-profile: " (source antivirus.profile.name)" - av-profile-status: "enable" + address_type: "ipv4" + application_list: " (source application.list.name)" + application_list_status: "enable" + av_profile: " (source antivirus.profile.name)" + av_profile_status: "enable" comments: "" - dlp-sensor: " (source dlp.sensor.name)" - dlp-sensor-status: "enable" + dlp_sensor: " (source dlp.sensor.name)" + dlp_sensor_status: "enable" dsri: "enable" dstaddr: - name: "default_name_13 (source firewall.address.name firewall.addrgrp.name)" interface: " (source system.zone.name system.interface.name)" - ips-sensor: " (source ips.sensor.name)" - ips-sensor-status: "enable" + ips_sensor: " (source ips.sensor.name)" + ips_sensor_status: "enable" label: "" logtraffic: "all" policyid: "19" - scan-botnet-connections: "disable" + scan_botnet_connections: "disable" service: - name: "default_name_22 (source firewall.service.custom.name firewall.service.group.name)" - spamfilter-profile: " (source spamfilter.profile.name)" - spamfilter-profile-status: "enable" + spamfilter_profile: " (source spamfilter.profile.name)" + spamfilter_profile_status: "enable" srcaddr: - name: "default_name_26 (source firewall.address.name firewall.addrgrp.name)" status: "enable" - webfilter-profile: " (source webfilter.profile.name)" - webfilter-profile-status: "enable" + webfilter_profile: " (source webfilter.profile.name)" + webfilter_profile_status: "enable" ''' RETURN = ''' @@ -311,14 +349,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -326,18 +366,18 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_interface_policy_data(json): - option_list = ['address-type', 'application-list', 'application-list-status', - 'av-profile', 'av-profile-status', 'comments', - 'dlp-sensor', 'dlp-sensor-status', 'dsri', - 'dstaddr', 'interface', 'ips-sensor', - 'ips-sensor-status', 'label', 'logtraffic', - 'policyid', 'scan-botnet-connections', 'service', - 'spamfilter-profile', 'spamfilter-profile-status', 'srcaddr', - 'status', 'webfilter-profile', 'webfilter-profile-status'] + option_list = ['address_type', 'application_list', 'application_list_status', + 'av_profile', 'av_profile_status', 'comments', + 'dlp_sensor', 'dlp_sensor_status', 'dsri', + 'dstaddr', 'interface', 'ips_sensor', + 'ips_sensor_status', 'label', 'logtraffic', + 'policyid', 'scan_botnet_connections', 'service', + 'spamfilter_profile', 'spamfilter_profile_status', 'srcaddr', + 'status', 'webfilter_profile', 'webfilter_profile_status'] dictionary = {} for attribute in option_list: @@ -347,59 +387,77 @@ def filter_firewall_interface_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_interface_policy(data, fos): vdom = data['vdom'] + state = data['state'] firewall_interface_policy_data = data['firewall_interface_policy'] - filtered_data = filter_firewall_interface_policy_data(firewall_interface_policy_data) - if firewall_interface_policy_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_interface_policy_data(firewall_interface_policy_data)) + + if state == "present": return fos.set('firewall', 'interface-policy', data=filtered_data, vdom=vdom) - elif firewall_interface_policy_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'interface-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_interface_policy'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_interface_policy']: + resp = firewall_interface_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_interface_policy": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "address-type": {"required": False, "type": "str", + "address_type": {"required": False, "type": "str", "choices": ["ipv4", "ipv6"]}, - "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"]}, "comments": {"required": False, "type": "str"}, - "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"]}, @@ -408,21 +466,21 @@ def main(): "name": {"required": True, "type": "str"} }}, "interface": {"required": False, "type": "str"}, - "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"]}, "label": {"required": False, "type": "str"}, "logtraffic": {"required": False, "type": "str", "choices": ["all", "utm", "disable"]}, "policyid": {"required": True, "type": "int"}, - "scan-botnet-connections": {"required": False, "type": "str", + "scan_botnet_connections": {"required": False, "type": "str", "choices": ["disable", "block", "monitor"]}, "service": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "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"]}, "srcaddr": {"required": False, "type": "list", "options": { @@ -430,8 +488,8 @@ def main(): }}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "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"]} } @@ -440,15 +498,30 @@ 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 = '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_interface_policy6.py b/lib/ansible/modules/network/fortios/fortios_firewall_interface_policy6.py index 3549d39075a..977bfdc9475 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_interface_policy6.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_interface_policy6.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_interface_policy6 short_description: Configure IPv6 interface 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 interface_policy6 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 device by allowing the + user to set and modify firewall feature and interface_policy6 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,108 +41,136 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_interface_policy6: description: - Configure IPv6 interface policies. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - address-type: + address_type: description: - Policy address type (IPv4 or IPv6). + type: str choices: - ipv4 - ipv6 - application-list: + application_list: description: - Application list name. Source application.list.name. - application-list-status: + type: str + application_list_status: description: - Enable/disable application control. + type: str choices: - enable - disable - av-profile: + av_profile: description: - Antivirus profile. Source antivirus.profile.name. - av-profile-status: + type: str + av_profile_status: description: - Enable/disable antivirus. + type: str choices: - enable - disable comments: description: - Comments. - dlp-sensor: + type: str + dlp_sensor: description: - DLP sensor name. Source dlp.sensor.name. - dlp-sensor-status: + type: str + dlp_sensor_status: description: - Enable/disable DLP. + type: str choices: - enable - disable dsri: description: - Enable/disable DSRI. + type: str choices: - enable - disable dstaddr6: description: - IPv6 address object to limit traffic monitoring to network traffic sent to the specified address or range. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str interface: description: - Monitored interface name from available interfaces. Source system.zone.name system.interface.name. - ips-sensor: + type: str + ips_sensor: description: - IPS sensor name. Source ips.sensor.name. - ips-sensor-status: + type: str + ips_sensor_status: description: - Enable/disable IPS. + type: str choices: - enable - disable label: description: - Label. + type: str logtraffic: description: - "Logging type to be used in this policy (Options: all | utm | disable, Default: utm)." + type: str choices: - all - utm @@ -154,9 +179,11 @@ options: description: - Policy ID. required: true - scan-botnet-connections: + type: int + scan_botnet_connections: description: - Enable/disable scanning for connections to Botnet servers. + type: str choices: - disable - block @@ -164,40 +191,49 @@ options: service6: description: - Service name. + type: list suboptions: name: description: - Address name. Source firewall.service.custom.name firewall.service.group.name. required: true - spamfilter-profile: + type: str + spamfilter_profile: description: - Antispam profile. Source spamfilter.profile.name. - spamfilter-profile-status: + type: str + spamfilter_profile_status: description: - Enable/disable antispam. + type: str choices: - enable - disable srcaddr6: description: - IPv6 address object to limit traffic monitoring to network traffic sent from the specified address or range. + type: list suboptions: name: description: - Address name. Source firewall.address6.name firewall.addrgrp6.name. required: true + type: str status: description: - Enable/disable this policy. + type: str choices: - enable - disable - webfilter-profile: + webfilter_profile: description: - Web filter profile. Source webfilter.profile.name. - webfilter-profile-status: + type: str + webfilter_profile_status: description: - Enable/disable web filtering. + type: str choices: - enable - disable @@ -210,6 +246,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure IPv6 interface policies. fortios_firewall_interface_policy6: @@ -217,38 +254,39 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_interface_policy6: - state: "present" - address-type: "ipv4" - application-list: " (source application.list.name)" - application-list-status: "enable" - av-profile: " (source antivirus.profile.name)" - av-profile-status: "enable" + address_type: "ipv4" + application_list: " (source application.list.name)" + application_list_status: "enable" + av_profile: " (source antivirus.profile.name)" + av_profile_status: "enable" comments: "" - dlp-sensor: " (source dlp.sensor.name)" - dlp-sensor-status: "enable" + dlp_sensor: " (source dlp.sensor.name)" + dlp_sensor_status: "enable" dsri: "enable" dstaddr6: - name: "default_name_13 (source firewall.address6.name firewall.addrgrp6.name)" interface: " (source system.zone.name system.interface.name)" - ips-sensor: " (source ips.sensor.name)" - ips-sensor-status: "enable" + ips_sensor: " (source ips.sensor.name)" + ips_sensor_status: "enable" label: "" logtraffic: "all" policyid: "19" - scan-botnet-connections: "disable" + scan_botnet_connections: "disable" service6: - name: "default_name_22 (source firewall.service.custom.name firewall.service.group.name)" - spamfilter-profile: " (source spamfilter.profile.name)" - spamfilter-profile-status: "enable" + spamfilter_profile: " (source spamfilter.profile.name)" + spamfilter_profile_status: "enable" srcaddr6: - name: "default_name_26 (source firewall.address6.name firewall.addrgrp6.name)" status: "enable" - webfilter-profile: " (source webfilter.profile.name)" - webfilter-profile-status: "enable" + webfilter_profile: " (source webfilter.profile.name)" + webfilter_profile_status: "enable" ''' RETURN = ''' @@ -311,14 +349,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -326,18 +366,18 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_interface_policy6_data(json): - option_list = ['address-type', 'application-list', 'application-list-status', - 'av-profile', 'av-profile-status', 'comments', - 'dlp-sensor', 'dlp-sensor-status', 'dsri', - 'dstaddr6', 'interface', 'ips-sensor', - 'ips-sensor-status', 'label', 'logtraffic', - 'policyid', 'scan-botnet-connections', 'service6', - 'spamfilter-profile', 'spamfilter-profile-status', 'srcaddr6', - 'status', 'webfilter-profile', 'webfilter-profile-status'] + option_list = ['address_type', 'application_list', 'application_list_status', + 'av_profile', 'av_profile_status', 'comments', + 'dlp_sensor', 'dlp_sensor_status', 'dsri', + 'dstaddr6', 'interface', 'ips_sensor', + 'ips_sensor_status', 'label', 'logtraffic', + 'policyid', 'scan_botnet_connections', 'service6', + 'spamfilter_profile', 'spamfilter_profile_status', 'srcaddr6', + 'status', 'webfilter_profile', 'webfilter_profile_status'] dictionary = {} for attribute in option_list: @@ -347,59 +387,77 @@ def filter_firewall_interface_policy6_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_interface_policy6(data, fos): vdom = data['vdom'] + state = data['state'] firewall_interface_policy6_data = data['firewall_interface_policy6'] - filtered_data = filter_firewall_interface_policy6_data(firewall_interface_policy6_data) - if firewall_interface_policy6_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_interface_policy6_data(firewall_interface_policy6_data)) + + if state == "present": return fos.set('firewall', 'interface-policy6', data=filtered_data, vdom=vdom) - elif firewall_interface_policy6_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'interface-policy6', 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_interface_policy6'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_interface_policy6']: + resp = firewall_interface_policy6(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_interface_policy6": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "address-type": {"required": False, "type": "str", + "address_type": {"required": False, "type": "str", "choices": ["ipv4", "ipv6"]}, - "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"]}, "comments": {"required": False, "type": "str"}, - "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"]}, @@ -408,21 +466,21 @@ def main(): "name": {"required": True, "type": "str"} }}, "interface": {"required": False, "type": "str"}, - "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"]}, "label": {"required": False, "type": "str"}, "logtraffic": {"required": False, "type": "str", "choices": ["all", "utm", "disable"]}, "policyid": {"required": True, "type": "int"}, - "scan-botnet-connections": {"required": False, "type": "str", + "scan_botnet_connections": {"required": False, "type": "str", "choices": ["disable", "block", "monitor"]}, "service6": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "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"]}, "srcaddr6": {"required": False, "type": "list", "options": { @@ -430,8 +488,8 @@ def main(): }}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "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"]} } @@ -440,15 +498,30 @@ 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 = '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_internet_service.py b/lib/ansible/modules/network/fortios/fortios_firewall_internet_service.py index 3ebdc5f5440..7c588636d31 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_internet_service.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_internet_service.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_internet_service short_description: Show Internet Service application 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 internet_service 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 device by allowing the + user to set and modify firewall feature and internet_service 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,49 +41,63 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_internet_service: description: - Show Internet Service application. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent database: description: - Database name this Internet Service belongs to. + type: str choices: - isdb - irdb direction: description: - How this service may be used in a firewall policy (source, destination or both). + type: str choices: - src - dst @@ -94,42 +105,54 @@ options: entry: description: - Entries in the Internet Service database. + type: list suboptions: id: description: - Entry ID. required: true - ip-number: + type: int + ip_number: description: - Total number of IP addresses. - ip-range-number: + type: int + ip_range_number: description: - Total number of IP ranges. + type: int port: description: - Integer value for the TCP/IP port (0 - 65535). + type: int protocol: description: - Integer value for the protocol type as defined by IANA (0 - 255). - icon-id: + type: int + icon_id: description: - Icon ID of Internet Service. + type: int id: description: - Internet Service ID. required: true + type: int name: description: - Internet Service name. + type: str offset: description: - Offset of Internet Service ID. + type: int reputation: description: - Reputation level of the Internet Service. - sld-id: + type: int + sld_id: description: - Second Level Domain. + type: int ''' EXAMPLES = ''' @@ -139,6 +162,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Show Internet Service application. fortios_firewall_internet_service: @@ -146,23 +170,24 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_internet_service: - state: "present" database: "isdb" direction: "src" entry: - id: "6" - ip-number: "7" - ip-range-number: "8" + ip_number: "7" + ip_range_number: "8" port: "9" protocol: "10" - icon-id: "11" + icon_id: "11" id: "12" name: "default_name_13" offset: "14" reputation: "15" - sld-id: "16" + sld_id: "16" ''' RETURN = ''' @@ -225,14 +250,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule +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 -fos = None - -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']: @@ -240,13 +267,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_internet_service_data(json): option_list = ['database', 'direction', 'entry', - 'icon-id', 'id', 'name', - 'offset', 'reputation', 'sld-id'] + 'icon_id', 'id', 'name', + 'offset', 'reputation', 'sld_id'] dictionary = {} for attribute in option_list: @@ -256,48 +283,66 @@ def filter_firewall_internet_service_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_internet_service(data, fos): vdom = data['vdom'] + state = data['state'] firewall_internet_service_data = data['firewall_internet_service'] - filtered_data = filter_firewall_internet_service_data(firewall_internet_service_data) - if firewall_internet_service_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_internet_service_data(firewall_internet_service_data)) + + if state == "present": return fos.set('firewall', 'internet-service', data=filtered_data, vdom=vdom) - elif firewall_internet_service_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'internet-service', 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_internet_service'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_internet_service']: + resp = firewall_internet_service(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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_internet_service": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "database": {"required": False, "type": "str", "choices": ["isdb", "irdb"]}, "direction": {"required": False, "type": "str", @@ -305,17 +350,17 @@ def main(): "entry": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "ip-number": {"required": False, "type": "int"}, - "ip-range-number": {"required": False, "type": "int"}, + "ip_number": {"required": False, "type": "int"}, + "ip_range_number": {"required": False, "type": "int"}, "port": {"required": False, "type": "int"}, "protocol": {"required": False, "type": "int"} }}, - "icon-id": {"required": False, "type": "int"}, + "icon_id": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, "name": {"required": False, "type": "str"}, "offset": {"required": False, "type": "int"}, "reputation": {"required": False, "type": "int"}, - "sld-id": {"required": False, "type": "int"} + "sld_id": {"required": False, "type": "int"} } } @@ -323,15 +368,30 @@ 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 = '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_internet_service_custom.py b/lib/ansible/modules/network/fortios/fortios_firewall_internet_service_custom.py index 4bee73c7967..5f58c97ead0 100644 --- a/lib/ansible/modules/network/fortios/fortios_firewall_internet_service_custom.py +++ b/lib/ansible/modules/network/fortios/fortios_firewall_internet_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_internet_service_custom short_description: Configure custom Internet 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 feature and internet_service_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 device by allowing the + user to set and modify firewall feature and internet_service_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,112 +41,144 @@ 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: false + 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 + choices: + - present + - absent + version_added: 2.9 firewall_internet_service_custom: description: - Configure custom Internet Services. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comment: description: - Comment. - disable-entry: + type: str + disable_entry: description: - Disable entries in the Internet Service database. + type: list suboptions: id: description: - Disable entry ID. required: true - ip-range: + type: int + ip_range: description: - IP ranges in the disable entry. + type: list suboptions: - end-ip: + end_ip: description: - End IP address. + type: str id: description: - Disable entry range ID. required: true - start-ip: + type: int + start_ip: description: - Start IP address. + type: str port: description: - Integer value for the TCP/IP port (0 - 65535). + type: int protocol: description: - Integer value for the protocol type as defined by IANA (0 - 255). + type: int entry: description: - Entries added to the Internet Service database and custom database. + type: list suboptions: dst: description: - Destination address or address group name. + type: list suboptions: name: description: - Select the destination address or address group object from available options. Source firewall.address.name firewall .addrgrp.name. required: true + type: str id: description: - Entry ID(1-255). required: true - port-range: + type: int + port_range: description: - Port ranges in the custom entry. + type: list suboptions: - end-port: + end_port: description: - Integer value for ending TCP/UDP/SCTP destination port in range (1 to 65535). + type: int id: description: - Custom entry port range ID. required: true - start-port: + type: int + start_port: description: - Integer value for starting TCP/UDP/SCTP destination port in range (1 to 65535). + type: int protocol: description: - Integer value for the protocol type as defined by IANA (0 - 255). - master-service-id: + type: int + master_service_id: description: - Internet Service ID in the Internet Service database. Source firewall.internet-service.id. + type: int name: description: - Internet Service name. required: true + type: str ''' EXAMPLES = ''' @@ -159,6 +188,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure custom Internet Services. fortios_firewall_internet_service_custom: @@ -166,17 +196,18 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" vdom: "{{ vdom }}" + https: "False" + state: "present" firewall_internet_service_custom: - state: "present" comment: "Comment." - disable-entry: + disable_entry: - id: "5" - ip-range: + ip_range: - - end-ip: "" + end_ip: "" id: "8" - start-ip: "" + start_ip: "" port: "10" protocol: "11" entry: @@ -185,13 +216,13 @@ EXAMPLES = ''' - name: "default_name_14 (source firewall.address.name firewall.addrgrp.name)" id: "15" - port-range: + port_range: - - end-port: "17" + end_port: "17" id: "18" - start-port: "19" + start_port: "19" protocol: "20" - master-service-id: "21 (source firewall.internet-service.id)" + master_service_id: "21 (source firewall.internet-service.id)" name: "default_name_22" ''' @@ -255,14 +286,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']: @@ -270,12 +303,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_firewall_internet_service_custom_data(json): - option_list = ['comment', 'disable-entry', 'entry', - 'master-service-id', 'name'] + option_list = ['comment', 'disable_entry', 'entry', + 'master_service_id', 'name'] dictionary = {} for attribute in option_list: @@ -285,57 +318,75 @@ def filter_firewall_internet_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_internet_service_custom(data, fos): vdom = data['vdom'] + state = data['state'] firewall_internet_service_custom_data = data['firewall_internet_service_custom'] - filtered_data = filter_firewall_internet_service_custom_data(firewall_internet_service_custom_data) - if firewall_internet_service_custom_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_firewall_internet_service_custom_data(firewall_internet_service_custom_data)) + + if state == "present": return fos.set('firewall', 'internet-service-custom', data=filtered_data, vdom=vdom) - elif firewall_internet_service_custom_data['state'] == "absent": + elif state == "absent": return fos.delete('firewall', 'internet-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(data, fos): - login(data) - methodlist = ['firewall_internet_service_custom'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['firewall_internet_service_custom']: + resp = firewall_internet_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"}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, "password": {"required": False, "type": "str", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "firewall_internet_service_custom": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comment": {"required": False, "type": "str"}, - "disable-entry": {"required": False, "type": "list", + "disable_entry": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "ip-range": {"required": False, "type": "list", + "ip_range": {"required": False, "type": "list", "options": { - "end-ip": {"required": False, "type": "str"}, + "end_ip": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"}, - "start-ip": {"required": False, "type": "str"} + "start_ip": {"required": False, "type": "str"} }}, "port": {"required": False, "type": "int"}, "protocol": {"required": False, "type": "int"} @@ -347,15 +398,15 @@ def main(): "name": {"required": True, "type": "str"} }}, "id": {"required": True, "type": "int"}, - "port-range": {"required": False, "type": "list", + "port_range": {"required": False, "type": "list", "options": { - "end-port": {"required": False, "type": "int"}, + "end_port": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, - "start-port": {"required": False, "type": "int"} + "start_port": {"required": False, "type": "int"} }}, "protocol": {"required": False, "type": "int"} }}, - "master-service-id": {"required": False, "type": "int"}, + "master_service_id": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"} } @@ -364,15 +415,30 @@ 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 = '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/test/sanity/ignore.txt b/test/sanity/ignore.txt index cabb65470af..0415dc38f17 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -3693,43 +3693,8 @@ lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E324 lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E338 lib/ansible/modules/network/fortios/fortios_antivirus_quarantine.py validate-modules:E326 lib/ansible/modules/network/fortios/fortios_config.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_endpoint_control_profile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_endpoint_control_profile.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_endpoint_control_settings.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_endpoint_control_settings.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_extender_controller_extender.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_extender_controller_extender.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_policy.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_address.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_address.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_address6.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_address6.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_address6_template.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_address6_template.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_addrgrp.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_addrgrp.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_addrgrp6.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_auth_portal.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_auth_portal.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_central_snat_map.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_central_snat_map.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_dnstranslation.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_identity_based_route.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_interface_policy.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_interface_policy.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_interface_policy6.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_interface_policy6.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_internet_service.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_internet_service.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_firewall_internet_service_custom.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_firewall_internet_service_custom.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_internet_service_group.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_firewall_ip_translation.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_firewall_ip_translation.py validate-modules:E337 diff --git a/test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_ems.py b/test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_ems.py new file mode 100644 index 00000000000..2328910decb --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_ems.py @@ -0,0 +1,289 @@ +# 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_endpoint_control_forticlient_ems +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_endpoint_control_forticlient_ems.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'address': 'test_value_3', + 'admin-password': 'test_value_4', + 'admin-type': 'Windows', + 'admin-username': 'test_value_6', + 'https-port': '7', + 'listen-port': '8', + 'name': 'default_name_9', + 'rest-api-auth': 'disable', + 'serial-number': 'test_value_11', + 'upload-port': '12' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'address': 'test_value_3', + 'admin-password': 'test_value_4', + 'admin-type': 'Windows', + 'admin-username': 'test_value_6', + 'https-port': '7', + 'listen-port': '8', + 'name': 'default_name_9', + 'rest-api-auth': 'disable', + 'serial-number': 'test_value_11', + 'upload-port': '12' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'address': 'test_value_3', + 'admin-password': 'test_value_4', + 'admin-type': 'Windows', + 'admin-username': 'test_value_6', + 'https-port': '7', + 'listen-port': '8', + 'name': 'default_name_9', + 'rest-api-auth': 'disable', + 'serial-number': 'test_value_11', + 'upload-port': '12' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_ems_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', + 'endpoint_control_forticlient_ems': { + 'random_attribute_not_valid': 'tag', + 'address': 'test_value_3', + 'admin_password': 'test_value_4', + 'admin_type': 'Windows', + 'admin_username': 'test_value_6', + 'https_port': '7', + 'listen_port': '8', + 'name': 'default_name_9', + 'rest_api_auth': 'disable', + 'serial_number': 'test_value_11', + 'upload_port': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_ems.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'address': 'test_value_3', + 'admin-password': 'test_value_4', + 'admin-type': 'Windows', + 'admin-username': 'test_value_6', + 'https-port': '7', + 'listen-port': '8', + 'name': 'default_name_9', + 'rest-api-auth': 'disable', + 'serial-number': 'test_value_11', + 'upload-port': '12' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-ems', 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_endpoint_control_forticlient_registration_sync.py b/test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_registration_sync.py new file mode 100644 index 00000000000..571f8454626 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_endpoint_control_forticlient_registration_sync.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_endpoint_control_forticlient_registration_sync +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_endpoint_control_forticlient_registration_sync.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'peer-ip': 'test_value_3', + 'peer-name': 'test_value_4' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'peer-ip': 'test_value_3', + 'peer-name': 'test_value_4' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'peer-ip': 'test_value_3', + 'peer-name': 'test_value_4' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_forticlient_registration_sync_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', + 'endpoint_control_forticlient_registration_sync': { + 'random_attribute_not_valid': 'tag', + 'peer_ip': 'test_value_3', + 'peer_name': 'test_value_4' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_forticlient_registration_sync.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'peer-ip': 'test_value_3', + 'peer-name': 'test_value_4' + } + + set_method_mock.assert_called_with('endpoint-control', 'forticlient-registration-sync', 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_endpoint_control_profile.py b/test/units/modules/network/fortios/test_fortios_endpoint_control_profile.py new file mode 100644 index 00000000000..2f97cf1c6d6 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_endpoint_control_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_endpoint_control_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_endpoint_control_profile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_endpoint_control_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', + 'endpoint_control_profile': { + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'description': 'test_value_3', + 'profile-name': 'test_value_4', + 'replacemsg-override-group': 'test_value_5', + + } + + set_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_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', + 'endpoint_control_profile': { + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'description': 'test_value_3', + 'profile-name': 'test_value_4', + 'replacemsg-override-group': 'test_value_5', + + } + + set_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_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', + 'endpoint_control_profile': { + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_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', + 'endpoint_control_profile': { + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + delete_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_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', + 'endpoint_control_profile': { + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'description': 'test_value_3', + 'profile-name': 'test_value_4', + 'replacemsg-override-group': 'test_value_5', + + } + + set_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_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', + 'endpoint_control_profile': { + 'random_attribute_not_valid': 'tag', + 'description': 'test_value_3', + 'profile_name': 'test_value_4', + 'replacemsg_override_group': 'test_value_5', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_profile.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'description': 'test_value_3', + 'profile-name': 'test_value_4', + 'replacemsg-override-group': 'test_value_5', + + } + + set_method_mock.assert_called_with('endpoint-control', '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_endpoint_control_settings.py b/test/units/modules/network/fortios/test_fortios_endpoint_control_settings.py new file mode 100644 index 00000000000..a8289860d84 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_endpoint_control_settings.py @@ -0,0 +1,255 @@ +# 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_endpoint_control_settings +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_endpoint_control_settings.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_endpoint_control_settings_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', + 'endpoint_control_settings': { + 'download_custom_link': 'test_value_3', + 'download_location': 'fortiguard', + 'forticlient_avdb_update_interval': '5', + 'forticlient_dereg_unsupported_client': 'enable', + 'forticlient_ems_rest_api_call_timeout': '7', + 'forticlient_keepalive_interval': '8', + 'forticlient_offline_grace': 'enable', + 'forticlient_offline_grace_interval': '10', + 'forticlient_reg_key': 'test_value_11', + 'forticlient_reg_key_enforce': 'enable', + 'forticlient_reg_timeout': '13', + 'forticlient_sys_update_interval': '14', + 'forticlient_user_avatar': 'enable', + 'forticlient_warning_interval': '16' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_settings.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'download-custom-link': 'test_value_3', + 'download-location': 'fortiguard', + 'forticlient-avdb-update-interval': '5', + 'forticlient-dereg-unsupported-client': 'enable', + 'forticlient-ems-rest-api-call-timeout': '7', + 'forticlient-keepalive-interval': '8', + 'forticlient-offline-grace': 'enable', + 'forticlient-offline-grace-interval': '10', + 'forticlient-reg-key': 'test_value_11', + 'forticlient-reg-key-enforce': 'enable', + 'forticlient-reg-timeout': '13', + 'forticlient-sys-update-interval': '14', + 'forticlient-user-avatar': 'enable', + 'forticlient-warning-interval': '16' + } + + set_method_mock.assert_called_with('endpoint-control', 'settings', 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_endpoint_control_settings_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', + 'endpoint_control_settings': { + 'download_custom_link': 'test_value_3', + 'download_location': 'fortiguard', + 'forticlient_avdb_update_interval': '5', + 'forticlient_dereg_unsupported_client': 'enable', + 'forticlient_ems_rest_api_call_timeout': '7', + 'forticlient_keepalive_interval': '8', + 'forticlient_offline_grace': 'enable', + 'forticlient_offline_grace_interval': '10', + 'forticlient_reg_key': 'test_value_11', + 'forticlient_reg_key_enforce': 'enable', + 'forticlient_reg_timeout': '13', + 'forticlient_sys_update_interval': '14', + 'forticlient_user_avatar': 'enable', + 'forticlient_warning_interval': '16' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_settings.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'download-custom-link': 'test_value_3', + 'download-location': 'fortiguard', + 'forticlient-avdb-update-interval': '5', + 'forticlient-dereg-unsupported-client': 'enable', + 'forticlient-ems-rest-api-call-timeout': '7', + 'forticlient-keepalive-interval': '8', + 'forticlient-offline-grace': 'enable', + 'forticlient-offline-grace-interval': '10', + 'forticlient-reg-key': 'test_value_11', + 'forticlient-reg-key-enforce': 'enable', + 'forticlient-reg-timeout': '13', + 'forticlient-sys-update-interval': '14', + 'forticlient-user-avatar': 'enable', + 'forticlient-warning-interval': '16' + } + + set_method_mock.assert_called_with('endpoint-control', 'settings', 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_endpoint_control_settings_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', + 'endpoint_control_settings': { + 'download_custom_link': 'test_value_3', + 'download_location': 'fortiguard', + 'forticlient_avdb_update_interval': '5', + 'forticlient_dereg_unsupported_client': 'enable', + 'forticlient_ems_rest_api_call_timeout': '7', + 'forticlient_keepalive_interval': '8', + 'forticlient_offline_grace': 'enable', + 'forticlient_offline_grace_interval': '10', + 'forticlient_reg_key': 'test_value_11', + 'forticlient_reg_key_enforce': 'enable', + 'forticlient_reg_timeout': '13', + 'forticlient_sys_update_interval': '14', + 'forticlient_user_avatar': 'enable', + 'forticlient_warning_interval': '16' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_settings.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'download-custom-link': 'test_value_3', + 'download-location': 'fortiguard', + 'forticlient-avdb-update-interval': '5', + 'forticlient-dereg-unsupported-client': 'enable', + 'forticlient-ems-rest-api-call-timeout': '7', + 'forticlient-keepalive-interval': '8', + 'forticlient-offline-grace': 'enable', + 'forticlient-offline-grace-interval': '10', + 'forticlient-reg-key': 'test_value_11', + 'forticlient-reg-key-enforce': 'enable', + 'forticlient-reg-timeout': '13', + 'forticlient-sys-update-interval': '14', + 'forticlient-user-avatar': 'enable', + 'forticlient-warning-interval': '16' + } + + set_method_mock.assert_called_with('endpoint-control', 'settings', 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_endpoint_control_settings_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', + 'endpoint_control_settings': { + 'random_attribute_not_valid': 'tag', + 'download_custom_link': 'test_value_3', + 'download_location': 'fortiguard', + 'forticlient_avdb_update_interval': '5', + 'forticlient_dereg_unsupported_client': 'enable', + 'forticlient_ems_rest_api_call_timeout': '7', + 'forticlient_keepalive_interval': '8', + 'forticlient_offline_grace': 'enable', + 'forticlient_offline_grace_interval': '10', + 'forticlient_reg_key': 'test_value_11', + 'forticlient_reg_key_enforce': 'enable', + 'forticlient_reg_timeout': '13', + 'forticlient_sys_update_interval': '14', + 'forticlient_user_avatar': 'enable', + 'forticlient_warning_interval': '16' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_endpoint_control_settings.fortios_endpoint_control(input_data, fos_instance) + + expected_data = { + 'download-custom-link': 'test_value_3', + 'download-location': 'fortiguard', + 'forticlient-avdb-update-interval': '5', + 'forticlient-dereg-unsupported-client': 'enable', + 'forticlient-ems-rest-api-call-timeout': '7', + 'forticlient-keepalive-interval': '8', + 'forticlient-offline-grace': 'enable', + 'forticlient-offline-grace-interval': '10', + 'forticlient-reg-key': 'test_value_11', + 'forticlient-reg-key-enforce': 'enable', + 'forticlient-reg-timeout': '13', + 'forticlient-sys-update-interval': '14', + 'forticlient-user-avatar': 'enable', + 'forticlient-warning-interval': '16' + } + + set_method_mock.assert_called_with('endpoint-control', 'settings', 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_extender_controller_extender.py b/test/units/modules/network/fortios/test_fortios_extender_controller_extender.py new file mode 100644 index 00000000000..7d3bd9e108c --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_extender_controller_extender.py @@ -0,0 +1,559 @@ +# 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_extender_controller_extender +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_extender_controller_extender.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_extender_controller_extender_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', + 'extender_controller_extender': { + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + expected_data = { + 'aaa-shared-secret': 'test_value_3', + 'access-point-name': 'test_value_4', + 'admin': 'disable', + 'at-dial-script': 'test_value_6', + 'billing-start-day': '7', + 'cdma-aaa-spi': 'test_value_8', + 'cdma-ha-spi': 'test_value_9', + 'cdma-nai': 'test_value_10', + 'conn-status': '11', + 'description': 'test_value_12', + 'dial-mode': 'dial-on-demand', + 'dial-status': '14', + 'ext-name': 'test_value_15', + 'ha-shared-secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated-update': 'enable', + 'mode': 'standalone', + 'modem-passwd': 'test_value_21', + 'modem-type': 'cdma', + 'multi-mode': 'auto', + 'ppp-auth-protocol': 'auto', + 'ppp-echo-request': 'enable', + 'ppp-password': 'test_value_26', + 'ppp-username': 'test_value_27', + 'primary-ha': 'test_value_28', + 'quota-limit-mb': '29', + 'redial': 'none', + 'redundant-intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary-ha': 'test_value_34', + 'sim-pin': 'test_value_35', + 'vdom': '36', + 'wimax-auth-protocol': 'tls', + 'wimax-carrier': 'test_value_38', + 'wimax-realm': 'test_value_39' + } + + set_method_mock.assert_called_with('extender-controller', 'extender', 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_extender_controller_extender_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', + 'extender_controller_extender': { + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + expected_data = { + 'aaa-shared-secret': 'test_value_3', + 'access-point-name': 'test_value_4', + 'admin': 'disable', + 'at-dial-script': 'test_value_6', + 'billing-start-day': '7', + 'cdma-aaa-spi': 'test_value_8', + 'cdma-ha-spi': 'test_value_9', + 'cdma-nai': 'test_value_10', + 'conn-status': '11', + 'description': 'test_value_12', + 'dial-mode': 'dial-on-demand', + 'dial-status': '14', + 'ext-name': 'test_value_15', + 'ha-shared-secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated-update': 'enable', + 'mode': 'standalone', + 'modem-passwd': 'test_value_21', + 'modem-type': 'cdma', + 'multi-mode': 'auto', + 'ppp-auth-protocol': 'auto', + 'ppp-echo-request': 'enable', + 'ppp-password': 'test_value_26', + 'ppp-username': 'test_value_27', + 'primary-ha': 'test_value_28', + 'quota-limit-mb': '29', + 'redial': 'none', + 'redundant-intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary-ha': 'test_value_34', + 'sim-pin': 'test_value_35', + 'vdom': '36', + 'wimax-auth-protocol': 'tls', + 'wimax-carrier': 'test_value_38', + 'wimax-realm': 'test_value_39' + } + + set_method_mock.assert_called_with('extender-controller', 'extender', 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_extender_controller_extender_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', + 'extender_controller_extender': { + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('extender-controller', 'extender', 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_extender_controller_extender_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', + 'extender_controller_extender': { + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('extender-controller', 'extender', 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_extender_controller_extender_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', + 'extender_controller_extender': { + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + expected_data = { + 'aaa-shared-secret': 'test_value_3', + 'access-point-name': 'test_value_4', + 'admin': 'disable', + 'at-dial-script': 'test_value_6', + 'billing-start-day': '7', + 'cdma-aaa-spi': 'test_value_8', + 'cdma-ha-spi': 'test_value_9', + 'cdma-nai': 'test_value_10', + 'conn-status': '11', + 'description': 'test_value_12', + 'dial-mode': 'dial-on-demand', + 'dial-status': '14', + 'ext-name': 'test_value_15', + 'ha-shared-secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated-update': 'enable', + 'mode': 'standalone', + 'modem-passwd': 'test_value_21', + 'modem-type': 'cdma', + 'multi-mode': 'auto', + 'ppp-auth-protocol': 'auto', + 'ppp-echo-request': 'enable', + 'ppp-password': 'test_value_26', + 'ppp-username': 'test_value_27', + 'primary-ha': 'test_value_28', + 'quota-limit-mb': '29', + 'redial': 'none', + 'redundant-intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary-ha': 'test_value_34', + 'sim-pin': 'test_value_35', + 'vdom': '36', + 'wimax-auth-protocol': 'tls', + 'wimax-carrier': 'test_value_38', + 'wimax-realm': 'test_value_39' + } + + set_method_mock.assert_called_with('extender-controller', 'extender', 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_extender_controller_extender_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', + 'extender_controller_extender': { + 'random_attribute_not_valid': 'tag', + 'aaa_shared_secret': 'test_value_3', + 'access_point_name': 'test_value_4', + 'admin': 'disable', + 'at_dial_script': 'test_value_6', + 'billing_start_day': '7', + 'cdma_aaa_spi': 'test_value_8', + 'cdma_ha_spi': 'test_value_9', + 'cdma_nai': 'test_value_10', + 'conn_status': '11', + 'description': 'test_value_12', + 'dial_mode': 'dial-on-demand', + 'dial_status': '14', + 'ext_name': 'test_value_15', + 'ha_shared_secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated_update': 'enable', + 'mode': 'standalone', + 'modem_passwd': 'test_value_21', + 'modem_type': 'cdma', + 'multi_mode': 'auto', + 'ppp_auth_protocol': 'auto', + 'ppp_echo_request': 'enable', + 'ppp_password': 'test_value_26', + 'ppp_username': 'test_value_27', + 'primary_ha': 'test_value_28', + 'quota_limit_mb': '29', + 'redial': 'none', + 'redundant_intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary_ha': 'test_value_34', + 'sim_pin': 'test_value_35', + 'vdom': '36', + 'wimax_auth_protocol': 'tls', + 'wimax_carrier': 'test_value_38', + 'wimax_realm': 'test_value_39' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_extender_controller_extender.fortios_extender_controller(input_data, fos_instance) + + expected_data = { + 'aaa-shared-secret': 'test_value_3', + 'access-point-name': 'test_value_4', + 'admin': 'disable', + 'at-dial-script': 'test_value_6', + 'billing-start-day': '7', + 'cdma-aaa-spi': 'test_value_8', + 'cdma-ha-spi': 'test_value_9', + 'cdma-nai': 'test_value_10', + 'conn-status': '11', + 'description': 'test_value_12', + 'dial-mode': 'dial-on-demand', + 'dial-status': '14', + 'ext-name': 'test_value_15', + 'ha-shared-secret': 'test_value_16', + 'id': '17', + 'ifname': 'test_value_18', + 'initiated-update': 'enable', + 'mode': 'standalone', + 'modem-passwd': 'test_value_21', + 'modem-type': 'cdma', + 'multi-mode': 'auto', + 'ppp-auth-protocol': 'auto', + 'ppp-echo-request': 'enable', + 'ppp-password': 'test_value_26', + 'ppp-username': 'test_value_27', + 'primary-ha': 'test_value_28', + 'quota-limit-mb': '29', + 'redial': 'none', + 'redundant-intf': 'test_value_31', + 'roaming': 'enable', + 'role': 'none', + 'secondary-ha': 'test_value_34', + 'sim-pin': 'test_value_35', + 'vdom': '36', + 'wimax-auth-protocol': 'tls', + 'wimax-carrier': 'test_value_38', + 'wimax-realm': 'test_value_39' + } + + set_method_mock.assert_called_with('extender-controller', 'extender', 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_DoS_policy.py b/test/units/modules/network/fortios/test_fortios_firewall_DoS_policy.py new file mode 100644 index 00000000000..428843a453a --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_DoS_policy.py @@ -0,0 +1,219 @@ +# 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_DoS_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_DoS_policy.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_DoS_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_DoS_policy': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-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_DoS_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_DoS_policy': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-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_DoS_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_DoS_policy': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'DoS-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_DoS_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_DoS_policy': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'DoS-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_DoS_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_DoS_policy': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-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_DoS_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_DoS_policy': { + 'random_attribute_not_valid': 'tag', 'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-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_DoS_policy6.py b/test/units/modules/network/fortios/test_fortios_firewall_DoS_policy6.py new file mode 100644 index 00000000000..02c87150b15 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_DoS_policy6.py @@ -0,0 +1,219 @@ +# 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_DoS_policy6 +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_DoS_policy6.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_DoS_policy6_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_DoS_policy6': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_DoS_policy6_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_DoS_policy6': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_DoS_policy6_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_DoS_policy6': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_DoS_policy6_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_DoS_policy6': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_DoS_policy6_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_DoS_policy6': {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_DoS_policy6_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_DoS_policy6': { + 'random_attribute_not_valid': 'tag', 'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_DoS_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = {'comments': 'test_value_3', + 'interface': 'test_value_4', + 'policyid': '5', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'DoS-policy6', 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_address.py b/test/units/modules/network/fortios/test_fortios_firewall_address.py new file mode 100644 index 00000000000..ca164d8c119 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_address.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_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_address.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_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_address': { + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'associated-interface': 'test_value_4', + 'cache-ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end-ip': 'test_value_9', + 'epg-name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj-id': 'test_value_14', + 'organization': 'test_value_15', + 'policy-group': 'test_value_16', + 'sdn': 'aci', + 'sdn-tag': 'test_value_18', + 'start-ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet-name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard-fqdn': 'test_value_27' + } + + set_method_mock.assert_called_with('firewall', '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_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_address': { + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'associated-interface': 'test_value_4', + 'cache-ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end-ip': 'test_value_9', + 'epg-name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj-id': 'test_value_14', + 'organization': 'test_value_15', + 'policy-group': 'test_value_16', + 'sdn': 'aci', + 'sdn-tag': 'test_value_18', + 'start-ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet-name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard-fqdn': 'test_value_27' + } + + set_method_mock.assert_called_with('firewall', '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_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_address': { + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', '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_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_address': { + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', '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_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_address': { + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'associated-interface': 'test_value_4', + 'cache-ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end-ip': 'test_value_9', + 'epg-name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj-id': 'test_value_14', + 'organization': 'test_value_15', + 'policy-group': 'test_value_16', + 'sdn': 'aci', + 'sdn-tag': 'test_value_18', + 'start-ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet-name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard-fqdn': 'test_value_27' + } + + set_method_mock.assert_called_with('firewall', '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_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_address': { + 'random_attribute_not_valid': 'tag', + 'allow_routing': 'enable', + 'associated_interface': 'test_value_4', + 'cache_ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end_ip': 'test_value_9', + 'epg_name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj_id': 'test_value_14', + 'organization': 'test_value_15', + 'policy_group': 'test_value_16', + 'sdn': 'aci', + 'sdn_tag': 'test_value_18', + 'start_ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet_name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard_fqdn': 'test_value_27' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'associated-interface': 'test_value_4', + 'cache-ttl': '5', + 'color': '6', + 'comment': 'Comment.', + 'country': 'test_value_8', + 'end-ip': 'test_value_9', + 'epg-name': 'test_value_10', + 'filter': 'test_value_11', + 'fqdn': 'test_value_12', + 'name': 'default_name_13', + 'obj-id': 'test_value_14', + 'organization': 'test_value_15', + 'policy-group': 'test_value_16', + 'sdn': 'aci', + 'sdn-tag': 'test_value_18', + 'start-ip': 'test_value_19', + 'subnet': 'test_value_20', + 'subnet-name': 'test_value_21', + 'tenant': 'test_value_22', + 'type': 'ipmask', + 'uuid': 'test_value_24', + 'visibility': 'enable', + 'wildcard': 'test_value_26', + 'wildcard-fqdn': 'test_value_27' + } + + set_method_mock.assert_called_with('firewall', '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_address6.py b/test/units/modules/network/fortios/test_fortios_firewall_address6.py new file mode 100644 index 00000000000..78d90b9c1ec --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_address6.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_address6 +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_address6.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_address6_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_address6': { + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'cache-ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end-ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host-type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj-id': 'test_value_12', + 'sdn': 'nsx', + 'start-ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'address6', 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_address6_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_address6': { + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'cache-ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end-ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host-type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj-id': 'test_value_12', + 'sdn': 'nsx', + 'start-ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'address6', 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_address6_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_address6': { + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'address6', 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_address6_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_address6': { + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'address6', 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_address6_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_address6': { + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'cache-ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end-ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host-type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj-id': 'test_value_12', + 'sdn': 'nsx', + 'start-ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'address6', 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_address6_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_address6': { + 'random_attribute_not_valid': 'tag', + 'cache_ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end_ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host_type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj_id': 'test_value_12', + 'sdn': 'nsx', + 'start_ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'cache-ttl': '3', + 'color': '4', + 'comment': 'Comment.', + 'end-ip': 'test_value_6', + 'fqdn': 'test_value_7', + 'host': 'test_value_8', + 'host-type': 'any', + 'ip6': 'test_value_10', + 'name': 'default_name_11', + 'obj-id': 'test_value_12', + 'sdn': 'nsx', + 'start-ip': 'test_value_14', + 'template': 'test_value_15', + 'type': 'ipprefix', + 'uuid': 'test_value_17', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'address6', 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_address6_template.py b/test/units/modules/network/fortios/test_fortios_firewall_address6_template.py new file mode 100644 index 00000000000..afbb7518920 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_address6_template.py @@ -0,0 +1,219 @@ +# 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_address6_template +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_address6_template.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_address6_template_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_address6_template': { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet-segment-count': '5' + } + + set_method_mock.assert_called_with('firewall', 'address6-template', 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_address6_template_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_address6_template': { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet-segment-count': '5' + } + + set_method_mock.assert_called_with('firewall', 'address6-template', 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_address6_template_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_address6_template': { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'address6-template', 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_address6_template_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_address6_template': { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'address6-template', 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_address6_template_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_address6_template': { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet-segment-count': '5' + } + + set_method_mock.assert_called_with('firewall', 'address6-template', 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_address6_template_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_address6_template': { + 'random_attribute_not_valid': 'tag', + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet_segment_count': '5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_address6_template.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'ip6': 'test_value_3', + 'name': 'default_name_4', + 'subnet-segment-count': '5' + } + + set_method_mock.assert_called_with('firewall', 'address6-template', 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_addrgrp.py b/test/units/modules/network/fortios/test_fortios_firewall_addrgrp.py new file mode 100644 index 00000000000..51b3250106d --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_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_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_addrgrp.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_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_addrgrp': { + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', '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_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_addrgrp': { + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', '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_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_addrgrp': { + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', '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_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_addrgrp': { + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', '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_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_addrgrp': { + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', '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_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_addrgrp': { + 'random_attribute_not_valid': 'tag', + 'allow_routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'allow-routing': 'enable', + 'color': '4', + 'comment': 'Comment.', + 'name': 'default_name_6', + 'uuid': 'test_value_7', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', '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_addrgrp6.py b/test/units/modules/network/fortios/test_fortios_firewall_addrgrp6.py new file mode 100644 index 00000000000..ce4eaa3a0e8 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_addrgrp6.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_addrgrp6 +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_addrgrp6.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_addrgrp6_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_addrgrp6': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'addrgrp6', 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_addrgrp6_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_addrgrp6': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'addrgrp6', 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_addrgrp6_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_addrgrp6': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'addrgrp6', 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_addrgrp6_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_addrgrp6': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'addrgrp6', 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_addrgrp6_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_addrgrp6': { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'addrgrp6', 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_addrgrp6_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_addrgrp6': { + 'random_attribute_not_valid': 'tag', + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_addrgrp6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'color': '3', + 'comment': 'Comment.', + 'name': 'default_name_5', + 'uuid': 'test_value_6', + 'visibility': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'addrgrp6', 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_auth_portal.py b/test/units/modules/network/fortios/test_fortios_firewall_auth_portal.py new file mode 100644 index 00000000000..def708b3da9 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_auth_portal.py @@ -0,0 +1,159 @@ +# 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_auth_portal +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_auth_portal.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_auth_portal_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_auth_portal': {'identity_based_route': 'test_value_3', + 'portal_addr': 'test_value_4', + 'portal_addr6': 'test_value_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_auth_portal.fortios_firewall(input_data, fos_instance) + + expected_data = {'identity-based-route': 'test_value_3', + 'portal-addr': 'test_value_4', + 'portal-addr6': 'test_value_5' + } + + set_method_mock.assert_called_with('firewall', 'auth-portal', 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_auth_portal_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_auth_portal': {'identity_based_route': 'test_value_3', + 'portal_addr': 'test_value_4', + 'portal_addr6': 'test_value_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_auth_portal.fortios_firewall(input_data, fos_instance) + + expected_data = {'identity-based-route': 'test_value_3', + 'portal-addr': 'test_value_4', + 'portal-addr6': 'test_value_5' + } + + set_method_mock.assert_called_with('firewall', 'auth-portal', 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_auth_portal_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_auth_portal': {'identity_based_route': 'test_value_3', + 'portal_addr': 'test_value_4', + 'portal_addr6': 'test_value_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_auth_portal.fortios_firewall(input_data, fos_instance) + + expected_data = {'identity-based-route': 'test_value_3', + 'portal-addr': 'test_value_4', + 'portal-addr6': 'test_value_5' + } + + set_method_mock.assert_called_with('firewall', 'auth-portal', 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_auth_portal_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_auth_portal': { + 'random_attribute_not_valid': 'tag', 'identity_based_route': 'test_value_3', + 'portal_addr': 'test_value_4', + 'portal_addr6': 'test_value_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_auth_portal.fortios_firewall(input_data, fos_instance) + + expected_data = {'identity-based-route': 'test_value_3', + 'portal-addr': 'test_value_4', + 'portal-addr6': 'test_value_5' + } + + set_method_mock.assert_called_with('firewall', 'auth-portal', 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_central_snat_map.py b/test/units/modules/network/fortios/test_fortios_firewall_central_snat_map.py new file mode 100644 index 00000000000..4f808d45b89 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_central_snat_map.py @@ -0,0 +1,259 @@ +# 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_central_snat_map +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_central_snat_map.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_central_snat_map_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_central_snat_map': { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat-port': 'test_value_5', + 'orig-port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'central-snat-map', 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_central_snat_map_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_central_snat_map': { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat-port': 'test_value_5', + 'orig-port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'central-snat-map', 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_central_snat_map_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_central_snat_map': { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'central-snat-map', 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_central_snat_map_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_central_snat_map': { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'central-snat-map', 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_central_snat_map_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_central_snat_map': { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat-port': 'test_value_5', + 'orig-port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'central-snat-map', 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_central_snat_map_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_central_snat_map': { + 'random_attribute_not_valid': 'tag', + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat_port': 'test_value_5', + 'orig_port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_central_snat_map.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'nat': 'disable', + 'nat-port': 'test_value_5', + 'orig-port': 'test_value_6', + 'policyid': '7', + 'protocol': '8', + 'status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'central-snat-map', 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_dnstranslation.py b/test/units/modules/network/fortios/test_fortios_firewall_dnstranslation.py new file mode 100644 index 00000000000..c0edb64c398 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_dnstranslation.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_dnstranslation +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_dnstranslation.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_dnstranslation_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_dnstranslation': { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + } + + set_method_mock.assert_called_with('firewall', 'dnstranslation', 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_dnstranslation_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_dnstranslation': { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + } + + set_method_mock.assert_called_with('firewall', 'dnstranslation', 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_dnstranslation_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_dnstranslation': { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'dnstranslation', 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_dnstranslation_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_dnstranslation': { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'dnstranslation', 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_dnstranslation_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_dnstranslation': { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + } + + set_method_mock.assert_called_with('firewall', 'dnstranslation', 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_dnstranslation_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_dnstranslation': { + 'random_attribute_not_valid': 'tag', + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_dnstranslation.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'dst': 'test_value_3', + 'id': '4', + 'netmask': 'test_value_5', + 'src': 'test_value_6' + } + + set_method_mock.assert_called_with('firewall', 'dnstranslation', 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_identity_based_route.py b/test/units/modules/network/fortios/test_fortios_firewall_identity_based_route.py new file mode 100644 index 00000000000..08d12c3245c --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_identity_based_route.py @@ -0,0 +1,219 @@ +# 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_identity_based_route +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_identity_based_route.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_identity_based_route_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_identity_based_route': { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + } + + set_method_mock.assert_called_with('firewall', 'identity-based-route', 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_identity_based_route_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_identity_based_route': { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + } + + set_method_mock.assert_called_with('firewall', 'identity-based-route', 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_identity_based_route_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_identity_based_route': { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'identity-based-route', 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_identity_based_route_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_identity_based_route': { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'identity-based-route', 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_identity_based_route_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_identity_based_route': { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + } + + set_method_mock.assert_called_with('firewall', 'identity-based-route', 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_identity_based_route_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_identity_based_route': { + 'random_attribute_not_valid': 'tag', + 'comments': 'test_value_3', + 'name': 'default_name_4', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_identity_based_route.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comments': 'test_value_3', + 'name': 'default_name_4', + + } + + set_method_mock.assert_called_with('firewall', 'identity-based-route', 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_interface_policy.py b/test/units/modules/network/fortios/test_fortios_firewall_interface_policy.py new file mode 100644 index 00000000000..2ca1bd76ae1 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_interface_policy.py @@ -0,0 +1,399 @@ +# 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_interface_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_interface_policy.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_interface_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_interface_policy': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-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_interface_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_interface_policy': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-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_interface_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_interface_policy': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'interface-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_interface_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_interface_policy': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'interface-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_interface_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_interface_policy': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-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_interface_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_interface_policy': { + 'random_attribute_not_valid': 'tag', + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-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_interface_policy6.py b/test/units/modules/network/fortios/test_fortios_firewall_interface_policy6.py new file mode 100644 index 00000000000..ab4d81af05f --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_interface_policy6.py @@ -0,0 +1,399 @@ +# 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_interface_policy6 +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_interface_policy6.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_interface_policy6_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_interface_policy6': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-policy6', 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_interface_policy6_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_interface_policy6': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-policy6', 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_interface_policy6_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_interface_policy6': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'interface-policy6', 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_interface_policy6_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_interface_policy6': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'interface-policy6', 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_interface_policy6_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_interface_policy6': { + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-policy6', 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_interface_policy6_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_interface_policy6': { + 'random_attribute_not_valid': 'tag', + 'address_type': 'ipv4', + 'application_list': 'test_value_4', + 'application_list_status': 'enable', + 'av_profile': 'test_value_6', + 'av_profile_status': 'enable', + 'comments': 'test_value_8', + 'dlp_sensor': 'test_value_9', + 'dlp_sensor_status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips_sensor': 'test_value_13', + 'ips_sensor_status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan_botnet_connections': 'disable', + 'spamfilter_profile': 'test_value_19', + 'spamfilter_profile_status': 'enable', + 'status': 'enable', + 'webfilter_profile': 'test_value_22', + 'webfilter_profile_status': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_interface_policy6.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'address-type': 'ipv4', + 'application-list': 'test_value_4', + 'application-list-status': 'enable', + 'av-profile': 'test_value_6', + 'av-profile-status': 'enable', + 'comments': 'test_value_8', + 'dlp-sensor': 'test_value_9', + 'dlp-sensor-status': 'enable', + 'dsri': 'enable', + 'interface': 'test_value_12', + 'ips-sensor': 'test_value_13', + 'ips-sensor-status': 'enable', + 'label': 'test_value_15', + 'logtraffic': 'all', + 'policyid': '17', + 'scan-botnet-connections': 'disable', + 'spamfilter-profile': 'test_value_19', + 'spamfilter-profile-status': 'enable', + 'status': 'enable', + 'webfilter-profile': 'test_value_22', + 'webfilter-profile-status': 'enable' + } + + set_method_mock.assert_called_with('firewall', 'interface-policy6', 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_internet_service.py b/test/units/modules/network/fortios/test_fortios_firewall_internet_service.py new file mode 100644 index 00000000000..992ba5c7809 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_internet_service.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_internet_service +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_internet_service.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_internet_service_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_internet_service': { + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'database': 'isdb', + 'direction': 'src', + 'icon-id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld-id': '10' + } + + set_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_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_internet_service': { + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'database': 'isdb', + 'direction': 'src', + 'icon-id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld-id': '10' + } + + set_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_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_internet_service': { + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_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_internet_service': { + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_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_internet_service': { + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'database': 'isdb', + 'direction': 'src', + 'icon-id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld-id': '10' + } + + set_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_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_internet_service': { + 'random_attribute_not_valid': 'tag', + 'database': 'isdb', + 'direction': 'src', + 'icon_id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld_id': '10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'database': 'isdb', + 'direction': 'src', + 'icon-id': '5', + 'id': '6', + 'name': 'default_name_7', + 'offset': '8', + 'reputation': '9', + 'sld-id': '10' + } + + set_method_mock.assert_called_with('firewall', 'internet-service', 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_internet_service_custom.py b/test/units/modules/network/fortios/test_fortios_firewall_internet_service_custom.py new file mode 100644 index 00000000000..ecb04b2bba9 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_firewall_internet_service_custom.py @@ -0,0 +1,219 @@ +# 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_internet_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_internet_service_custom.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_firewall_internet_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_internet_service_custom': { + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'master-service-id': '4', + 'name': 'default_name_5' + } + + set_method_mock.assert_called_with('firewall', 'internet-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_internet_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_internet_service_custom': { + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'master-service-id': '4', + 'name': 'default_name_5' + } + + set_method_mock.assert_called_with('firewall', 'internet-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_internet_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_internet_service_custom': { + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'internet-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_internet_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_internet_service_custom': { + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + delete_method_mock.assert_called_with('firewall', 'internet-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_internet_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_internet_service_custom': { + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'master-service-id': '4', + 'name': 'default_name_5' + } + + set_method_mock.assert_called_with('firewall', 'internet-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_internet_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_internet_service_custom': { + 'random_attribute_not_valid': 'tag', + 'comment': 'Comment.', + 'master_service_id': '4', + 'name': 'default_name_5' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_firewall_internet_service_custom.fortios_firewall(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'master-service-id': '4', + 'name': 'default_name_5' + } + + set_method_mock.assert_called_with('firewall', 'internet-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