From e62fb1e2f9d0a9280135f62d74bb5c258d5f81a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Angel=20Mu=C3=B1oz=20Gonz=C3=A1lez?= Date: Tue, 27 Aug 2019 12:27:34 +0200 Subject: [PATCH] FortiOS modules for 2.9 - 9 (#61320) * FortiOS modules for 2.9 - 9 * Undo ignore file * Remove non valid identifiers * Leave fortios_switch_controller_lldp_profile and fortios_switch_controller_managed_switch out of this PR * Updated fortios_switch_controller_lldp_profile and fortios_switch_controller_managed_switch --- .../fortios/fortios_spamfilter_profile.py | 311 ++- .../fortios/fortios_ssh_filter_profile.py | 168 +- .../fortios_switch_controller_global.py | 179 +- .../fortios_switch_controller_lldp_profile.py | 229 ++- ...fortios_switch_controller_lldp_settings.py | 154 +- ...ios_switch_controller_mac_sync_settings.py | 122 +- ...ortios_switch_controller_managed_switch.py | 955 +++++---- ...tch_controller_network_monitor_settings.py | 123 +- .../fortios/fortios_system_accprofile.py | 281 ++- .../network/fortios/fortios_system_admin.py | 619 +++--- .../fortios/fortios_system_api_user.py | 197 +- .../fortios_system_central_management.py | 263 ++- .../fortios/fortios_system_dhcp_server.py | 506 +++-- .../network/fortios/fortios_system_dns.py | 199 +- .../network/fortios/fortios_system_global.py | 1486 ++++++++------ .../fortios/fortios_system_interface.py | 1552 +++++++++------ .../fortios/fortios_system_sdn_connector.py | 411 ++-- .../fortios/fortios_system_settings.py | 20 +- .../network/fortios/fortios_system_vdom.py | 160 +- .../fortios_system_virtual_wan_link.py | 651 +++--- test/sanity/ignore.txt | 36 - .../test_fortios_spamfilter_profile.py | 339 ++++ .../test_fortios_ssh_filter_profile.py | 239 +++ .../test_fortios_switch_controller_global.py | 199 ++ ..._fortios_switch_controller_lldp_profile.py | 269 +++ ...fortios_switch_controller_lldp_settings.py | 183 ++ ...ios_switch_controller_mac_sync_settings.py | 151 ++ ...ortios_switch_controller_managed_switch.py | 389 ++++ ...tch_controller_network_monitor_settings.py | 151 ++ .../fortios/test_fortios_system_accprofile.py | 349 ++++ .../fortios/test_fortios_system_admin.py | 689 +++++++ .../fortios/test_fortios_system_api_user.py | 279 +++ .../test_fortios_system_central_management.py | 263 +++ .../test_fortios_system_dhcp_server.py | 589 ++++++ .../fortios/test_fortios_system_dns.py | 223 +++ .../fortios/test_fortios_system_global.py | 1559 +++++++++++++++ .../fortios/test_fortios_system_interface.py | 1769 +++++++++++++++++ .../test_fortios_system_sdn_connector.py | 489 +++++ .../fortios/test_fortios_system_vdom.py | 229 +++ .../test_fortios_system_virtual_wan_link.py | 159 ++ 40 files changed, 13724 insertions(+), 3415 deletions(-) create mode 100644 test/units/modules/network/fortios/test_fortios_spamfilter_profile.py create mode 100644 test/units/modules/network/fortios/test_fortios_ssh_filter_profile.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_global.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_lldp_profile.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_lldp_settings.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_mac_sync_settings.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_managed_switch.py create mode 100644 test/units/modules/network/fortios/test_fortios_switch_controller_network_monitor_settings.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_accprofile.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_admin.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_api_user.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_central_management.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_dhcp_server.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_dns.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_global.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_interface.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_sdn_connector.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_vdom.py create mode 100644 test/units/modules/network/fortios/test_fortios_system_virtual_wan_link.py diff --git a/lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py b/lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py index 970a6739a2e..66d926d9e55 100644 --- a/lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py +++ b/lib/ansible/modules/network/fortios/fortios_spamfilter_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_spamfilter_profile short_description: Configure AntiSpam profiles in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify spamfilter feature and profile category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,87 +41,110 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 spamfilter_profile: description: - Configure AntiSpam profiles. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent comment: description: - Comment. + type: str external: description: - Enable/disable external Email inspection. + type: str choices: - enable - disable - flow-based: + flow_based: description: - Enable/disable flow-based spam filtering. + type: str choices: - enable - disable gmail: description: - Gmail. + type: dict suboptions: log: description: - Enable/disable logging. + type: str choices: - enable - disable imap: description: - IMAP. + type: dict suboptions: action: description: - Action for spam email. + type: str choices: - pass - tag log: description: - Enable/disable logging. + type: str choices: - enable - disable - tag-msg: + tag_msg: description: - Subject text or header added to spam email. - tag-type: + type: str + tag_type: description: - Tag subject or header for spam email. + type: list choices: - subject - header @@ -132,26 +152,31 @@ options: mapi: description: - MAPI. + type: dict suboptions: action: description: - Action for spam email. + type: str choices: - pass - discard log: description: - Enable/disable logging. + type: str choices: - enable - disable - msn-hotmail: + msn_hotmail: description: - MSN Hotmail. + type: dict suboptions: log: description: - Enable/disable logging. + type: str choices: - enable - disable @@ -159,9 +184,11 @@ options: description: - Profile name. required: true + type: str options: description: - Options. + type: list choices: - bannedword - spambwl @@ -177,39 +204,47 @@ options: pop3: description: - POP3. + type: dict suboptions: action: description: - Action for spam email. + type: str choices: - pass - tag log: description: - Enable/disable logging. + type: str choices: - enable - disable - tag-msg: + tag_msg: description: - Subject text or header added to spam email. - tag-type: + type: str + tag_type: description: - Tag subject or header for spam email. + type: list choices: - subject - header - spaminfo - replacemsg-group: + replacemsg_group: description: - Replacement message group. Source system.replacemsg-group.name. + type: str smtp: description: - SMTP. + type: dict suboptions: action: description: - Action for spam email. + type: str choices: - pass - tag @@ -217,74 +252,90 @@ options: hdrip: description: - Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters. + type: str choices: - disable - enable - local-override: + local_override: description: - Enable/disable local filter to override SMTP remote check result. + type: str choices: - disable - enable log: description: - Enable/disable logging. + type: str choices: - enable - disable - tag-msg: + tag_msg: description: - Subject text or header added to spam email. - tag-type: + type: str + tag_type: description: - Tag subject or header for spam email. + type: list choices: - subject - header - spaminfo - spam-bwl-table: + spam_bwl_table: description: - Anti-spam black/white list table ID. Source spamfilter.bwl.id. - spam-bword-table: + type: int + spam_bword_table: description: - Anti-spam banned word table ID. Source spamfilter.bword.id. - spam-bword-threshold: + type: int + spam_bword_threshold: description: - Spam banned word threshold. - spam-filtering: + type: int + spam_filtering: description: - Enable/disable spam filtering. + type: str choices: - enable - disable - spam-iptrust-table: + spam_iptrust_table: description: - Anti-spam IP trust table ID. Source spamfilter.iptrust.id. - spam-log: + type: int + spam_log: description: - Enable/disable spam logging for email filtering. + type: str choices: - disable - enable - spam-log-fortiguard-response: + spam_log_fortiguard_response: description: - Enable/disable logging FortiGuard spam response. + type: str choices: - disable - enable - spam-mheader-table: + spam_mheader_table: description: - Anti-spam MIME header table ID. Source spamfilter.mheader.id. - spam-rbl-table: + type: int + spam_rbl_table: description: - Anti-spam DNSBL table ID. Source spamfilter.dnsbl.id. - yahoo-mail: + type: int + yahoo_mail: description: - Yahoo! Mail. + type: dict suboptions: log: description: - Enable/disable logging. + type: str choices: - enable - disable @@ -297,6 +348,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure AntiSpam profiles. fortios_spamfilter_profile: @@ -305,48 +357,48 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" spamfilter_profile: - state: "present" comment: "Comment." external: "enable" - flow-based: "enable" + flow_based: "enable" gmail: log: "enable" imap: action: "pass" log: "enable" - tag-msg: "" - tag-type: "subject" + tag_msg: "" + tag_type: "subject" mapi: action: "pass" log: "enable" - msn-hotmail: + msn_hotmail: log: "enable" name: "default_name_18" options: "bannedword" pop3: action: "pass" log: "enable" - tag-msg: "" - tag-type: "subject" - replacemsg-group: " (source system.replacemsg-group.name)" + tag_msg: "" + tag_type: "subject" + replacemsg_group: " (source system.replacemsg-group.name)" smtp: action: "pass" hdrip: "disable" - local-override: "disable" + local_override: "disable" log: "enable" - tag-msg: "" - tag-type: "subject" - spam-bwl-table: "33 (source spamfilter.bwl.id)" - spam-bword-table: "34 (source spamfilter.bword.id)" - spam-bword-threshold: "35" - spam-filtering: "enable" - spam-iptrust-table: "37 (source spamfilter.iptrust.id)" - spam-log: "disable" - spam-log-fortiguard-response: "disable" - spam-mheader-table: "40 (source spamfilter.mheader.id)" - spam-rbl-table: "41 (source spamfilter.dnsbl.id)" - yahoo-mail: + tag_msg: "" + tag_type: "subject" + spam_bwl_table: "33 (source spamfilter.bwl.id)" + spam_bword_table: "34 (source spamfilter.bword.id)" + spam_bword_threshold: "35" + spam_filtering: "enable" + spam_iptrust_table: "37 (source spamfilter.iptrust.id)" + spam_log: "disable" + spam_log_fortiguard_response: "disable" + spam_mheader_table: "40 (source spamfilter.mheader.id)" + spam_rbl_table: "41 (source spamfilter.dnsbl.id)" + yahoo_mail: log: "enable" ''' @@ -410,14 +462,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']: @@ -425,18 +479,18 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_spamfilter_profile_data(json): - option_list = ['comment', 'external', 'flow-based', + option_list = ['comment', 'external', 'flow_based', 'gmail', 'imap', 'mapi', - 'msn-hotmail', 'name', 'options', - 'pop3', 'replacemsg-group', 'smtp', - 'spam-bwl-table', 'spam-bword-table', 'spam-bword-threshold', - 'spam-filtering', 'spam-iptrust-table', 'spam-log', - 'spam-log-fortiguard-response', 'spam-mheader-table', 'spam-rbl-table', - 'yahoo-mail'] + 'msn_hotmail', 'name', 'options', + 'pop3', 'replacemsg_group', 'smtp', + 'spam_bwl_table', 'spam_bword_table', 'spam_bword_threshold', + 'spam_filtering', 'spam_iptrust_table', 'spam_log', + 'spam_log_fortiguard_response', 'spam_mheader_table', 'spam_rbl_table', + 'yahoo_mail'] dictionary = {} for attribute in option_list: @@ -447,7 +501,7 @@ def filter_spamfilter_profile_data(json): def flatten_multilists_attributes(data): - multilist_attrs = [[u'options'], [u'imap', u'tag-type'], [u'pop3', u'tag-type'], [u'smtp', u'tag-type']] + multilist_attrs = [[u'options'], [u'imap', u'tag_type'], [u'pop3', u'tag_type'], [u'smtp', u'tag_type']] for attr in multilist_attrs: try: @@ -461,50 +515,71 @@ def flatten_multilists_attributes(data): return data +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 spamfilter_profile(data, fos): vdom = data['vdom'] + state = data['state'] spamfilter_profile_data = data['spamfilter_profile'] - flattened_data = flatten_multilists_attributes(spamfilter_profile_data) - filtered_data = filter_spamfilter_profile_data(flattened_data) - if spamfilter_profile_data['state'] == "present": + spamfilter_profile_data = flatten_multilists_attributes(spamfilter_profile_data) + filtered_data = underscore_to_hyphen(filter_spamfilter_profile_data(spamfilter_profile_data)) + + if state == "present": return fos.set('spamfilter', 'profile', data=filtered_data, vdom=vdom) - elif spamfilter_profile_data['state'] == "absent": + elif state == "absent": return fos.delete('spamfilter', 'profile', 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_spamfilter(data, fos): - login(data) if data['spamfilter_profile']: resp = spamfilter_profile(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "spamfilter_profile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "comment": {"required": False, "type": "str"}, "external": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "flow-based": {"required": False, "type": "str", + "flow_based": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "gmail": {"required": False, "type": "dict", "options": { @@ -517,8 +592,8 @@ def main(): "choices": ["pass", "tag"]}, "log": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "tag-msg": {"required": False, "type": "str"}, - "tag-type": {"required": False, "type": "list", + "tag_msg": {"required": False, "type": "str"}, + "tag_type": {"required": False, "type": "list", "choices": ["subject", "header", "spaminfo"]} }}, "mapi": {"required": False, "type": "dict", @@ -528,7 +603,7 @@ def main(): "log": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "msn-hotmail": {"required": False, "type": "dict", + "msn_hotmail": {"required": False, "type": "dict", "options": { "log": {"required": False, "type": "str", "choices": ["enable", "disable"]} @@ -545,38 +620,38 @@ def main(): "choices": ["pass", "tag"]}, "log": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "tag-msg": {"required": False, "type": "str"}, - "tag-type": {"required": False, "type": "list", + "tag_msg": {"required": False, "type": "str"}, + "tag_type": {"required": False, "type": "list", "choices": ["subject", "header", "spaminfo"]} }}, - "replacemsg-group": {"required": False, "type": "str"}, + "replacemsg_group": {"required": False, "type": "str"}, "smtp": {"required": False, "type": "dict", "options": { "action": {"required": False, "type": "str", "choices": ["pass", "tag", "discard"]}, "hdrip": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "local-override": {"required": False, "type": "str", + "local_override": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "log": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "tag-msg": {"required": False, "type": "str"}, - "tag-type": {"required": False, "type": "list", + "tag_msg": {"required": False, "type": "str"}, + "tag_type": {"required": False, "type": "list", "choices": ["subject", "header", "spaminfo"]} }}, - "spam-bwl-table": {"required": False, "type": "int"}, - "spam-bword-table": {"required": False, "type": "int"}, - "spam-bword-threshold": {"required": False, "type": "int"}, - "spam-filtering": {"required": False, "type": "str", + "spam_bwl_table": {"required": False, "type": "int"}, + "spam_bword_table": {"required": False, "type": "int"}, + "spam_bword_threshold": {"required": False, "type": "int"}, + "spam_filtering": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "spam-iptrust-table": {"required": False, "type": "int"}, - "spam-log": {"required": False, "type": "str", + "spam_iptrust_table": {"required": False, "type": "int"}, + "spam_log": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "spam-log-fortiguard-response": {"required": False, "type": "str", + "spam_log_fortiguard_response": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "spam-mheader-table": {"required": False, "type": "int"}, - "spam-rbl-table": {"required": False, "type": "int"}, - "yahoo-mail": {"required": False, "type": "dict", + "spam_mheader_table": {"required": False, "type": "int"}, + "spam_rbl_table": {"required": False, "type": "int"}, + "yahoo_mail": {"required": False, "type": "dict", "options": { "log": {"required": False, "type": "str", "choices": ["enable", "disable"]} @@ -588,15 +663,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_spamfilter(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_spamfilter(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_spamfilter(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_ssh_filter_profile.py b/lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py index 8158118f2ee..2752c0a987b 100644 --- a/lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py +++ b/lib/ansible/modules/network/fortios/fortios_ssh_filter_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_ssh_filter_profile short_description: SSH filter profile in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify ssh_filter feature and profile category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,43 +41,57 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 ssh_filter_profile: description: - SSH filter profile. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent block: description: - SSH blocking options. + type: str choices: - x11 - shell @@ -89,15 +100,17 @@ options: - tun-forward - sftp - unknown - default-command-log: + default_command_log: description: - Enable/disable logging unmatched shell commands. + type: str choices: - enable - disable log: description: - SSH logging options. + type: str choices: - x11 - shell @@ -110,19 +123,23 @@ options: description: - SSH filter profile name. required: true - shell-commands: + type: str + shell_commands: description: - SSH command filter. + type: list suboptions: action: description: - Action to take for URL filter matches. + type: str choices: - block - allow alert: description: - Enable/disable alert. + type: str choices: - enable - disable @@ -130,18 +147,22 @@ options: description: - Id. required: true + type: int log: description: - Enable/disable logging. + type: str choices: - enable - disable pattern: description: - SSH shell command pattern. + type: str severity: description: - Log severity. + type: str choices: - low - medium @@ -150,6 +171,7 @@ options: type: description: - Matching type. + type: str choices: - simple - regex @@ -162,6 +184,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: SSH filter profile. fortios_ssh_filter_profile: @@ -170,13 +193,13 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" ssh_filter_profile: - state: "present" block: "x11" - default-command-log: "enable" + default_command_log: "enable" log: "x11" name: "default_name_6" - shell-commands: + shell_commands: - action: "block" alert: "enable" @@ -247,14 +270,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']: @@ -262,12 +287,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_ssh_filter_profile_data(json): - option_list = ['block', 'default-command-log', 'log', - 'name', 'shell-commands'] + option_list = ['block', 'default_command_log', 'log', + 'name', 'shell_commands'] dictionary = {} for attribute in option_list: @@ -277,73 +302,78 @@ def filter_ssh_filter_profile_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 ssh_filter_profile(data, fos): vdom = data['vdom'] + state = data['state'] ssh_filter_profile_data = data['ssh_filter_profile'] - flattened_data = flatten_multilists_attributes(ssh_filter_profile_data) - filtered_data = filter_ssh_filter_profile_data(flattened_data) - if ssh_filter_profile_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_ssh_filter_profile_data(ssh_filter_profile_data)) + + if state == "present": return fos.set('ssh-filter', 'profile', data=filtered_data, vdom=vdom) - elif ssh_filter_profile_data['state'] == "absent": + elif state == "absent": return fos.delete('ssh-filter', 'profile', 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_ssh_filter(data, fos): - login(data) if data['ssh_filter_profile']: resp = ssh_filter_profile(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "ssh_filter_profile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "block": {"required": False, "type": "str", "choices": ["x11", "shell", "exec", "port-forward", "tun-forward", "sftp", "unknown"]}, - "default-command-log": {"required": False, "type": "str", + "default_command_log": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "log": {"required": False, "type": "str", "choices": ["x11", "shell", "exec", "port-forward", "tun-forward", "sftp", "unknown"]}, "name": {"required": True, "type": "str"}, - "shell-commands": {"required": False, "type": "list", + "shell_commands": {"required": False, "type": "list", "options": { "action": {"required": False, "type": "str", "choices": ["block", "allow"]}, @@ -366,15 +396,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_ssh_filter(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_ssh_filter(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_ssh_filter(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_switch_controller_global.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_global.py index b7ff30e9710..b19f94485d2 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_global.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_global.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_switch_controller_global short_description: Configure FortiSwitch global settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and global category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,72 +41,91 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 switch_controller_global: description: - Configure FortiSwitch global settings. default: null + type: dict suboptions: - allow-multiple-interfaces: + allow_multiple_interfaces: description: - Enable/disable multiple FortiLink interfaces for redundant connections between a managed FortiSwitch and FortiGate. + type: str choices: - enable - disable - default-virtual-switch-vlan: + default_virtual_switch_vlan: description: - Default VLAN for ports when added to the virtual-switch. Source system.interface.name. - disable-discovery: + type: str + disable_discovery: description: - Prevent this FortiSwitch from discovering. + type: list suboptions: name: description: - Managed device ID. required: true - https-image-push: + type: str + https_image_push: description: - Enable/disable image push to FortiSwitch using HTTPS. + type: str choices: - enable - disable - log-mac-limit-violations: + log_mac_limit_violations: description: - Enable/disable logs for Learning Limit Violations. + type: str choices: - enable - disable - mac-aging-interval: + mac_aging_interval: description: - - Time after which an inactive MAC is aged out (10 - 1000000 sec, default = 300, 0 = disable). - mac-retention-period: + - Time after which an inactive MAC is aged out (10 - 1000000 sec). + type: int + mac_retention_period: description: - Time in hours after which an inactive MAC is removed from client DB. - mac-violation-timer: + type: int + mac_violation_timer: description: - Set timeout for Learning Limit Violations (0 = disabled). + type: int ''' EXAMPLES = ''' @@ -119,6 +135,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiSwitch global settings. fortios_switch_controller_global: @@ -128,16 +145,16 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" switch_controller_global: - allow-multiple-interfaces: "enable" - default-virtual-switch-vlan: " (source system.interface.name)" - disable-discovery: + allow_multiple_interfaces: "enable" + default_virtual_switch_vlan: " (source system.interface.name)" + disable_discovery: - name: "default_name_6" - https-image-push: "enable" - log-mac-limit-violations: "enable" - mac-aging-interval: "9" - mac-retention-period: "10" - mac-violation-timer: "11" + https_image_push: "enable" + log_mac_limit_violations: "enable" + mac_aging_interval: "9" + mac_retention_period: "10" + mac_violation_timer: "11" ''' RETURN = ''' @@ -200,14 +217,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']: @@ -215,13 +234,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_global_data(json): - option_list = ['allow-multiple-interfaces', 'default-virtual-switch-vlan', 'disable-discovery', - 'https-image-push', 'log-mac-limit-violations', 'mac-aging-interval', - 'mac-retention-period', 'mac-violation-timer'] + option_list = ['allow_multiple_interfaces', 'default_virtual_switch_vlan', 'disable_discovery', + 'https_image_push', 'log_mac_limit_violations', 'mac_aging_interval', + 'mac_retention_period', 'mac_violation_timer'] dictionary = {} for attribute in option_list: @@ -231,17 +250,15 @@ def filter_switch_controller_global_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 @@ -249,48 +266,54 @@ def flatten_multilists_attributes(data): def switch_controller_global(data, fos): vdom = data['vdom'] switch_controller_global_data = data['switch_controller_global'] - flattened_data = flatten_multilists_attributes(switch_controller_global_data) - filtered_data = filter_switch_controller_global_data(flattened_data) + filtered_data = underscore_to_hyphen(filter_switch_controller_global_data(switch_controller_global_data)) + return fos.set('switch-controller', 'global', 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_switch_controller(data, fos): - login(data) if data['switch_controller_global']: resp = switch_controller_global(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "switch_controller_global": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "allow-multiple-interfaces": {"required": False, "type": "str", + "allow_multiple_interfaces": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "default-virtual-switch-vlan": {"required": False, "type": "str"}, - "disable-discovery": {"required": False, "type": "list", + "default_virtual_switch_vlan": {"required": False, "type": "str"}, + "disable_discovery": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "https-image-push": {"required": False, "type": "str", + "https_image_push": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "log-mac-limit-violations": {"required": False, "type": "str", + "log_mac_limit_violations": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "mac-aging-interval": {"required": False, "type": "int"}, - "mac-retention-period": {"required": False, "type": "int"}, - "mac-violation-timer": {"required": False, "type": "int"} + "mac_aging_interval": {"required": False, "type": "int"}, + "mac_retention_period": {"required": False, "type": "int"}, + "mac_violation_timer": {"required": False, "type": "int"} } } @@ -298,15 +321,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_switch_controller_lldp_profile.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py index 5ac675f4a31..386aa273318 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_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_switch_controller_lldp_profile short_description: Configure FortiSwitch LLDP profiles in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and lldp_profile category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,109 +41,140 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 switch_controller_lldp_profile: description: - Configure FortiSwitch LLDP profiles. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - 802.1-tlvs: + 802.1_tlvs: description: - Transmitted IEEE 802.1 TLVs. + type: str choices: - port-vlan-id - 802.3-tlvs: + 802.3_tlvs: description: - Transmitted IEEE 802.3 TLVs. + type: str choices: - max-frame-size - auto-isl: + auto_isl: description: - Enable/disable auto inter-switch LAG. + type: str choices: - disable - enable - auto-isl-hello-timer: + auto_isl_hello_timer: description: - - Auto inter-switch LAG hello timer duration (1 - 30 sec, default = 3). - auto-isl-port-group: + - Auto inter-switch LAG hello timer duration (1 - 30 sec). + type: int + auto_isl_port_group: description: - Auto inter-switch LAG port group ID (0 - 9). - auto-isl-receive-timeout: + type: int + auto_isl_receive_timeout: description: - - Auto inter-switch LAG timeout if no response is received (3 - 90 sec, default = 9). - custom-tlvs: + - Auto inter-switch LAG timeout if no response is received (3 - 90 sec). + type: int + custom_tlvs: description: - Configuration method to edit custom TLV entries. + type: list suboptions: - information-string: + information_string: description: - Organizationally defined information string (0 - 507 hexadecimal bytes). + type: str name: description: - TLV name (not sent). required: true + type: str oui: description: - Organizationally unique identifier (OUI), a 3-byte hexadecimal number, for this TLV. + type: str subtype: description: - Organizationally defined subtype (0 - 255). - med-network-policy: + type: int + med_network_policy: description: - Configuration method to edit Media Endpoint Discovery (MED) network policy type-length-value (TLV) categories. + type: list suboptions: dscp: description: - Advertised Differentiated Services Code Point (DSCP) value, a packet header value indicating the level of service requested for traffic, such as high priority or best effort delivery. + type: int name: description: - Policy type name. required: true + type: str priority: description: - Advertised Layer 2 priority (0 - 7; from lowest to highest priority). + type: int status: description: - Enable or disable this TLV. + type: str choices: - disable - enable vlan: description: - ID of VLAN to advertise, if configured on port (0 - 4094, 0 = priority tag). - med-tlvs: + type: int + med_tlvs: description: - "Transmitted LLDP-MED TLVs (type-length-value descriptions): inventory management TLV and/or network policy TLV." + type: str choices: - inventory-management - network-policy @@ -154,6 +182,7 @@ options: description: - Profile name. required: true + type: str ''' EXAMPLES = ''' @@ -163,6 +192,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiSwitch LLDP profiles. fortios_switch_controller_lldp_profile: @@ -171,28 +201,28 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" switch_controller_lldp_profile: - state: "present" - 802.1-tlvs: "port-vlan-id" - 802.3-tlvs: "max-frame-size" - auto-isl: "disable" - auto-isl-hello-timer: "6" - auto-isl-port-group: "7" - auto-isl-receive-timeout: "8" - custom-tlvs: + 802.1_tlvs: "port-vlan-id" + 802.3_tlvs: "max-frame-size" + auto_isl: "disable" + auto_isl_hello_timer: "6" + auto_isl_port_group: "7" + auto_isl_receive_timeout: "8" + custom_tlvs: - - information-string: "" + information_string: "" name: "default_name_11" oui: "" subtype: "13" - med-network-policy: + med_network_policy: - dscp: "15" name: "default_name_16" priority: "17" status: "disable" vlan: "19" - med-tlvs: "inventory-management" + med_tlvs: "inventory-management" name: "default_name_21" ''' @@ -256,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']: @@ -271,13 +303,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_lldp_profile_data(json): - option_list = ['802.1-tlvs', '802.3-tlvs', 'auto-isl', - 'auto-isl-hello-timer', 'auto-isl-port-group', 'auto-isl-receive-timeout', - 'custom-tlvs', 'med-network-policy', 'med-tlvs', + option_list = ['802.1_tlvs', '802.3_tlvs', 'auto_isl', + 'auto_isl_hello_timer', 'auto_isl_port_group', 'auto_isl_receive_timeout', + 'custom_tlvs', 'med_network_policy', 'med_tlvs', 'name'] dictionary = {} @@ -288,78 +320,83 @@ def filter_switch_controller_lldp_profile_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 switch_controller_lldp_profile(data, fos): vdom = data['vdom'] + state = data['state'] switch_controller_lldp_profile_data = data['switch_controller_lldp_profile'] - flattened_data = flatten_multilists_attributes(switch_controller_lldp_profile_data) - filtered_data = filter_switch_controller_lldp_profile_data(flattened_data) - if switch_controller_lldp_profile_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_switch_controller_lldp_profile_data(switch_controller_lldp_profile_data)) + + if state == "present": return fos.set('switch-controller', 'lldp-profile', data=filtered_data, vdom=vdom) - elif switch_controller_lldp_profile_data['state'] == "absent": + elif state == "absent": return fos.delete('switch-controller', 'lldp-profile', 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_switch_controller(data, fos): - login(data) if data['switch_controller_lldp_profile']: resp = switch_controller_lldp_profile(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "switch_controller_lldp_profile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "802.1-tlvs": {"required": False, "type": "str", + "802.1_tlvs": {"required": False, "type": "str", "choices": ["port-vlan-id"]}, - "802.3-tlvs": {"required": False, "type": "str", + "802.3_tlvs": {"required": False, "type": "str", "choices": ["max-frame-size"]}, - "auto-isl": {"required": False, "type": "str", + "auto_isl": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "auto-isl-hello-timer": {"required": False, "type": "int"}, - "auto-isl-port-group": {"required": False, "type": "int"}, - "auto-isl-receive-timeout": {"required": False, "type": "int"}, - "custom-tlvs": {"required": False, "type": "list", + "auto_isl_hello_timer": {"required": False, "type": "int"}, + "auto_isl_port_group": {"required": False, "type": "int"}, + "auto_isl_receive_timeout": {"required": False, "type": "int"}, + "custom_tlvs": {"required": False, "type": "list", "options": { - "information-string": {"required": False, "type": "str"}, + "information_string": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, "oui": {"required": False, "type": "str"}, "subtype": {"required": False, "type": "int"} }}, - "med-network-policy": {"required": False, "type": "list", + "med_network_policy": {"required": False, "type": "list", "options": { "dscp": {"required": False, "type": "int"}, "name": {"required": True, "type": "str"}, @@ -368,7 +405,7 @@ def main(): "choices": ["disable", "enable"]}, "vlan": {"required": False, "type": "int"} }}, - "med-tlvs": {"required": False, "type": "str", + "med_tlvs": {"required": False, "type": "str", "choices": ["inventory-management", "network-policy"]}, "name": {"required": True, "type": "str"} @@ -378,15 +415,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_switch_controller_lldp_settings.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py index 87e767c445d..0b861193f4e 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_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_switch_controller_lldp_settings short_description: Configure FortiSwitch LLDP settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and lldp_settings category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,56 +41,70 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 switch_controller_lldp_settings: description: - Configure FortiSwitch LLDP settings. default: null + type: dict suboptions: - fast-start-interval: + fast_start_interval: description: - - Frequency of LLDP PDU transmission from FortiSwitch for the first 4 packets when the link is up (2 - 5 sec, default = 2, 0 = disable - fast start). - management-interface: + - Frequency of LLDP PDU transmission from FortiSwitch for the first 4 packets when the link is up (2 - 5 sec). + type: int + management_interface: description: - Primary management interface to be advertised in LLDP and CDP PDUs. + type: str choices: - internal - mgmt status: description: - Enable/disable LLDP global settings. + type: str choices: - enable - disable - tx-hold: + tx_hold: description: - - Number of tx-intervals before local LLDP data expires (1 - 16, default = 4). Packet TTL is tx-hold * tx-interval. - tx-interval: + - Number of tx-intervals before local LLDP data expires (1 - 16). Packet TTL is tx-hold * tx-interval. + type: int + tx_interval: description: - - Frequency of LLDP PDU transmission from FortiSwitch (5 - 4095 sec, default = 30). Packet TTL is tx-hold * tx-interval. + - Frequency of LLDP PDU transmission from FortiSwitch (5 - 4095 sec). Packet TTL is tx-hold * tx-interval. + type: int ''' EXAMPLES = ''' @@ -103,6 +114,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiSwitch LLDP settings. fortios_switch_controller_lldp_settings: @@ -112,11 +124,11 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" switch_controller_lldp_settings: - fast-start-interval: "3" - management-interface: "internal" + fast_start_interval: "3" + management_interface: "internal" status: "enable" - tx-hold: "6" - tx-interval: "7" + tx_hold: "6" + tx_interval: "7" ''' RETURN = ''' @@ -179,14 +191,16 @@ version: ''' from ansible.module_utils.basic import AnsibleModule - -fos = None +from ansible.module_utils.connection import Connection +from ansible.module_utils.network.fortios.fortios import FortiOSHandler +from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG -def login(data): +def login(data, fos): host = data['host'] username = data['username'] password = data['password'] + ssl_verify = data['ssl_verify'] fos.debug('on') if 'https' in data and not data['https']: @@ -194,12 +208,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_lldp_settings_data(json): - option_list = ['fast-start-interval', 'management-interface', 'status', - 'tx-hold', 'tx-interval'] + option_list = ['fast_start_interval', 'management_interface', 'status', + 'tx_hold', 'tx_interval'] dictionary = {} for attribute in option_list: @@ -209,17 +223,15 @@ def filter_switch_controller_lldp_settings_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 @@ -227,41 +239,47 @@ def flatten_multilists_attributes(data): def switch_controller_lldp_settings(data, fos): vdom = data['vdom'] switch_controller_lldp_settings_data = data['switch_controller_lldp_settings'] - flattened_data = flatten_multilists_attributes(switch_controller_lldp_settings_data) - filtered_data = filter_switch_controller_lldp_settings_data(flattened_data) + filtered_data = underscore_to_hyphen(filter_switch_controller_lldp_settings_data(switch_controller_lldp_settings_data)) + return fos.set('switch-controller', 'lldp-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_switch_controller(data, fos): - login(data) if data['switch_controller_lldp_settings']: resp = switch_controller_lldp_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"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "switch_controller_lldp_settings": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "fast-start-interval": {"required": False, "type": "int"}, - "management-interface": {"required": False, "type": "str", + "fast_start_interval": {"required": False, "type": "int"}, + "management_interface": {"required": False, "type": "str", "choices": ["internal", "mgmt"]}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "tx-hold": {"required": False, "type": "int"}, - "tx-interval": {"required": False, "type": "int"} + "tx_hold": {"required": False, "type": "int"}, + "tx_interval": {"required": False, "type": "int"} } } @@ -269,15 +287,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_switch_controller_mac_sync_settings.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py index f020ef5e40e..2ad0bd6a206 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py @@ -26,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_switch_controller_mac_sync_settings short_description: Configure global MAC synchronization settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and mac_sync_settings category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -41,37 +41,48 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 switch_controller_mac_sync_settings: description: - Configure global MAC synchronization settings. default: null + type: dict suboptions: - mac-sync-interval: + mac_sync_interval: description: - - Time interval between MAC synchronizations (30 - 1800 sec, default = 60, 0 = disable MAC synchronization). + - Time interval between MAC synchronizations (30 - 1800 sec). + type: int ''' EXAMPLES = ''' @@ -81,6 +92,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure global MAC synchronization settings. fortios_switch_controller_mac_sync_settings: @@ -90,7 +102,7 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" switch_controller_mac_sync_settings: - mac-sync-interval: "3" + mac_sync_interval: "3" ''' RETURN = ''' @@ -153,14 +165,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']: @@ -168,11 +182,11 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_mac_sync_settings_data(json): - option_list = ['mac-sync-interval'] + option_list = ['mac_sync_interval'] dictionary = {} for attribute in option_list: @@ -182,17 +196,15 @@ def filter_switch_controller_mac_sync_settings_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 @@ -200,35 +212,41 @@ def flatten_multilists_attributes(data): def switch_controller_mac_sync_settings(data, fos): vdom = data['vdom'] switch_controller_mac_sync_settings_data = data['switch_controller_mac_sync_settings'] - flattened_data = flatten_multilists_attributes(switch_controller_mac_sync_settings_data) - filtered_data = filter_switch_controller_mac_sync_settings_data(flattened_data) + filtered_data = underscore_to_hyphen(filter_switch_controller_mac_sync_settings_data(switch_controller_mac_sync_settings_data)) + return fos.set('switch-controller', 'mac-sync-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_switch_controller(data, fos): - login(data) if data['switch_controller_mac_sync_settings']: resp = switch_controller_mac_sync_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"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "switch_controller_mac_sync_settings": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "mac-sync-interval": {"required": False, "type": "int"} + "mac_sync_interval": {"required": False, "type": "int"} } } @@ -236,15 +254,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_switch_controller_managed_switch.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py index 806fefe938e..8fc50bad1c8 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.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_switch_controller_managed_switch short_description: Configure FortiSwitch devices that are managed by this FortiGate in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and managed_switch category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,401 +41,493 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 switch_controller_managed_switch: description: - Configure FortiSwitch devices that are managed by this FortiGate. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - 802-1X-settings: + 802_1X_settings: description: - Configuration method to edit FortiSwitch 802.1X global settings. + type: dict suboptions: - link-down-auth: + link_down_auth: description: - Authentication state to set if a link is down. + type: str choices: - set-unauth - no-action - local-override: + local_override: description: - Enable to override global 802.1X settings on individual FortiSwitches. + type: str choices: - enable - disable - max-reauth-attempt: + max_reauth_attempt: description: - - Maximum number of authentication attempts (0 - 15, default = 3). - reauth-period: + - Maximum number of authentication attempts (0 - 15). + type: int + reauth_period: description: - - Reauthentication time interval (1 - 1440 min, default = 60, 0 = disable). - connected: - description: - - CAPWAP connection. - custom-command: + - Reauthentication time interval (1 - 1440 min). + type: int + custom_command: description: - Configuration method to edit FortiSwitch commands to be pushed to this FortiSwitch device upon rebooting the FortiGate switch controller or the FortiSwitch. + type: list suboptions: - command-entry: + command_entry: description: - List of FortiSwitch commands. - required: true - command-name: + type: str + command_name: description: - Names of commands to be pushed to this FortiSwitch device, as configured under config switch-controller custom-command. Source switch-controller.custom-command.command-name. - delayed-restart-trigger: + type: str + delayed_restart_trigger: description: - Delayed restart triggered for this FortiSwitch. + type: int description: description: - Description. - directly-connected: + type: str + directly_connected: description: - Directly connected FortiSwitch. - dynamic-capability: + type: int + dynamic_capability: description: - List of features this FortiSwitch supports (not configurable) that is sent to the FortiGate device for subsequent configuration initiated by the FortiGate device. - dynamically-discovered: + type: int + dynamically_discovered: description: - Dynamically discovered FortiSwitch. - fsw-wan1-admin: + type: int + fsw_wan1_admin: description: - FortiSwitch WAN1 admin status; enable to authorize the FortiSwitch as a managed switch. + type: str choices: - discovered - disable - enable - fsw-wan1-peer: + fsw_wan1_peer: description: - Fortiswitch WAN1 peer port. - fsw-wan2-admin: + type: str + fsw_wan2_admin: description: - FortiSwitch WAN2 admin status; enable to authorize the FortiSwitch as a managed switch. + type: str choices: - discovered - disable - enable - fsw-wan2-peer: + fsw_wan2_peer: description: - FortiSwitch WAN2 peer port. - igmp-snooping: + type: str + igmp_snooping: description: - Configure FortiSwitch IGMP snooping global settings. + type: dict suboptions: - aging-time: + aging_time: description: - - Maximum time to retain a multicast snooping entry for which no packets have been seen (15 - 3600 sec, default = 300). - flood-unknown-multicast: + - Maximum time to retain a multicast snooping entry for which no packets have been seen (15 - 3600 sec). + type: int + flood_unknown_multicast: description: - Enable/disable unknown multicast flooding. + type: str choices: - enable - disable - local-override: + local_override: description: - Enable/disable overriding the global IGMP snooping configuration. + type: str choices: - enable - disable - max-allowed-trunk-members: + max_allowed_trunk_members: description: - FortiSwitch maximum allowed trunk members. + type: int mirror: description: - Configuration method to edit FortiSwitch packet mirror. + type: list suboptions: dst: description: - Destination port. + type: str name: description: - Mirror name. required: true - src-egress: + type: str + src_egress: description: - Source egress interfaces. + type: list suboptions: name: description: - Interface name. required: true - src-ingress: + type: str + src_ingress: description: - Source ingress interfaces. + type: list suboptions: name: description: - Interface name. required: true + type: str status: description: - Active/inactive mirror configuration. + type: str choices: - active - inactive - switching-packet: + switching_packet: description: - Enable/disable switching functionality when mirroring. + type: str choices: - enable - disable name: description: - Managed-switch name. - owner-vdom: + type: str + owner_vdom: description: - VDOM which owner of port belongs to. - poe-pre-standard-detection: + type: str + poe_detection_type: + description: + - PoE detection type for FortiSwitch. + type: int + poe_pre_standard_detection: description: - Enable/disable PoE pre-standard detection. + type: str choices: - enable - disable ports: description: - Managed-switch port list. + type: list suboptions: - allowed-vlans: + allowed_vlans: description: - Configure switch port tagged vlans + type: list suboptions: - vlan-name: + vlan_name: description: - VLAN name. Source system.interface.name. - required: true - allowed-vlans-all: + type: str + allowed_vlans_all: description: - Enable/disable all defined vlans on this port. + type: str choices: - enable - disable - arp-inspection-trust: + arp_inspection_trust: description: - Trusted or untrusted dynamic ARP inspection. + type: str choices: - untrusted - trusted bundle: description: - Enable/disable Link Aggregation Group (LAG) bundling for non-FortiLink interfaces. + type: str choices: - enable - disable description: description: - Description for port. - dhcp-snoop-option82-trust: + type: str + dhcp_snoop_option82_trust: description: - Enable/disable allowance of DHCP with option-82 on untrusted interface. + type: str choices: - enable - disable - dhcp-snooping: + dhcp_snooping: description: - Trusted or untrusted DHCP-snooping interface. + type: str choices: - untrusted - trusted - discard-mode: + discard_mode: description: - Configure discard mode for port. + type: str choices: - none - all-untagged - all-tagged - edge-port: + edge_port: description: - Enable/disable this interface as an edge port, bridging connections between workstations and/or computers. + type: str choices: - enable - disable - export-tags: + export_tags: description: - Switch controller export tag name. + type: list suboptions: - tag-name: + tag_name: description: - Switch tag name. Source switch-controller.switch-interface-tag.name. - required: true - export-to: + type: str + export_to: description: - Export managed-switch port to a tenant VDOM. Source system.vdom.name. - export-to-pool: + type: str + export_to_pool: description: - Switch controller export port to pool-list. Source switch-controller.virtual-port-pool.name. - export-to-pool_flag: + type: str + export_to_pool_flag: description: - Switch controller export port to pool-list. - fgt-peer-device-name: + type: int + fgt_peer_device_name: description: - FGT peer device name. - fgt-peer-port-name: + type: str + fgt_peer_port_name: description: - FGT peer port name. - fiber-port: + type: str + fiber_port: description: - Fiber-port. + type: int flags: description: - Port properties flags. - fortilink-port: + type: int + fortilink_port: description: - FortiLink uplink port. - igmp-snooping: + type: int + igmp_snooping: description: - Set IGMP snooping mode for the physical port interface. + type: str choices: - enable - disable - igmps-flood-reports: + igmps_flood_reports: description: - Enable/disable flooding of IGMP reports to this interface when igmp-snooping enabled. + type: str choices: - enable - disable - igmps-flood-traffic: + igmps_flood_traffic: description: - Enable/disable flooding of IGMP snooping traffic to this interface. + type: str choices: - enable - disable - isl-local-trunk-name: + isl_local_trunk_name: description: - ISL local trunk name. - isl-peer-device-name: + type: str + isl_peer_device_name: description: - ISL peer device name. - isl-peer-port-name: + type: str + isl_peer_port_name: description: - ISL peer port name. - lacp-speed: + type: str + lacp_speed: description: - end Link Aggregation Control Protocol (LACP) messages every 30 seconds (slow) or every second (fast). + type: str choices: - slow - fast - learning-limit: + learning_limit: description: - Limit the number of dynamic MAC addresses on this Port (1 - 128, 0 = no limit, default). - lldp-profile: + type: int + lldp_profile: description: - LLDP port TLV profile. Source switch-controller.lldp-profile.name. - lldp-status: + type: str + lldp_status: description: - LLDP transmit and receive status. + type: str choices: - disable - rx-only - tx-only - tx-rx - loop-guard: + loop_guard: description: - Enable/disable loop-guard on this interface, an STP optimization used to prevent network loops. + type: str choices: - enabled - disabled - loop-guard-timeout: + loop_guard_timeout: description: - - Loop-guard timeout (0 - 120 min, default = 45). - max-bundle: + - Loop-guard timeout (0 - 120 min). + type: int + max_bundle: description: - - Maximum size of LAG bundle (1 - 24, default = 24) + - Maximum size of LAG bundle (1 - 24) + type: int mclag: description: - Enable/disable multi-chassis link aggregation (MCLAG). + type: str choices: - enable - disable - member-withdrawal-behavior: + member_withdrawal_behavior: description: - Port behavior after it withdraws because of loss of control packets. + type: str choices: - forward - block members: description: - Aggregated LAG bundle interfaces. + type: list suboptions: - member-name: + member_name: description: - Interface name from available options. - required: true - min-bundle: + type: str + min_bundle: description: - - Minimum size of LAG bundle (1 - 24, default = 1) + - Minimum size of LAG bundle (1 - 24) + type: int mode: description: - "LACP mode: ignore and do not send control messages, or negotiate 802.3ad aggregation passively or actively." + type: str choices: - static - lacp-passive - lacp-active - poe-capable: + poe_capable: description: - PoE capable. - poe-pre-standard-detection: + type: int + poe_pre_standard_detection: description: - Enable/disable PoE pre-standard detection. + type: str choices: - enable - disable - poe-status: + poe_status: description: - Enable/disable PoE status. + type: str choices: - enable - disable - port-name: + port_name: description: - Switch port name. - required: true - port-number: + type: str + port_number: description: - Port number. - port-owner: + type: int + port_owner: description: - Switch port name. - port-prefix-type: + type: str + port_prefix_type: description: - Port prefix type. - port-security-policy: + type: int + port_security_policy: description: - Switch controller authentication policy to apply to this managed switch from available options. Source switch-controller .security-policy.802-1X.name switch-controller.security-policy.captive-portal.name. - port-selection-criteria: + type: str + port_selection_criteria: description: - Algorithm for aggregate port selection. + type: str choices: - src-mac - dst-mac @@ -446,31 +535,37 @@ options: - src-ip - dst-ip - src-dst-ip - qos-policy: + qos_policy: description: - Switch controller QoS policy from available options. Source switch-controller.qos.qos-policy.name. - sample-direction: + type: str + sample_direction: description: - sFlow sample direction. + type: str choices: - tx - rx - both - sflow-counter-interval: + sflow_counter_interval: description: - sFlow sampler counter polling interval (1 - 255 sec). - sflow-sample-rate: + type: int + sflow_sample_rate: description: - sFlow sampler sample rate (0 - 99999 p/sec). - sflow-sampler: + type: int + sflow_sampler: description: - Enable/disable sFlow protocol on this interface. + type: str choices: - enabled - disabled speed: description: - Switch port speed; default and available settings depend on hardware. + type: str choices: - 10half - 10full @@ -489,157 +584,191 @@ options: - 2500full - 25000full - 50000full - speed-mask: + speed_mask: description: - Switch port speed mask. - stacking-port: + type: int + stacking_port: description: - Stacking port. + type: int status: description: - "Switch port admin status: up or down." + type: str choices: - up - down - stp-bpdu-guard: + stp_bpdu_guard: description: - Enable/disable STP BPDU guard on this interface. + type: str choices: - enabled - disabled - stp-bpdu-guard-timeout: + stp_bpdu_guard_timeout: description: - BPDU Guard disabling protection (0 - 120 min). - stp-root-guard: + type: int + stp_root_guard: description: - Enable/disable STP root guard on this interface. + type: str choices: - enabled - disabled - stp-state: + stp_state: description: - Enable/disable Spanning Tree Protocol (STP) on this interface. + type: str choices: - enabled - disabled - switch-id: + switch_id: description: - Switch id. + type: str type: description: - "Interface type: physical or trunk port." + type: str choices: - physical - trunk - untagged-vlans: + untagged_vlans: description: - Configure switch port untagged vlans + type: list suboptions: - vlan-name: + vlan_name: description: - VLAN name. Source system.interface.name. - required: true - virtual-port: + type: str + virtual_port: description: - Virtualized switch port. + type: int vlan: description: - Assign switch ports to a VLAN. Source system.interface.name. - pre-provisioned: + type: str + pre_provisioned: description: - Pre-provisioned managed switch. - staged-image-version: + type: int + staged_image_version: description: - Staged image version for FortiSwitch. - storm-control: + type: str + storm_control: description: - Configuration method to edit FortiSwitch storm control for measuring traffic activity using data rates to prevent traffic disruption. + type: dict suboptions: broadcast: description: - Enable/disable storm control to drop broadcast traffic. + type: str choices: - enable - disable - local-override: + local_override: description: - Enable to override global FortiSwitch storm control settings for this FortiSwitch. + type: str choices: - enable - disable rate: description: - - Rate in packets per second at which storm traffic is controlled (1 - 10000000, default = 500). Storm control drops excess - traffic data rates beyond this threshold. - unknown-multicast: + - Rate in packets per second at which storm traffic is controlled (1 - 10000000). Storm control drops excess traffic data rates + beyond this threshold. + type: int + unknown_multicast: description: - Enable/disable storm control to drop unknown multicast traffic. + type: str choices: - enable - disable - unknown-unicast: + unknown_unicast: description: - Enable/disable storm control to drop unknown unicast traffic. + type: str choices: - enable - disable - stp-settings: + stp_settings: description: - Configuration method to edit Spanning Tree Protocol (STP) settings used to prevent bridge loops. + type: dict suboptions: - forward-time: + forward_time: description: - - Period of time a port is in listening and learning state (4 - 30 sec, default = 15). - hello-time: + - Period of time a port is in listening and learning state (4 - 30 sec). + type: int + hello_time: description: - - Period of time between successive STP frame Bridge Protocol Data Units (BPDUs) sent on a port (1 - 10 sec, default = 2). - local-override: + - Period of time between successive STP frame Bridge Protocol Data Units (BPDUs) sent on a port (1 - 10 sec). + type: int + local_override: description: - Enable to configure local STP settings that override global STP settings. + type: str choices: - enable - disable - max-age: + max_age: description: - - Maximum time before a bridge port saves its configuration BPDU information (6 - 40 sec, default = 20). - max-hops: + - Maximum time before a bridge port saves its configuration BPDU information (6 - 40 sec). + type: int + max_hops: description: - - Maximum number of hops between the root bridge and the furthest bridge (1- 40, default = 20). + - Maximum number of hops between the root bridge and the furthest bridge (1- 40). + type: int name: description: - Name of local STP settings configuration. - pending-timer: + type: str + pending_timer: description: - - Pending time (1 - 15 sec, default = 4). + - Pending time (1 - 15 sec). + type: int revision: description: - STP revision number (0 - 65535). + type: int status: description: - Enable/disable STP. + type: str choices: - enable - disable - switch-device-tag: + switch_device_tag: description: - User definable label/tag. - switch-id: + type: str + switch_id: description: - Managed-switch id. - required: true - switch-log: + type: str + switch_log: description: - Configuration method to edit FortiSwitch logging settings (logs are transferred to and inserted into the FortiGate event log). + type: dict suboptions: - local-override: + local_override: description: - Enable to configure local logging settings that override global logging settings. + type: str choices: - enable - disable severity: description: - Severity of FortiSwitch logs that are added to the FortiGate event log. + type: str choices: - emergency - alert @@ -652,31 +781,37 @@ options: status: description: - Enable/disable adding FortiSwitch logs to the FortiGate event log. + type: str choices: - enable - disable - switch-profile: + switch_profile: description: - FortiSwitch profile. Source switch-controller.switch-profile.name. - switch-stp-settings: + type: str + switch_stp_settings: description: - Configure spanning tree protocol (STP). + type: dict suboptions: status: description: - Enable/disable STP. + type: str choices: - enable - disable type: description: - Indication of switch type, physical or virtual. + type: str choices: - virtual - physical version: description: - FortiSwitch version. + type: int ''' EXAMPLES = ''' @@ -686,6 +821,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure FortiSwitch devices that are managed by this FortiGate. fortios_switch_controller_managed_switch: @@ -694,147 +830,147 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" switch_controller_managed_switch: - state: "present" - 802-1X-settings: - link-down-auth: "set-unauth" - local-override: "enable" - max-reauth-attempt: "6" - reauth-period: "7" - connected: "8" - custom-command: + 802_1X_settings: + link_down_auth: "set-unauth" + local_override: "enable" + max_reauth_attempt: "6" + reauth_period: "7" + custom_command: - - command-entry: "" - command-name: " (source switch-controller.custom-command.command-name)" - delayed-restart-trigger: "12" + command_entry: "" + command_name: " (source switch-controller.custom-command.command-name)" + delayed_restart_trigger: "11" description: "" - directly-connected: "14" - dynamic-capability: "15" - dynamically-discovered: "16" - fsw-wan1-admin: "discovered" - fsw-wan1-peer: "" - fsw-wan2-admin: "discovered" - fsw-wan2-peer: "" - igmp-snooping: - aging-time: "22" - flood-unknown-multicast: "enable" - local-override: "enable" - max-allowed-trunk-members: "25" + directly_connected: "13" + dynamic_capability: "14" + dynamically_discovered: "15" + fsw_wan1_admin: "discovered" + fsw_wan1_peer: "" + fsw_wan2_admin: "discovered" + fsw_wan2_peer: "" + igmp_snooping: + aging_time: "21" + flood_unknown_multicast: "enable" + local_override: "enable" + max_allowed_trunk_members: "24" mirror: - dst: "" - name: "default_name_28" - src-egress: + name: "default_name_27" + src_egress: - - name: "default_name_30" - src-ingress: + name: "default_name_29" + src_ingress: - - name: "default_name_32" + name: "default_name_31" status: "active" - switching-packet: "enable" - name: "default_name_35" - owner-vdom: "" - poe-pre-standard-detection: "enable" + switching_packet: "enable" + name: "default_name_34" + owner_vdom: "" + poe_detection_type: "36" + poe_pre_standard_detection: "enable" ports: - - allowed-vlans: + allowed_vlans: - - vlan-name: " (source system.interface.name)" - allowed-vlans-all: "enable" - arp-inspection-trust: "untrusted" + vlan_name: " (source system.interface.name)" + allowed_vlans_all: "enable" + arp_inspection_trust: "untrusted" bundle: "enable" description: "" - dhcp-snoop-option82-trust: "enable" - dhcp-snooping: "untrusted" - discard-mode: "none" - edge-port: "enable" - export-tags: + dhcp_snoop_option82_trust: "enable" + dhcp_snooping: "untrusted" + discard_mode: "none" + edge_port: "enable" + export_tags: - - tag-name: " (source switch-controller.switch-interface-tag.name)" - export-to: " (source system.vdom.name)" - export-to-pool: " (source switch-controller.virtual-port-pool.name)" - export-to-pool_flag: "53" - fgt-peer-device-name: "" - fgt-peer-port-name: "" - fiber-port: "56" + tag_name: " (source switch-controller.switch-interface-tag.name)" + export_to: " (source system.vdom.name)" + export_to_pool: " (source switch-controller.virtual-port-pool.name)" + export_to_pool_flag: "53" + fgt_peer_device_name: "" + fgt_peer_port_name: "" + fiber_port: "56" flags: "57" - fortilink-port: "58" - igmp-snooping: "enable" - igmps-flood-reports: "enable" - igmps-flood-traffic: "enable" - isl-local-trunk-name: "" - isl-peer-device-name: "" - isl-peer-port-name: "" - lacp-speed: "slow" - learning-limit: "66" - lldp-profile: " (source switch-controller.lldp-profile.name)" - lldp-status: "disable" - loop-guard: "enabled" - loop-guard-timeout: "70" - max-bundle: "71" + fortilink_port: "58" + igmp_snooping: "enable" + igmps_flood_reports: "enable" + igmps_flood_traffic: "enable" + isl_local_trunk_name: "" + isl_peer_device_name: "" + isl_peer_port_name: "" + lacp_speed: "slow" + learning_limit: "66" + lldp_profile: " (source switch-controller.lldp-profile.name)" + lldp_status: "disable" + loop_guard: "enabled" + loop_guard_timeout: "70" + max_bundle: "71" mclag: "enable" - member-withdrawal-behavior: "forward" + member_withdrawal_behavior: "forward" members: - - member-name: "" - min-bundle: "76" + member_name: "" + min_bundle: "76" mode: "static" - poe-capable: "78" - poe-pre-standard-detection: "enable" - poe-status: "enable" - port-name: "" - port-number: "82" - port-owner: "" - port-prefix-type: "84" - port-security-policy: " (source switch-controller.security-policy.802-1X.name switch-controller.security-policy.captive-portal + poe_capable: "78" + poe_pre_standard_detection: "enable" + poe_status: "enable" + port_name: "" + port_number: "82" + port_owner: "" + port_prefix_type: "84" + port_security_policy: " (source switch-controller.security-policy.802-1X.name switch-controller.security-policy.captive-portal .name)" - port-selection-criteria: "src-mac" - qos-policy: " (source switch-controller.qos.qos-policy.name)" - sample-direction: "tx" - sflow-counter-interval: "89" - sflow-sample-rate: "90" - sflow-sampler: "enabled" + port_selection_criteria: "src-mac" + qos_policy: " (source switch-controller.qos.qos-policy.name)" + sample_direction: "tx" + sflow_counter_interval: "89" + sflow_sample_rate: "90" + sflow_sampler: "enabled" speed: "10half" - speed-mask: "93" - stacking-port: "94" + speed_mask: "93" + stacking_port: "94" status: "up" - stp-bpdu-guard: "enabled" - stp-bpdu-guard-timeout: "97" - stp-root-guard: "enabled" - stp-state: "enabled" - switch-id: "" + stp_bpdu_guard: "enabled" + stp_bpdu_guard_timeout: "97" + stp_root_guard: "enabled" + stp_state: "enabled" + switch_id: "" type: "physical" - untagged-vlans: + untagged_vlans: - - vlan-name: " (source system.interface.name)" - virtual-port: "104" + vlan_name: " (source system.interface.name)" + virtual_port: "104" vlan: " (source system.interface.name)" - pre-provisioned: "106" - staged-image-version: "" - storm-control: + pre_provisioned: "106" + staged_image_version: "" + storm_control: broadcast: "enable" - local-override: "enable" + local_override: "enable" rate: "111" - unknown-multicast: "enable" - unknown-unicast: "enable" - stp-settings: - forward-time: "115" - hello-time: "116" - local-override: "enable" - max-age: "118" - max-hops: "119" + unknown_multicast: "enable" + unknown_unicast: "enable" + stp_settings: + forward_time: "115" + hello_time: "116" + local_override: "enable" + max_age: "118" + max_hops: "119" name: "default_name_120" - pending-timer: "121" + pending_timer: "121" revision: "122" status: "enable" - switch-device-tag: "" - switch-id: "" - switch-log: - local-override: "enable" + switch_device_tag: "" + switch_id: "" + switch_log: + local_override: "enable" severity: "emergency" status: "enable" - switch-profile: " (source switch-controller.switch-profile.name)" - switch-stp-settings: + switch_profile: " (source switch-controller.switch-profile.name)" + switch_stp_settings: status: "enable" type: "virtual" version: "134" @@ -900,14 +1036,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']: @@ -915,20 +1053,20 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_managed_switch_data(json): - option_list = ['802-1X-settings', 'connected', 'custom-command', - 'delayed-restart-trigger', 'description', 'directly-connected', - 'dynamic-capability', 'dynamically-discovered', 'fsw-wan1-admin', - 'fsw-wan1-peer', 'fsw-wan2-admin', 'fsw-wan2-peer', - 'igmp-snooping', 'max-allowed-trunk-members', 'mirror', - 'name', 'owner-vdom', 'poe-pre-standard-detection', - 'ports', 'pre-provisioned', 'staged-image-version', - 'storm-control', 'stp-settings', 'switch-device-tag', - 'switch-id', 'switch-log', 'switch-profile', - 'switch-stp-settings', 'type', 'version'] + option_list = ['802_1X_settings', 'custom_command', 'delayed_restart_trigger', + 'description', 'directly_connected', 'dynamic_capability', + 'dynamically_discovered', 'fsw_wan1_admin', 'fsw_wan1_peer', + 'fsw_wan2_admin', 'fsw_wan2_peer', 'igmp_snooping', + 'max_allowed_trunk_members', 'mirror', 'name', + 'owner_vdom', 'poe_detection_type', 'poe_pre_standard_detection', + 'ports', 'pre_provisioned', 'staged_image_version', + 'storm_control', 'stp_settings', 'switch_device_tag', + 'switch_id', 'switch_log', 'switch_profile', + 'switch_stp_settings', 'type', 'version'] dictionary = {} for attribute in option_list: @@ -938,200 +1076,205 @@ def filter_switch_controller_managed_switch_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 switch_controller_managed_switch(data, fos): vdom = data['vdom'] + state = data['state'] switch_controller_managed_switch_data = data['switch_controller_managed_switch'] - flattened_data = flatten_multilists_attributes(switch_controller_managed_switch_data) - filtered_data = filter_switch_controller_managed_switch_data(flattened_data) - if switch_controller_managed_switch_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_switch_controller_managed_switch_data(switch_controller_managed_switch_data)) + + if state == "present": return fos.set('switch-controller', 'managed-switch', data=filtered_data, vdom=vdom) - elif switch_controller_managed_switch_data['state'] == "absent": + elif state == "absent": return fos.delete('switch-controller', 'managed-switch', mkey=filtered_data['switch-id'], vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_switch_controller(data, fos): - login(data) if data['switch_controller_managed_switch']: resp = switch_controller_managed_switch(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "switch_controller_managed_switch": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "802-1X-settings": {"required": False, "type": "dict", + "802_1X_settings": {"required": False, "type": "dict", "options": { - "link-down-auth": {"required": False, "type": "str", + "link_down_auth": {"required": False, "type": "str", "choices": ["set-unauth", "no-action"]}, - "local-override": {"required": False, "type": "str", + "local_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "max-reauth-attempt": {"required": False, "type": "int"}, - "reauth-period": {"required": False, "type": "int"} + "max_reauth_attempt": {"required": False, "type": "int"}, + "reauth_period": {"required": False, "type": "int"} }}, - "connected": {"required": False, "type": "int"}, - "custom-command": {"required": False, "type": "list", + "custom_command": {"required": False, "type": "list", "options": { - "command-entry": {"required": True, "type": "str"}, - "command-name": {"required": False, "type": "str"} + "command_entry": {"required": False, "type": "str"}, + "command_name": {"required": False, "type": "str"} }}, - "delayed-restart-trigger": {"required": False, "type": "int"}, + "delayed_restart_trigger": {"required": False, "type": "int"}, "description": {"required": False, "type": "str"}, - "directly-connected": {"required": False, "type": "int"}, - "dynamic-capability": {"required": False, "type": "int"}, - "dynamically-discovered": {"required": False, "type": "int"}, - "fsw-wan1-admin": {"required": False, "type": "str", + "directly_connected": {"required": False, "type": "int"}, + "dynamic_capability": {"required": False, "type": "int"}, + "dynamically_discovered": {"required": False, "type": "int"}, + "fsw_wan1_admin": {"required": False, "type": "str", "choices": ["discovered", "disable", "enable"]}, - "fsw-wan1-peer": {"required": False, "type": "str"}, - "fsw-wan2-admin": {"required": False, "type": "str", + "fsw_wan1_peer": {"required": False, "type": "str"}, + "fsw_wan2_admin": {"required": False, "type": "str", "choices": ["discovered", "disable", "enable"]}, - "fsw-wan2-peer": {"required": False, "type": "str"}, - "igmp-snooping": {"required": False, "type": "dict", + "fsw_wan2_peer": {"required": False, "type": "str"}, + "igmp_snooping": {"required": False, "type": "dict", "options": { - "aging-time": {"required": False, "type": "int"}, - "flood-unknown-multicast": {"required": False, "type": "str", + "aging_time": {"required": False, "type": "int"}, + "flood_unknown_multicast": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "local-override": {"required": False, "type": "str", + "local_override": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "max-allowed-trunk-members": {"required": False, "type": "int"}, + "max_allowed_trunk_members": {"required": False, "type": "int"}, "mirror": {"required": False, "type": "list", "options": { "dst": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, - "src-egress": {"required": False, "type": "list", + "src_egress": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "src-ingress": {"required": False, "type": "list", + "src_ingress": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, "status": {"required": False, "type": "str", "choices": ["active", "inactive"]}, - "switching-packet": {"required": False, "type": "str", + "switching_packet": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, "name": {"required": False, "type": "str"}, - "owner-vdom": {"required": False, "type": "str"}, - "poe-pre-standard-detection": {"required": False, "type": "str", + "owner_vdom": {"required": False, "type": "str"}, + "poe_detection_type": {"required": False, "type": "int"}, + "poe_pre_standard_detection": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "ports": {"required": False, "type": "list", "options": { - "allowed-vlans": {"required": False, "type": "list", + "allowed_vlans": {"required": False, "type": "list", "options": { - "vlan-name": {"required": True, "type": "str"} + "vlan_name": {"required": False, "type": "str"} }}, - "allowed-vlans-all": {"required": False, "type": "str", + "allowed_vlans_all": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "arp-inspection-trust": {"required": False, "type": "str", + "arp_inspection_trust": {"required": False, "type": "str", "choices": ["untrusted", "trusted"]}, "bundle": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "description": {"required": False, "type": "str"}, - "dhcp-snoop-option82-trust": {"required": False, "type": "str", + "dhcp_snoop_option82_trust": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dhcp-snooping": {"required": False, "type": "str", + "dhcp_snooping": {"required": False, "type": "str", "choices": ["untrusted", "trusted"]}, - "discard-mode": {"required": False, "type": "str", + "discard_mode": {"required": False, "type": "str", "choices": ["none", "all-untagged", "all-tagged"]}, - "edge-port": {"required": False, "type": "str", + "edge_port": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "export-tags": {"required": False, "type": "list", + "export_tags": {"required": False, "type": "list", "options": { - "tag-name": {"required": True, "type": "str"} + "tag_name": {"required": False, "type": "str"} }}, - "export-to": {"required": False, "type": "str"}, - "export-to-pool": {"required": False, "type": "str"}, - "export-to-pool_flag": {"required": False, "type": "int"}, - "fgt-peer-device-name": {"required": False, "type": "str"}, - "fgt-peer-port-name": {"required": False, "type": "str"}, - "fiber-port": {"required": False, "type": "int"}, + "export_to": {"required": False, "type": "str"}, + "export_to_pool": {"required": False, "type": "str"}, + "export_to_pool_flag": {"required": False, "type": "int"}, + "fgt_peer_device_name": {"required": False, "type": "str"}, + "fgt_peer_port_name": {"required": False, "type": "str"}, + "fiber_port": {"required": False, "type": "int"}, "flags": {"required": False, "type": "int"}, - "fortilink-port": {"required": False, "type": "int"}, - "igmp-snooping": {"required": False, "type": "str", + "fortilink_port": {"required": False, "type": "int"}, + "igmp_snooping": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "igmps-flood-reports": {"required": False, "type": "str", + "igmps_flood_reports": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "igmps-flood-traffic": {"required": False, "type": "str", + "igmps_flood_traffic": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "isl-local-trunk-name": {"required": False, "type": "str"}, - "isl-peer-device-name": {"required": False, "type": "str"}, - "isl-peer-port-name": {"required": False, "type": "str"}, - "lacp-speed": {"required": False, "type": "str", + "isl_local_trunk_name": {"required": False, "type": "str"}, + "isl_peer_device_name": {"required": False, "type": "str"}, + "isl_peer_port_name": {"required": False, "type": "str"}, + "lacp_speed": {"required": False, "type": "str", "choices": ["slow", "fast"]}, - "learning-limit": {"required": False, "type": "int"}, - "lldp-profile": {"required": False, "type": "str"}, - "lldp-status": {"required": False, "type": "str", + "learning_limit": {"required": False, "type": "int"}, + "lldp_profile": {"required": False, "type": "str"}, + "lldp_status": {"required": False, "type": "str", "choices": ["disable", "rx-only", "tx-only", "tx-rx"]}, - "loop-guard": {"required": False, "type": "str", + "loop_guard": {"required": False, "type": "str", "choices": ["enabled", "disabled"]}, - "loop-guard-timeout": {"required": False, "type": "int"}, - "max-bundle": {"required": False, "type": "int"}, + "loop_guard_timeout": {"required": False, "type": "int"}, + "max_bundle": {"required": False, "type": "int"}, "mclag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "member-withdrawal-behavior": {"required": False, "type": "str", + "member_withdrawal_behavior": {"required": False, "type": "str", "choices": ["forward", "block"]}, "members": {"required": False, "type": "list", "options": { - "member-name": {"required": True, "type": "str"} + "member_name": {"required": False, "type": "str"} }}, - "min-bundle": {"required": False, "type": "int"}, + "min_bundle": {"required": False, "type": "int"}, "mode": {"required": False, "type": "str", "choices": ["static", "lacp-passive", "lacp-active"]}, - "poe-capable": {"required": False, "type": "int"}, - "poe-pre-standard-detection": {"required": False, "type": "str", + "poe_capable": {"required": False, "type": "int"}, + "poe_pre_standard_detection": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "poe-status": {"required": False, "type": "str", + "poe_status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "port-name": {"required": True, "type": "str"}, - "port-number": {"required": False, "type": "int"}, - "port-owner": {"required": False, "type": "str"}, - "port-prefix-type": {"required": False, "type": "int"}, - "port-security-policy": {"required": False, "type": "str"}, - "port-selection-criteria": {"required": False, "type": "str", + "port_name": {"required": False, "type": "str"}, + "port_number": {"required": False, "type": "int"}, + "port_owner": {"required": False, "type": "str"}, + "port_prefix_type": {"required": False, "type": "int"}, + "port_security_policy": {"required": False, "type": "str"}, + "port_selection_criteria": {"required": False, "type": "str", "choices": ["src-mac", "dst-mac", "src-dst-mac", "src-ip", "dst-ip", "src-dst-ip"]}, - "qos-policy": {"required": False, "type": "str"}, - "sample-direction": {"required": False, "type": "str", + "qos_policy": {"required": False, "type": "str"}, + "sample_direction": {"required": False, "type": "str", "choices": ["tx", "rx", "both"]}, - "sflow-counter-interval": {"required": False, "type": "int"}, - "sflow-sample-rate": {"required": False, "type": "int"}, - "sflow-sampler": {"required": False, "type": "str", + "sflow_counter_interval": {"required": False, "type": "int"}, + "sflow_sample_rate": {"required": False, "type": "int"}, + "sflow_sampler": {"required": False, "type": "str", "choices": ["enabled", "disabled"]}, "speed": {"required": False, "type": "str", "choices": ["10half", "10full", "100half", @@ -1140,60 +1283,60 @@ def main(): "auto", "auto-module", "100FX-half", "100FX-full", "100000full", "2500full", "25000full", "50000full"]}, - "speed-mask": {"required": False, "type": "int"}, - "stacking-port": {"required": False, "type": "int"}, + "speed_mask": {"required": False, "type": "int"}, + "stacking_port": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["up", "down"]}, - "stp-bpdu-guard": {"required": False, "type": "str", + "stp_bpdu_guard": {"required": False, "type": "str", "choices": ["enabled", "disabled"]}, - "stp-bpdu-guard-timeout": {"required": False, "type": "int"}, - "stp-root-guard": {"required": False, "type": "str", + "stp_bpdu_guard_timeout": {"required": False, "type": "int"}, + "stp_root_guard": {"required": False, "type": "str", "choices": ["enabled", "disabled"]}, - "stp-state": {"required": False, "type": "str", + "stp_state": {"required": False, "type": "str", "choices": ["enabled", "disabled"]}, - "switch-id": {"required": False, "type": "str"}, + "switch_id": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", "choices": ["physical", "trunk"]}, - "untagged-vlans": {"required": False, "type": "list", + "untagged_vlans": {"required": False, "type": "list", "options": { - "vlan-name": {"required": True, "type": "str"} + "vlan_name": {"required": False, "type": "str"} }}, - "virtual-port": {"required": False, "type": "int"}, + "virtual_port": {"required": False, "type": "int"}, "vlan": {"required": False, "type": "str"} }}, - "pre-provisioned": {"required": False, "type": "int"}, - "staged-image-version": {"required": False, "type": "str"}, - "storm-control": {"required": False, "type": "dict", + "pre_provisioned": {"required": False, "type": "int"}, + "staged_image_version": {"required": False, "type": "str"}, + "storm_control": {"required": False, "type": "dict", "options": { "broadcast": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "local-override": {"required": False, "type": "str", + "local_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "rate": {"required": False, "type": "int"}, - "unknown-multicast": {"required": False, "type": "str", + "unknown_multicast": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "unknown-unicast": {"required": False, "type": "str", + "unknown_unicast": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "stp-settings": {"required": False, "type": "dict", + "stp_settings": {"required": False, "type": "dict", "options": { - "forward-time": {"required": False, "type": "int"}, - "hello-time": {"required": False, "type": "int"}, - "local-override": {"required": False, "type": "str", + "forward_time": {"required": False, "type": "int"}, + "hello_time": {"required": False, "type": "int"}, + "local_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "max-age": {"required": False, "type": "int"}, - "max-hops": {"required": False, "type": "int"}, + "max_age": {"required": False, "type": "int"}, + "max_hops": {"required": False, "type": "int"}, "name": {"required": False, "type": "str"}, - "pending-timer": {"required": False, "type": "int"}, + "pending_timer": {"required": False, "type": "int"}, "revision": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "switch-device-tag": {"required": False, "type": "str"}, - "switch-id": {"required": True, "type": "str"}, - "switch-log": {"required": False, "type": "dict", + "switch_device_tag": {"required": False, "type": "str"}, + "switch_id": {"required": False, "type": "str"}, + "switch_log": {"required": False, "type": "dict", "options": { - "local-override": {"required": False, "type": "str", + "local_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "severity": {"required": False, "type": "str", "choices": ["emergency", "alert", "critical", @@ -1202,8 +1345,8 @@ def main(): "status": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "switch-profile": {"required": False, "type": "str"}, - "switch-stp-settings": {"required": False, "type": "dict", + "switch_profile": {"required": False, "type": "str"}, + "switch_stp_settings": {"required": False, "type": "dict", "options": { "status": {"required": False, "type": "str", "choices": ["enable", "disable"]} @@ -1218,15 +1361,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_switch_controller_network_monitor_settings.py b/lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py index a82183a305a..a7685a37bb5 100644 --- a/lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py +++ b/lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_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_switch_controller_network_monitor_settings short_description: Configure network monitor settings in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify switch_controller feature and network_monitor_settings category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,37 +41,48 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 switch_controller_network_monitor_settings: description: - Configure network monitor settings. default: null + type: dict suboptions: - network-monitoring: + network_monitoring: description: - Enable/disable passive gathering of information by FortiSwitch units concerning other network devices. + type: str choices: - enable - disable @@ -87,6 +95,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure network monitor settings. fortios_switch_controller_network_monitor_settings: @@ -96,7 +105,7 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" switch_controller_network_monitor_settings: - network-monitoring: "enable" + network_monitoring: "enable" ''' RETURN = ''' @@ -159,14 +168,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']: @@ -174,11 +185,11 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_switch_controller_network_monitor_settings_data(json): - option_list = ['network-monitoring'] + option_list = ['network_monitoring'] dictionary = {} for attribute in option_list: @@ -188,17 +199,15 @@ def filter_switch_controller_network_monitor_settings_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 @@ -206,35 +215,41 @@ def flatten_multilists_attributes(data): def switch_controller_network_monitor_settings(data, fos): vdom = data['vdom'] switch_controller_network_monitor_settings_data = data['switch_controller_network_monitor_settings'] - flattened_data = flatten_multilists_attributes(switch_controller_network_monitor_settings_data) - filtered_data = filter_switch_controller_network_monitor_settings_data(flattened_data) + filtered_data = underscore_to_hyphen(filter_switch_controller_network_monitor_settings_data(switch_controller_network_monitor_settings_data)) + return fos.set('switch-controller', 'network-monitor-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_switch_controller(data, fos): - login(data) if data['switch_controller_network_monitor_settings']: resp = switch_controller_network_monitor_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"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "switch_controller_network_monitor_settings": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "network-monitoring": {"required": False, "type": "str", + "network_monitoring": {"required": False, "type": "str", "choices": ["enable", "disable"]} } @@ -243,15 +258,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_switch_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_switch_controller(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_switch_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_system_accprofile.py b/lib/ansible/modules/network/fortios/fortios_system_accprofile.py index 9e28f2b077c..66ce62777ac 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_accprofile.py +++ b/lib/ansible/modules/network/fortios/fortios_system_accprofile.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_system_accprofile short_description: Configure access profiles for system administrators in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and accprofile category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,52 +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: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_accprofile: description: - Configure access profiles for system administrators. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent admintimeout: description: - - Administrator timeout for this access profile (0 - 480 min, default = 10, 0 means never timeout). - admintimeout-override: + - Administrator timeout for this access profile (0 - 480 min). + type: int + admintimeout_override: description: - Enable/disable overriding the global administrator idle timeout. + type: str choices: - enable - disable authgrp: description: - Administrator access to Users and Devices. + type: str choices: - none - read @@ -97,9 +110,11 @@ options: comments: description: - Comment. + type: str ftviewgrp: description: - FortiView. + type: str choices: - none - read @@ -107,18 +122,21 @@ options: fwgrp: description: - Administrator access to the Firewall configuration. + type: str choices: - none - read - read-write - custom - fwgrp-permission: + fwgrp_permission: description: - Custom firewall permission. + type: dict suboptions: address: description: - Address Configuration. + type: str choices: - none - read @@ -126,6 +144,7 @@ options: policy: description: - Policy Configuration. + type: str choices: - none - read @@ -133,6 +152,7 @@ options: schedule: description: - Schedule Configuration. + type: str choices: - none - read @@ -140,6 +160,7 @@ options: service: description: - Service Configuration. + type: str choices: - none - read @@ -147,39 +168,45 @@ options: loggrp: description: - Administrator access to Logging and Reporting including viewing log messages. + type: str choices: - none - read - read-write - custom - loggrp-permission: + loggrp_permission: description: - Custom Log & Report permission. + type: dict suboptions: config: description: - Log & Report configuration. + type: str choices: - none - read - read-write - data-access: + data_access: description: - Log & Report Data Access. + type: str choices: - none - read - read-write - report-access: + report_access: description: - Log & Report Report Access. + type: str choices: - none - read - read-write - threat-weight: + threat_weight: description: - Log & Report Threat Weight. + type: str choices: - none - read @@ -188,35 +215,41 @@ options: description: - Profile name. required: true + type: str netgrp: description: - Network Configuration. + type: str choices: - none - read - read-write - custom - netgrp-permission: + netgrp_permission: description: - Custom network permission. + type: dict suboptions: cfg: description: - Network Configuration. + type: str choices: - none - read - read-write - packet-capture: + packet_capture: description: - Packet Capture Configuration. + type: str choices: - none - read - read-write - route-cfg: + route_cfg: description: - Router Configuration. + type: str choices: - none - read @@ -224,12 +257,14 @@ options: scope: description: - "Scope of admin access: global or specific VDOM(s)." + type: str choices: - vdom - global secfabgrp: description: - Security Fabric. + type: str choices: - none - read @@ -237,18 +272,21 @@ options: sysgrp: description: - System Configuration. + type: str choices: - none - read - read-write - custom - sysgrp-permission: + sysgrp_permission: description: - Custom system permission. + type: dict suboptions: admin: description: - Administrator Users. + type: str choices: - none - read @@ -256,6 +294,7 @@ options: cfg: description: - System Configuration. + type: str choices: - none - read @@ -263,6 +302,7 @@ options: mnt: description: - Maintenance. + type: str choices: - none - read @@ -270,6 +310,7 @@ options: upd: description: - FortiGuard Updates. + type: str choices: - none - read @@ -277,32 +318,37 @@ options: utmgrp: description: - Administrator access to Security Profiles. + type: str choices: - none - read - read-write - custom - utmgrp-permission: + utmgrp_permission: description: - Custom Security Profile permissions. + type: dict suboptions: antivirus: description: - Antivirus profiles and settings. + type: str choices: - none - read - read-write - application-control: + application_control: description: - Application Control profiles and settings. + type: str choices: - none - read - read-write - data-loss-prevention: + data_loss_prevention: description: - DLP profiles and settings. + type: str choices: - none - read @@ -310,13 +356,15 @@ options: dnsfilter: description: - DNS Filter profiles and settings. + type: str choices: - none - read - read-write - endpoint-control: + endpoint_control: description: - FortiClient Profiles. + type: str choices: - none - read @@ -324,6 +372,7 @@ options: icap: description: - ICAP profiles and settings. + type: str choices: - none - read @@ -331,6 +380,7 @@ options: ips: description: - IPS profiles and settings. + type: str choices: - none - read @@ -338,6 +388,7 @@ options: spamfilter: description: - AntiSpam filter and settings. + type: str choices: - none - read @@ -345,6 +396,7 @@ options: voip: description: - VoIP profiles and settings. + type: str choices: - none - read @@ -352,6 +404,7 @@ options: waf: description: - Web Application Firewall profiles and settings. + type: str choices: - none - read @@ -359,6 +412,7 @@ options: webfilter: description: - Web Filter profiles and settings. + type: str choices: - none - read @@ -366,6 +420,7 @@ options: vpngrp: description: - Administrator access to IPsec, SSL, PPTP, and L2TP VPN. + type: str choices: - none - read @@ -373,6 +428,7 @@ options: wanoptgrp: description: - Administrator access to WAN Opt & Cache. + type: str choices: - none - read @@ -380,6 +436,7 @@ options: wifi: description: - Administrator access to the WiFi controller and Switch controller. + type: str choices: - none - read @@ -393,6 +450,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure access profiles for system administrators. fortios_system_accprofile: @@ -401,46 +459,46 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_accprofile: - state: "present" admintimeout: "3" - admintimeout-override: "enable" + admintimeout_override: "enable" authgrp: "none" comments: "" ftviewgrp: "none" fwgrp: "none" - fwgrp-permission: + fwgrp_permission: address: "none" policy: "none" schedule: "none" service: "none" loggrp: "none" - loggrp-permission: + loggrp_permission: config: "none" - data-access: "none" - report-access: "none" - threat-weight: "none" + data_access: "none" + report_access: "none" + threat_weight: "none" name: "default_name_20" netgrp: "none" - netgrp-permission: + netgrp_permission: cfg: "none" - packet-capture: "none" - route-cfg: "none" + packet_capture: "none" + route_cfg: "none" scope: "vdom" secfabgrp: "none" sysgrp: "none" - sysgrp-permission: + sysgrp_permission: admin: "none" cfg: "none" mnt: "none" upd: "none" utmgrp: "none" - utmgrp-permission: + utmgrp_permission: antivirus: "none" - application-control: "none" - data-loss-prevention: "none" + application_control: "none" + data_loss_prevention: "none" dnsfilter: "none" - endpoint-control: "none" + endpoint_control: "none" icap: "none" ips: "none" spamfilter: "none" @@ -512,14 +570,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']: @@ -527,16 +587,16 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_accprofile_data(json): - option_list = ['admintimeout', 'admintimeout-override', 'authgrp', + option_list = ['admintimeout', 'admintimeout_override', 'authgrp', 'comments', 'ftviewgrp', 'fwgrp', - 'fwgrp-permission', 'loggrp', 'loggrp-permission', - 'name', 'netgrp', 'netgrp-permission', + 'fwgrp_permission', 'loggrp', 'loggrp_permission', + 'name', 'netgrp', 'netgrp_permission', 'scope', 'secfabgrp', 'sysgrp', - 'sysgrp-permission', 'utmgrp', 'utmgrp-permission', + 'sysgrp_permission', 'utmgrp', 'utmgrp_permission', 'vpngrp', 'wanoptgrp', 'wifi'] dictionary = {} @@ -547,63 +607,68 @@ def filter_system_accprofile_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 system_accprofile(data, fos): vdom = data['vdom'] + state = data['state'] system_accprofile_data = data['system_accprofile'] - flattened_data = flatten_multilists_attributes(system_accprofile_data) - filtered_data = filter_system_accprofile_data(flattened_data) - if system_accprofile_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_accprofile_data(system_accprofile_data)) + + if state == "present": return fos.set('system', 'accprofile', data=filtered_data, vdom=vdom) - elif system_accprofile_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'accprofile', 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_system(data, fos): - login(data) if data['system_accprofile']: resp = system_accprofile(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_accprofile": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "admintimeout": {"required": False, "type": "int"}, - "admintimeout-override": {"required": False, "type": "str", + "admintimeout_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "authgrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, @@ -613,7 +678,7 @@ def main(): "fwgrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write", "custom"]}, - "fwgrp-permission": {"required": False, "type": "dict", + "fwgrp_permission": {"required": False, "type": "dict", "options": { "address": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, @@ -627,28 +692,28 @@ def main(): "loggrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write", "custom"]}, - "loggrp-permission": {"required": False, "type": "dict", + "loggrp_permission": {"required": False, "type": "dict", "options": { "config": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "data-access": {"required": False, "type": "str", + "data_access": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "report-access": {"required": False, "type": "str", + "report_access": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "threat-weight": {"required": False, "type": "str", + "threat_weight": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]} }}, "name": {"required": True, "type": "str"}, "netgrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write", "custom"]}, - "netgrp-permission": {"required": False, "type": "dict", + "netgrp_permission": {"required": False, "type": "dict", "options": { "cfg": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "packet-capture": {"required": False, "type": "str", + "packet_capture": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "route-cfg": {"required": False, "type": "str", + "route_cfg": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]} }}, "scope": {"required": False, "type": "str", @@ -658,7 +723,7 @@ def main(): "sysgrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write", "custom"]}, - "sysgrp-permission": {"required": False, "type": "dict", + "sysgrp_permission": {"required": False, "type": "dict", "options": { "admin": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, @@ -672,17 +737,17 @@ def main(): "utmgrp": {"required": False, "type": "str", "choices": ["none", "read", "read-write", "custom"]}, - "utmgrp-permission": {"required": False, "type": "dict", + "utmgrp_permission": {"required": False, "type": "dict", "options": { "antivirus": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "application-control": {"required": False, "type": "str", + "application_control": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "data-loss-prevention": {"required": False, "type": "str", + "data_loss_prevention": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, "dnsfilter": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, - "endpoint-control": {"required": False, "type": "str", + "endpoint_control": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, "icap": {"required": False, "type": "str", "choices": ["none", "read", "read-write"]}, @@ -710,15 +775,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_admin.py b/lib/ansible/modules/network/fortios/fortios_system_admin.py index c89486ebb7e..79ebb9109f6 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_admin.py +++ b/lib/ansible/modules/network/fortios/fortios_system_admin.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_system_admin short_description: Configure admin users in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and admin category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,201 +41,222 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. type: bool default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. + type: bool + default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_admin: description: - Configure admin users. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent accprofile: description: - Access profile for this administrator. Access profiles control administrator access to FortiGate features. Source system.accprofile.name. - accprofile-override: + type: str + accprofile_override: description: - Enable to use the name of an access profile provided by the remote authentication server to control the FortiGate features that this administrator can access. + type: str choices: - enable - disable - allow-remove-admin-session: + allow_remove_admin_session: description: - Enable/disable allow admin session to be removed by privileged admin users. + type: str choices: - enable - disable comments: description: - Comment. - email-to: + type: str + email_to: description: - This administrator's email address. - force-password-change: + type: str + force_password_change: description: - Enable/disable force password change on next login. + type: str choices: - enable - disable fortitoken: description: - This administrator's FortiToken serial number. - guest-auth: + type: str + guest_auth: description: - Enable/disable guest authentication. + type: str choices: - disable - enable - guest-lang: + guest_lang: description: - Guest management portal language. Source system.custom-language.name. - guest-usergroups: + type: str + guest_usergroups: description: - Select guest user groups. + type: list suboptions: name: description: - Select guest user groups. required: true - gui-dashboard: + type: str + gui_dashboard: description: - GUI dashboards. + type: list suboptions: columns: description: - Number of columns. + type: int id: description: - Dashboard ID. required: true - layout-type: + type: int + layout_type: description: - Layout type. + type: str choices: - responsive - fixed name: description: - Dashboard name. + type: str scope: description: - Dashboard scope. + type: str choices: - global - vdom widget: description: - Dashboard widgets. + type: list suboptions: - fabric-device: + fabric_device: description: - Fabric device to monitor. - filters: + type: str + fortiview_filters: description: - FortiView filters. + type: list suboptions: id: description: - FortiView Filter ID. required: true + type: int key: description: - Filter key. + type: str value: description: - Filter value. + type: str + fortiview_sort_by: + description: + - FortiView sort by. + type: str + fortiview_timeframe: + description: + - FortiView timeframe. + type: str + fortiview_type: + description: + - FortiView type. + type: str + fortiview_visualization: + description: + - FortiView visualization. + type: str height: description: - Height. + type: int id: description: - Widget ID. required: true + type: int industry: description: - Security Audit Rating industry. + type: str choices: - default - custom interface: description: - Interface to monitor. Source system.interface.name. + type: str region: description: - Security Audit Rating region. + type: str choices: - default - custom - report-by: - description: - - Field to aggregate the data by. - choices: - - source - - destination - - country - - intfpair - - srcintf - - dstintf - - policy - - wificlient - - shaper - - endpoint-vulnerability - - endpoint-device - - application - - cloud-app - - cloud-user - - web-domain - - web-category - - web-search-phrase - - threat - - system - - unauth - - admin - - vpn - sort-by: - description: - - Field to sort the data by. - timeframe: - description: - - Timeframe period of reported data. - choices: - - realtime - - 5min - - hour - - day - - week title: description: - Widget title. + type: str type: description: - Widget type. + type: str choices: - sysinfo - licinfo @@ -262,200 +280,242 @@ options: - fortiview - botnet-activity - fortimail - visualization: - description: - - Visualization to use. - choices: - - table - - bubble - - country - - chord width: description: - Width. - x-pos: + type: int + x_pos: description: - X position. - y-pos: + type: int + y_pos: description: - Y position. - gui-global-menu-favorites: + type: int + gui_global_menu_favorites: description: - Favorite GUI menu IDs for the global VDOM. + type: list suboptions: id: description: - Select menu ID. required: true - gui-vdom-menu-favorites: + type: str + gui_vdom_menu_favorites: description: - Favorite GUI menu IDs for VDOMs. + type: list suboptions: id: description: - Select menu ID. required: true + type: str hidden: description: - Admin user hidden attribute. + type: int history0: description: - history0 + type: str history1: description: - history1 - ip6-trusthost1: + type: str + ip6_trusthost1: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost10: + type: str + ip6_trusthost10: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost2: + type: str + ip6_trusthost2: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost3: + type: str + ip6_trusthost3: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost4: + type: str + ip6_trusthost4: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost5: + type: str + ip6_trusthost5: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost6: + type: str + ip6_trusthost6: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost7: + type: str + ip6_trusthost7: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost8: + type: str + ip6_trusthost8: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - ip6-trusthost9: + type: str + ip6_trusthost9: description: - Any IPv6 address from which the administrator can connect to the FortiGate unit. Default allows access from any IPv6 address. - login-time: + type: str + login_time: description: - Record user login time. + type: list suboptions: - last-failed-login: + last_failed_login: description: - Last failed login time. - last-login: + type: str + last_login: description: - Last successful login time. - usr-name: + type: str + usr_name: description: - User name. - required: true + type: str name: description: - User name. required: true + type: str password: description: - Admin user password. - password-expire: + type: str + password_expire: description: - Password expire time. - peer-auth: + type: str + peer_auth: description: - Set to enable peer certificate authentication (for HTTPS admin access). + type: str choices: - enable - disable - peer-group: + peer_group: description: - Name of peer group defined under config user group which has PKI members. Used for peer certificate authentication (for HTTPS admin access). - radius-vdom-override: + type: str + radius_vdom_override: description: - Enable to use the names of VDOMs provided by the remote authentication server to control the VDOMs that this administrator can access. + type: str choices: - enable - disable - remote-auth: + remote_auth: description: - Enable/disable authentication using a remote RADIUS, LDAP, or TACACS+ server. + type: str choices: - enable - disable - remote-group: + remote_group: description: - User group name used for remote auth. + type: str schedule: description: - Firewall schedule used to restrict when the administrator can log in. No schedule means no restrictions. - sms-custom-server: + type: str + sms_custom_server: description: - Custom SMS server to send SMS messages to. Source system.sms-server.name. - sms-phone: + type: str + sms_phone: description: - Phone number on which the administrator receives SMS messages. - sms-server: + type: str + sms_server: description: - Send SMS messages using the FortiGuard SMS server or a custom server. + type: str choices: - fortiguard - custom - ssh-certificate: + ssh_certificate: description: - Select the certificate to be used by the FortiGate for authentication with an SSH client. Source certificate.local.name. - ssh-public-key1: + type: str + ssh_public_key1: description: - Public key of an SSH client. The client is authenticated without being asked for credentials. Create the public-private key pair in the SSH client application. - ssh-public-key2: + type: str + ssh_public_key2: description: - Public key of an SSH client. The client is authenticated without being asked for credentials. Create the public-private key pair in the SSH client application. - ssh-public-key3: + type: str + ssh_public_key3: description: - Public key of an SSH client. The client is authenticated without being asked for credentials. Create the public-private key pair in the SSH client application. + type: str trusthost1: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost10: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost2: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost3: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost4: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost5: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost6: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost7: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost8: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. + type: str trusthost9: description: - Any IPv4 address or subnet address and netmask from which the administrator can connect to the FortiGate unit. Default allows access from any IPv4 address. - two-factor: + type: str + two_factor: description: - Enable/disable two-factor authentication. + type: str choices: - disable - fortitoken @@ -464,14 +524,17 @@ options: vdom: description: - Virtual domain(s) that the administrator can access. + type: list suboptions: name: description: - Virtual domain name. Source system.vdom.name. required: true + type: str wildcard: description: - Enable/disable wildcard RADIUS authentication. + type: str choices: - enable - disable @@ -484,6 +547,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure admin users. fortios_system_admin: @@ -492,89 +556,89 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_admin: - state: "present" accprofile: " (source system.accprofile.name)" - accprofile-override: "enable" - allow-remove-admin-session: "enable" + accprofile_override: "enable" + allow_remove_admin_session: "enable" comments: "" - email-to: "" - force-password-change: "enable" + email_to: "" + force_password_change: "enable" fortitoken: "" - guest-auth: "disable" - guest-lang: " (source system.custom-language.name)" - guest-usergroups: + guest_auth: "disable" + guest_lang: " (source system.custom-language.name)" + guest_usergroups: - name: "default_name_13" - gui-dashboard: + gui_dashboard: - columns: "15" id: "16" - layout-type: "responsive" + layout_type: "responsive" name: "default_name_18" scope: "global" widget: - - fabric-device: "" - filters: + fabric_device: "" + fortiview_filters: - id: "23" key: "" value: "" - height: "26" - id: "27" + fortiview_sort_by: "" + fortiview_timeframe: "" + fortiview_type: "" + fortiview_visualization: "" + height: "30" + id: "31" industry: "default" interface: " (source system.interface.name)" region: "default" - report-by: "source" - sort-by: "" - timeframe: "realtime" title: "" type: "sysinfo" - visualization: "table" width: "37" - x-pos: "38" - y-pos: "39" - gui-global-menu-favorites: + x_pos: "38" + y_pos: "39" + gui_global_menu_favorites: - id: "41" - gui-vdom-menu-favorites: + gui_vdom_menu_favorites: - id: "43" hidden: "44" history0: "" history1: "" - ip6-trusthost1: "" - ip6-trusthost10: "" - ip6-trusthost2: "" - ip6-trusthost3: "" - ip6-trusthost4: "" - ip6-trusthost5: "" - ip6-trusthost6: "" - ip6-trusthost7: "" - ip6-trusthost8: "" - ip6-trusthost9: "" - login-time: + ip6_trusthost1: "" + ip6_trusthost10: "" + ip6_trusthost2: "" + ip6_trusthost3: "" + ip6_trusthost4: "" + ip6_trusthost5: "" + ip6_trusthost6: "" + ip6_trusthost7: "" + ip6_trusthost8: "" + ip6_trusthost9: "" + login_time: - - last-failed-login: "" - last-login: "" - usr-name: "" + last_failed_login: "" + last_login: "" + usr_name: "" name: "default_name_61" password: "" - password-expire: "" - peer-auth: "enable" - peer-group: "" - radius-vdom-override: "enable" - remote-auth: "enable" - remote-group: "" + password_expire: "" + peer_auth: "enable" + peer_group: "" + radius_vdom_override: "enable" + remote_auth: "enable" + remote_group: "" schedule: "" - sms-custom-server: " (source system.sms-server.name)" - sms-phone: "" - sms-server: "fortiguard" - ssh-certificate: " (source certificate.local.name)" - ssh-public-key1: "" - ssh-public-key2: "" - ssh-public-key3: "" + sms_custom_server: " (source system.sms-server.name)" + sms_phone: "" + sms_server: "fortiguard" + ssh_certificate: " (source certificate.local.name)" + ssh_public_key1: "" + ssh_public_key2: "" + ssh_public_key3: "" trusthost1: "" trusthost10: "" trusthost2: "" @@ -585,7 +649,7 @@ EXAMPLES = ''' trusthost7: "" trusthost8: "" trusthost9: "" - two-factor: "disable" + two_factor: "disable" vdom: - name: "default_name_89 (source system.vdom.name)" @@ -652,14 +716,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']: @@ -667,28 +733,28 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_admin_data(json): - option_list = ['accprofile', 'accprofile-override', 'allow-remove-admin-session', - 'comments', 'email-to', 'force-password-change', - 'fortitoken', 'guest-auth', 'guest-lang', - 'guest-usergroups', 'gui-dashboard', 'gui-global-menu-favorites', - 'gui-vdom-menu-favorites', 'hidden', 'history0', - 'history1', 'ip6-trusthost1', 'ip6-trusthost10', - 'ip6-trusthost2', 'ip6-trusthost3', 'ip6-trusthost4', - 'ip6-trusthost5', 'ip6-trusthost6', 'ip6-trusthost7', - 'ip6-trusthost8', 'ip6-trusthost9', 'login-time', - 'name', 'password', 'password-expire', - 'peer-auth', 'peer-group', 'radius-vdom-override', - 'remote-auth', 'remote-group', 'schedule', - 'sms-custom-server', 'sms-phone', 'sms-server', - 'ssh-certificate', 'ssh-public-key1', 'ssh-public-key2', - 'ssh-public-key3', 'trusthost1', 'trusthost10', + option_list = ['accprofile', 'accprofile_override', 'allow_remove_admin_session', + 'comments', 'email_to', 'force_password_change', + 'fortitoken', 'guest_auth', 'guest_lang', + 'guest_usergroups', 'gui_dashboard', 'gui_global_menu_favorites', + 'gui_vdom_menu_favorites', 'hidden', 'history0', + 'history1', 'ip6_trusthost1', 'ip6_trusthost10', + 'ip6_trusthost2', 'ip6_trusthost3', 'ip6_trusthost4', + 'ip6_trusthost5', 'ip6_trusthost6', 'ip6_trusthost7', + 'ip6_trusthost8', 'ip6_trusthost9', 'login_time', + 'name', 'password', 'password_expire', + 'peer_auth', 'peer_group', 'radius_vdom_override', + 'remote_auth', 'remote_group', 'schedule', + 'sms_custom_server', 'sms_phone', 'sms_server', + 'ssh_certificate', 'ssh_public_key1', 'ssh_public_key2', + 'ssh_public_key3', 'trusthost1', 'trusthost10', 'trusthost2', 'trusthost3', 'trusthost4', 'trusthost5', 'trusthost6', 'trusthost7', - 'trusthost8', 'trusthost9', 'two-factor', + 'trusthost8', 'trusthost9', 'two_factor', 'vdom', 'wildcard'] dictionary = {} @@ -699,96 +765,105 @@ def filter_system_admin_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 system_admin(data, fos): vdom = data['vdom'] + state = data['state'] system_admin_data = data['system_admin'] - flattened_data = flatten_multilists_attributes(system_admin_data) - filtered_data = filter_system_admin_data(flattened_data) - if system_admin_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_admin_data(system_admin_data)) + + if state == "present": return fos.set('system', 'admin', data=filtered_data, vdom=vdom) - elif system_admin_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'admin', 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_system(data, fos): - login(data) if data['system_admin']: resp = system_admin(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_admin": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "accprofile": {"required": False, "type": "str"}, - "accprofile-override": {"required": False, "type": "str", + "accprofile_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "allow-remove-admin-session": {"required": False, "type": "str", + "allow_remove_admin_session": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "comments": {"required": False, "type": "str"}, - "email-to": {"required": False, "type": "str"}, - "force-password-change": {"required": False, "type": "str", + "email_to": {"required": False, "type": "str"}, + "force_password_change": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "fortitoken": {"required": False, "type": "str"}, - "guest-auth": {"required": False, "type": "str", + "guest_auth": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "guest-lang": {"required": False, "type": "str"}, - "guest-usergroups": {"required": False, "type": "list", + "guest_lang": {"required": False, "type": "str"}, + "guest_usergroups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "gui-dashboard": {"required": False, "type": "list", + "gui_dashboard": {"required": False, "type": "list", "options": { "columns": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, - "layout-type": {"required": False, "type": "str", + "layout_type": {"required": False, "type": "str", "choices": ["responsive", "fixed"]}, "name": {"required": False, "type": "str"}, "scope": {"required": False, "type": "str", "choices": ["global", "vdom"]}, "widget": {"required": False, "type": "list", "options": { - "fabric-device": {"required": False, "type": "str"}, - "filters": {"required": False, "type": "list", - "options": { - "id": {"required": True, "type": "int"}, - "key": {"required": False, "type": "str"}, - "value": {"required": False, "type": "str"} - }}, + "fabric_device": {"required": False, "type": "str"}, + "fortiview_filters": {"required": False, "type": "list", + "options": { + "id": {"required": True, "type": "int"}, + "key": {"required": False, "type": "str"}, + "value": {"required": False, "type": "str"} + }}, + "fortiview_sort_by": {"required": False, "type": "str"}, + "fortiview_timeframe": {"required": False, "type": "str"}, + "fortiview_type": {"required": False, "type": "str"}, + "fortiview_visualization": {"required": False, "type": "str"}, "height": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, "industry": {"required": False, "type": "str", @@ -796,19 +871,6 @@ def main(): "interface": {"required": False, "type": "str"}, "region": {"required": False, "type": "str", "choices": ["default", "custom"]}, - "report-by": {"required": False, "type": "str", - "choices": ["source", "destination", "country", - "intfpair", "srcintf", "dstintf", - "policy", "wificlient", "shaper", - "endpoint-vulnerability", "endpoint-device", "application", - "cloud-app", "cloud-user", "web-domain", - "web-category", "web-search-phrase", "threat", - "system", "unauth", "admin", - "vpn"]}, - "sort-by": {"required": False, "type": "str"}, - "timeframe": {"required": False, "type": "str", - "choices": ["realtime", "5min", "hour", - "day", "week"]}, "title": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", "choices": ["sysinfo", "licinfo", "vminfo", @@ -819,61 +881,58 @@ def main(): "security-fabric-ranking", "ha-status", "vulnerability-summary", "host-scan-summary", "fortiview", "botnet-activity", "fortimail"]}, - "visualization": {"required": False, "type": "str", - "choices": ["table", "bubble", "country", - "chord"]}, "width": {"required": False, "type": "int"}, - "x-pos": {"required": False, "type": "int"}, - "y-pos": {"required": False, "type": "int"} + "x_pos": {"required": False, "type": "int"}, + "y_pos": {"required": False, "type": "int"} }} }}, - "gui-global-menu-favorites": {"required": False, "type": "list", + "gui_global_menu_favorites": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "str"} }}, - "gui-vdom-menu-favorites": {"required": False, "type": "list", + "gui_vdom_menu_favorites": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "str"} }}, "hidden": {"required": False, "type": "int"}, "history0": {"required": False, "type": "str"}, "history1": {"required": False, "type": "str"}, - "ip6-trusthost1": {"required": False, "type": "str"}, - "ip6-trusthost10": {"required": False, "type": "str"}, - "ip6-trusthost2": {"required": False, "type": "str"}, - "ip6-trusthost3": {"required": False, "type": "str"}, - "ip6-trusthost4": {"required": False, "type": "str"}, - "ip6-trusthost5": {"required": False, "type": "str"}, - "ip6-trusthost6": {"required": False, "type": "str"}, - "ip6-trusthost7": {"required": False, "type": "str"}, - "ip6-trusthost8": {"required": False, "type": "str"}, - "ip6-trusthost9": {"required": False, "type": "str"}, - "login-time": {"required": False, "type": "list", + "ip6_trusthost1": {"required": False, "type": "str"}, + "ip6_trusthost10": {"required": False, "type": "str"}, + "ip6_trusthost2": {"required": False, "type": "str"}, + "ip6_trusthost3": {"required": False, "type": "str"}, + "ip6_trusthost4": {"required": False, "type": "str"}, + "ip6_trusthost5": {"required": False, "type": "str"}, + "ip6_trusthost6": {"required": False, "type": "str"}, + "ip6_trusthost7": {"required": False, "type": "str"}, + "ip6_trusthost8": {"required": False, "type": "str"}, + "ip6_trusthost9": {"required": False, "type": "str"}, + "login_time": {"required": False, "type": "list", "options": { - "last-failed-login": {"required": False, "type": "str"}, - "last-login": {"required": False, "type": "str"}, - "usr-name": {"required": True, "type": "str"} + "last_failed_login": {"required": False, "type": "str"}, + "last_login": {"required": False, "type": "str"}, + "usr_name": {"required": False, "type": "str"} }}, "name": {"required": True, "type": "str"}, "password": {"required": False, "type": "str"}, - "password-expire": {"required": False, "type": "str"}, - "peer-auth": {"required": False, "type": "str", + "password_expire": {"required": False, "type": "str"}, + "peer_auth": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "peer-group": {"required": False, "type": "str"}, - "radius-vdom-override": {"required": False, "type": "str", + "peer_group": {"required": False, "type": "str"}, + "radius_vdom_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "remote-auth": {"required": False, "type": "str", + "remote_auth": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "remote-group": {"required": False, "type": "str"}, + "remote_group": {"required": False, "type": "str"}, "schedule": {"required": False, "type": "str"}, - "sms-custom-server": {"required": False, "type": "str"}, - "sms-phone": {"required": False, "type": "str"}, - "sms-server": {"required": False, "type": "str", + "sms_custom_server": {"required": False, "type": "str"}, + "sms_phone": {"required": False, "type": "str"}, + "sms_server": {"required": False, "type": "str", "choices": ["fortiguard", "custom"]}, - "ssh-certificate": {"required": False, "type": "str"}, - "ssh-public-key1": {"required": False, "type": "str"}, - "ssh-public-key2": {"required": False, "type": "str"}, - "ssh-public-key3": {"required": False, "type": "str"}, + "ssh_certificate": {"required": False, "type": "str"}, + "ssh_public_key1": {"required": False, "type": "str"}, + "ssh_public_key2": {"required": False, "type": "str"}, + "ssh_public_key3": {"required": False, "type": "str"}, "trusthost1": {"required": False, "type": "str"}, "trusthost10": {"required": False, "type": "str"}, "trusthost2": {"required": False, "type": "str"}, @@ -884,7 +943,7 @@ def main(): "trusthost7": {"required": False, "type": "str"}, "trusthost8": {"required": False, "type": "str"}, "trusthost9": {"required": False, "type": "str"}, - "two-factor": {"required": False, "type": "str", + "two_factor": {"required": False, "type": "str", "choices": ["disable", "fortitoken", "email", "sms"]}, "vdom": {"required": False, "type": "list", @@ -900,15 +959,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_api_user.py b/lib/ansible/modules/network/fortios/fortios_system_api_user.py index 8855dbf5943..d810ea76a1b 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_api_user.py +++ b/lib/ansible/modules/network/fortios/fortios_system_api_user.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_system_api_user short_description: Configure API users in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and api_user category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,96 +41,124 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_api_user: description: - Configure API users. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent accprofile: description: - Admin user access profile. Source system.accprofile.name. - api-key: + type: str + api_key: description: - Admin user password. + type: str comments: description: - Comment. - cors-allow-origin: + type: str + cors_allow_origin: description: - Value for Access-Control-Allow-Origin on API responses. Avoid using '*' if possible. + type: str name: description: - User name. required: true - peer-auth: + type: str + peer_auth: description: - Enable/disable peer authentication. + type: str choices: - enable - disable - peer-group: + peer_group: description: - Peer group name. + type: str schedule: description: - Schedule name. + type: str trusthost: description: - Trusthost. + type: list suboptions: id: description: - Table ID. required: true - ipv4-trusthost: + type: int + ipv4_trusthost: description: - IPv4 trusted host address. - ipv6-trusthost: + type: str + ipv6_trusthost: description: - IPv6 trusted host address. + type: str type: description: - Trusthost type. + type: str choices: - ipv4-trusthost - ipv6-trusthost vdom: description: - Virtual domains. + type: list suboptions: name: description: - Virtual domain name. Source system.vdom.name. required: true + type: str ''' EXAMPLES = ''' @@ -143,6 +168,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure API users. fortios_system_api_user: @@ -151,21 +177,21 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_api_user: - state: "present" accprofile: " (source system.accprofile.name)" - api-key: "" + api_key: "" comments: "" - cors-allow-origin: "" + cors_allow_origin: "" name: "default_name_7" - peer-auth: "enable" - peer-group: "" + peer_auth: "enable" + peer_group: "" schedule: "" trusthost: - id: "12" - ipv4-trusthost: "" - ipv6-trusthost: "" + ipv4_trusthost: "" + ipv6_trusthost: "" type: "ipv4-trusthost" vdom: - @@ -232,14 +258,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']: @@ -247,13 +275,13 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_api_user_data(json): - option_list = ['accprofile', 'api-key', 'comments', - 'cors-allow-origin', 'name', 'peer-auth', - 'peer-group', 'schedule', 'trusthost', + option_list = ['accprofile', 'api_key', 'comments', + 'cors_allow_origin', 'name', 'peer_auth', + 'peer_group', 'schedule', 'trusthost', 'vdom'] dictionary = {} @@ -264,75 +292,80 @@ def filter_system_api_user_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 system_api_user(data, fos): vdom = data['vdom'] + state = data['state'] system_api_user_data = data['system_api_user'] - flattened_data = flatten_multilists_attributes(system_api_user_data) - filtered_data = filter_system_api_user_data(flattened_data) - if system_api_user_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_api_user_data(system_api_user_data)) + + if state == "present": return fos.set('system', 'api-user', data=filtered_data, vdom=vdom) - elif system_api_user_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'api-user', 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_system(data, fos): - login(data) if data['system_api_user']: resp = system_api_user(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_api_user": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "accprofile": {"required": False, "type": "str"}, - "api-key": {"required": False, "type": "str"}, + "api_key": {"required": False, "type": "str"}, "comments": {"required": False, "type": "str"}, - "cors-allow-origin": {"required": False, "type": "str"}, + "cors_allow_origin": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, - "peer-auth": {"required": False, "type": "str", + "peer_auth": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "peer-group": {"required": False, "type": "str"}, + "peer_group": {"required": False, "type": "str"}, "schedule": {"required": False, "type": "str"}, "trusthost": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "ipv4-trusthost": {"required": False, "type": "str"}, - "ipv6-trusthost": {"required": False, "type": "str"}, + "ipv4_trusthost": {"required": False, "type": "str"}, + "ipv6_trusthost": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", "choices": ["ipv4-trusthost", "ipv6-trusthost"]} }}, @@ -347,15 +380,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_central_management.py b/lib/ansible/modules/network/fortios/fortios_system_central_management.py index c13ed6809fd..f239016bbad 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_central_management.py +++ b/lib/ansible/modules/network/fortios/fortios_system_central_management.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_system_central_management -short_description: Configure central management. +short_description: Configure central management in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure system feature and central_management category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify system feature and central_management category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,61 +41,76 @@ 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 system_central_management: description: - Configure central management. default: null + type: dict suboptions: - allow-monitor: + allow_monitor: description: - Enable/disable allowing the central management server to remotely monitor this FortiGate + type: str choices: - enable - disable - allow-push-configuration: + allow_push_configuration: description: - Enable/disable allowing the central management server to push configuration changes to this FortiGate. + type: str choices: - enable - disable - allow-push-firmware: + allow_push_firmware: description: - Enable/disable allowing the central management server to push firmware updates to this FortiGate. + type: str choices: - enable - disable - allow-remote-firmware-upgrade: + allow_remote_firmware_upgrade: description: - Enable/disable remotely upgrading the firmware on this FortiGate from the central management server. + type: str choices: - enable - disable - enc-algorithm: + enc_algorithm: description: - Encryption strength for communications between the FortiGate and central management. + type: str choices: - default - high @@ -106,47 +118,57 @@ options: fmg: description: - IP address or FQDN of the FortiManager. - fmg-source-ip: + type: str + fmg_source_ip: description: - IPv4 source address that this FortiGate uses when communicating with FortiManager. - fmg-source-ip6: + type: str + fmg_source_ip6: description: - IPv6 source address that this FortiGate uses when communicating with FortiManager. - include-default-servers: + type: str + include_default_servers: description: - Enable/disable inclusion of public FortiGuard servers in the override server list. + type: str choices: - enable - disable mode: description: - Central management mode. + type: str choices: - normal - backup - schedule-config-restore: + schedule_config_restore: description: - Enable/disable allowing the central management server to restore the configuration of this FortiGate. + type: str choices: - enable - disable - schedule-script-restore: + schedule_script_restore: description: - Enable/disable allowing the central management server to restore the scripts stored on this FortiGate. + type: str choices: - enable - disable - serial-number: + serial_number: description: - Serial number. - server-list: + type: str + server_list: description: - Additional severs that the FortiGate can use for updates (for AV, IPS, updates) and ratings (for web filter and antispam ratings) servers. + type: list suboptions: - addr-type: + addr_type: description: - Indicate whether the FortiGate communicates with the override server using an IPv4 address, an IPv6 address or a FQDN. + type: str choices: - ipv4 - ipv6 @@ -154,25 +176,31 @@ options: fqdn: description: - FQDN address of override server. + type: str id: description: - ID. required: true - server-address: + type: int + server_address: description: - IPv4 address of override server. - server-address6: + type: str + server_address6: description: - IPv6 address of override server. - server-type: + type: str + server_type: description: - FortiGuard service type. + type: str choices: - update - rating type: description: - Central management type. + type: str choices: - fortimanager - fortiguard @@ -180,6 +208,7 @@ options: vdom: description: - Virtual domain (VDOM) name to use when communicating with FortiManager. Source system.vdom.name. + type: str ''' EXAMPLES = ''' @@ -189,35 +218,37 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure central management. fortios_system_central_management: - host: "{{ host }}" + host: "{{ host }}" username: "{{ username }}" password: "{{ password }}" - vdom: "{{ vdom }}" + vdom: "{{ vdom }}" + https: "False" system_central_management: - allow-monitor: "enable" - allow-push-configuration: "enable" - allow-push-firmware: "enable" - allow-remote-firmware-upgrade: "enable" - enc-algorithm: "default" + allow_monitor: "enable" + allow_push_configuration: "enable" + allow_push_firmware: "enable" + allow_remote_firmware_upgrade: "enable" + enc_algorithm: "default" fmg: "" - fmg-source-ip: "" - fmg-source-ip6: "" - include-default-servers: "enable" + fmg_source_ip: "" + fmg_source_ip6: "" + include_default_servers: "enable" mode: "normal" - schedule-config-restore: "enable" - schedule-script-restore: "enable" - serial-number: "" - server-list: + schedule_config_restore: "enable" + schedule_script_restore: "enable" + serial_number: "" + server_list: - - addr-type: "ipv4" + addr_type: "ipv4" fqdn: "" id: "19" - server-address: "" - server-address6: "" - server-type: "update" + server_address: "" + server_address6: "" + server_type: "update" type: "fortimanager" vdom: " (source system.vdom.name)" ''' @@ -242,7 +273,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 @@ -282,14 +313,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']: @@ -297,90 +330,106 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_central_management_data(json): - option_list = ['allow-monitor', 'allow-push-configuration', 'allow-push-firmware', - 'allow-remote-firmware-upgrade', 'enc-algorithm', 'fmg', - 'fmg-source-ip', 'fmg-source-ip6', 'include-default-servers', - 'mode', 'schedule-config-restore', 'schedule-script-restore', - 'serial-number', 'server-list', 'type', + option_list = ['allow_monitor', 'allow_push_configuration', 'allow_push_firmware', + 'allow_remote_firmware_upgrade', 'enc_algorithm', 'fmg', + 'fmg_source_ip', 'fmg_source_ip6', 'include_default_servers', + 'mode', 'schedule_config_restore', 'schedule_script_restore', + 'serial_number', 'server_list', 'type', 'vdom'] 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 system_central_management(data, fos): vdom = data['vdom'] system_central_management_data = data['system_central_management'] - filtered_data = filter_system_central_management_data( - system_central_management_data) + filtered_data = underscore_to_hyphen(filter_system_central_management_data(system_central_management_data)) + return fos.set('system', 'central-management', 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_system(data, fos): - login(data) - methodlist = ['system_central_management'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['system_central_management']: + resp = system_central_management(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "system_central_management": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "allow-monitor": {"required": False, "type": "str", + "allow_monitor": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "allow-push-configuration": {"required": False, "type": "str", + "allow_push_configuration": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "allow-push-firmware": {"required": False, "type": "str", + "allow_push_firmware": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "allow-remote-firmware-upgrade": {"required": False, "type": "str", + "allow_remote_firmware_upgrade": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "enc-algorithm": {"required": False, "type": "str", + "enc_algorithm": {"required": False, "type": "str", "choices": ["default", "high", "low"]}, "fmg": {"required": False, "type": "str"}, - "fmg-source-ip": {"required": False, "type": "str"}, - "fmg-source-ip6": {"required": False, "type": "str"}, - "include-default-servers": {"required": False, "type": "str", + "fmg_source_ip": {"required": False, "type": "str"}, + "fmg_source_ip6": {"required": False, "type": "str"}, + "include_default_servers": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "mode": {"required": False, "type": "str", "choices": ["normal", "backup"]}, - "schedule-config-restore": {"required": False, "type": "str", + "schedule_config_restore": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "schedule-script-restore": {"required": False, "type": "str", + "schedule_script_restore": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "serial-number": {"required": False, "type": "str"}, - "server-list": {"required": False, "type": "list", + "serial_number": {"required": False, "type": "str"}, + "server_list": {"required": False, "type": "list", "options": { - "addr-type": {"required": False, "type": "str", + "addr_type": {"required": False, "type": "str", "choices": ["ipv4", "ipv6", "fqdn"]}, "fqdn": {"required": False, "type": "str"}, "id": {"required": True, "type": "int"}, - "server-address": {"required": False, "type": "str"}, - "server-address6": {"required": False, "type": "str"}, - "server-type": {"required": False, "type": "str", + "server_address": {"required": False, "type": "str"}, + "server_address6": {"required": False, "type": "str"}, + "server_type": {"required": False, "type": "str", "choices": ["update", "rating"]} }}, "type": {"required": False, "type": "str", @@ -393,15 +442,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_dhcp_server.py b/lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py index 18f5db71e32..9c5738b38e1 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py +++ b/lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py @@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function) # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# the lib use python logging can get it if the following is set in your -# Ansible config. __metaclass__ = type @@ -29,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_system_dhcp_server short_description: Configure DHCP servers in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system_dhcp feature and server category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,97 +41,125 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_dhcp_server: description: - Configure DHCP servers. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - auto-configuration: + auto_configuration: description: - Enable/disable auto configuration. + type: str choices: - disable - enable - conflicted-ip-timeout: + conflicted_ip_timeout: description: - Time in seconds to wait after a conflicted IP address is removed from the DHCP range before it can be reused. - ddns-auth: + type: int + ddns_auth: description: - DDNS authentication mode. + type: str choices: - disable - tsig - ddns-key: + ddns_key: description: - DDNS update key (base 64 encoding). - ddns-keyname: + type: str + ddns_keyname: description: - DDNS update key name. - ddns-server-ip: + type: str + ddns_server_ip: description: - DDNS server IP. - ddns-ttl: + type: str + ddns_ttl: description: - TTL. - ddns-update: + type: int + ddns_update: description: - Enable/disable DDNS update for DHCP. + type: str choices: - disable - enable - ddns-update-override: + ddns_update_override: description: - Enable/disable DDNS update override for DHCP. + type: str choices: - disable - enable - ddns-zone: + ddns_zone: description: - Zone of your domain name (ex. DDNS.com). - default-gateway: + type: str + default_gateway: description: - Default gateway IP address assigned by the DHCP server. - dns-server1: + type: str + dns_server1: description: - DNS server 1. - dns-server2: + type: str + dns_server2: description: - DNS server 2. - dns-server3: + type: str + dns_server3: description: - DNS server 3. - dns-service: + type: str + dns_service: description: - Options for assigning DNS servers to DHCP clients. + type: str choices: - local - default @@ -142,26 +167,33 @@ options: domain: description: - Domain name suffix for the IP addresses that the DHCP server assigns to clients. - exclude-range: + type: str + exclude_range: description: - Exclude one or more ranges of IP addresses from being assigned to clients. + type: list suboptions: - end-ip: + end_ip: description: - End of IP range. + type: str id: description: - ID. required: true - start-ip: + type: int + start_ip: description: - Start of IP range. + type: str filename: description: - Name of the boot file on the TFTP server. - forticlient-on-net-status: + type: str + forticlient_on_net_status: description: - Enable/disable FortiClient-On-Net service for this DHCP server. + type: str choices: - disable - enable @@ -169,59 +201,75 @@ options: description: - ID. required: true + type: int interface: description: - DHCP server can assign IP configurations to clients connected to this interface. Source system.interface.name. - ip-mode: + type: str + ip_mode: description: - Method used to assign client IP. + type: str choices: - range - usrgrp - ip-range: + ip_range: description: - DHCP IP range configuration. + type: list suboptions: - end-ip: + end_ip: description: - End of IP range. + type: str id: description: - ID. required: true - start-ip: + type: int + start_ip: description: - Start of IP range. - ipsec-lease-hold: + type: str + ipsec_lease_hold: description: - DHCP over IPsec leases expire this many seconds after tunnel down (0 to disable forced-expiry). - lease-time: + type: int + lease_time: description: - Lease time in seconds, 0 means unlimited. - mac-acl-default-action: + type: int + mac_acl_default_action: description: - MAC access control default action (allow or block assigning IP settings). + type: str choices: - assign - block netmask: description: - Netmask assigned by the DHCP server. - next-server: + type: str + next_server: description: - IP address of a server (for example, a TFTP sever) that DHCP clients can download a boot file from. - ntp-server1: + type: str + ntp_server1: description: - NTP server 1. - ntp-server2: + type: str + ntp_server2: description: - NTP server 2. - ntp-server3: + type: str + ntp_server3: description: - NTP server 3. - ntp-service: + type: str + ntp_service: description: - Options for assigning Network Time Protocol (NTP) servers to DHCP clients. + type: str choices: - local - default @@ -229,34 +277,43 @@ options: options: description: - DHCP options. + type: list suboptions: code: description: - DHCP option code. + type: int id: description: - ID. required: true + type: int ip: description: - DHCP option IPs. + type: str type: description: - DHCP option type. + type: str choices: - hex - string - ip + - fqdn value: description: - DHCP option value. - reserved-address: + type: str + reserved_address: description: - Options for the DHCP server to assign IP settings to specific MAC addresses. + type: list suboptions: action: description: - Options for the DHCP server to configure the client with the reserved MAC address. + type: str choices: - assign - block @@ -264,39 +321,47 @@ options: description: description: - Description. + type: str id: description: - ID. required: true + type: int ip: description: - IP address to be reserved for the MAC address. + type: str mac: description: - MAC address of the client that will get the reserved IP address. - server-type: + type: str + server_type: description: - DHCP server can be a normal DHCP server or an IPsec DHCP server. + type: str choices: - regular - ipsec status: description: - Enable/disable this DHCP configuration. + type: str choices: - disable - enable - tftp-server: + tftp_server: description: - One or more hostnames or IP addresses of the TFTP servers in quotes separated by spaces. + type: list suboptions: - tftp-server: + tftp_server: description: - TFTP server. - required: true + type: str timezone: description: - Select the time zone to be assigned to DHCP clients. + type: str choices: - 01 - 02 @@ -386,42 +451,50 @@ options: - 73 - 86 - 76 - timezone-option: + timezone_option: description: - Options for the DHCP server to set the client's time zone. + type: str choices: - disable - default - specify - vci-match: + vci_match: description: - Enable/disable vendor class identifier (VCI) matching. When enabled only DHCP requests with a matching VCI are served. + type: str choices: - disable - enable - vci-string: + vci_string: description: - One or more VCI strings in quotes separated by spaces. + type: list suboptions: - vci-string: + vci_string: description: - VCI strings. - required: true - wifi-ac1: + type: str + wifi_ac1: description: - WiFi Access Controller 1 IP address (DHCP option 138, RFC 5417). - wifi-ac2: + type: str + wifi_ac2: description: - WiFi Access Controller 2 IP address (DHCP option 138, RFC 5417). - wifi-ac3: + type: str + wifi_ac3: description: - WiFi Access Controller 3 IP address (DHCP option 138, RFC 5417). - wins-server1: + type: str + wins_server1: description: - WINS server 1. - wins-server2: + type: str + wins_server2: description: - WINS server 2. + type: str ''' EXAMPLES = ''' @@ -431,6 +504,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure DHCP servers. fortios_system_dhcp_server: @@ -439,48 +513,48 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_dhcp_server: - state: "present" - auto-configuration: "disable" - conflicted-ip-timeout: "4" - ddns-auth: "disable" - ddns-key: "" - ddns-keyname: "" - ddns-server-ip: "" - ddns-ttl: "9" - ddns-update: "disable" - ddns-update-override: "disable" - ddns-zone: "" - default-gateway: "" - dns-server1: "" - dns-server2: "" - dns-server3: "" - dns-service: "local" + auto_configuration: "disable" + conflicted_ip_timeout: "4" + ddns_auth: "disable" + ddns_key: "" + ddns_keyname: "" + ddns_server_ip: "" + ddns_ttl: "9" + ddns_update: "disable" + ddns_update_override: "disable" + ddns_zone: "" + default_gateway: "" + dns_server1: "" + dns_server2: "" + dns_server3: "" + dns_service: "local" domain: "" - exclude-range: + exclude_range: - - end-ip: "" + end_ip: "" id: "21" - start-ip: "" + start_ip: "" filename: "" - forticlient-on-net-status: "disable" + forticlient_on_net_status: "disable" id: "25" interface: " (source system.interface.name)" - ip-mode: "range" - ip-range: + ip_mode: "range" + ip_range: - - end-ip: "" + end_ip: "" id: "30" - start-ip: "" - ipsec-lease-hold: "32" - lease-time: "33" - mac-acl-default-action: "assign" + start_ip: "" + ipsec_lease_hold: "32" + lease_time: "33" + mac_acl_default_action: "assign" netmask: "" - next-server: "" - ntp-server1: "" - ntp-server2: "" - ntp-server3: "" - ntp-service: "local" + next_server: "" + ntp_server1: "" + ntp_server2: "" + ntp_server3: "" + ntp_service: "local" options: - code: "42" @@ -488,29 +562,29 @@ EXAMPLES = ''' ip: "" type: "hex" value: "" - reserved-address: + reserved_address: - action: "assign" description: "" id: "50" ip: "" mac: "" - server-type: "regular" + server_type: "regular" status: "disable" - tftp-server: + tftp_server: - - tftp-server: "" + tftp_server: "" timezone: "01" - timezone-option: "disable" - vci-match: "disable" - vci-string: + timezone_option: "disable" + vci_match: "disable" + vci_string: - - vci-string: "" - wifi-ac1: "" - wifi-ac2: "" - wifi-ac3: "" - wins-server1: "" - wins-server2: "" + vci_string: "" + wifi_ac1: "" + wifi_ac2: "" + wifi_ac3: "" + wins_server1: "" + wins_server2: "" ''' RETURN = ''' @@ -573,14 +647,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']: @@ -588,26 +664,26 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_dhcp_server_data(json): - option_list = ['auto-configuration', 'conflicted-ip-timeout', 'ddns-auth', - 'ddns-key', 'ddns-keyname', 'ddns-server-ip', - 'ddns-ttl', 'ddns-update', 'ddns-update-override', - 'ddns-zone', 'default-gateway', 'dns-server1', - 'dns-server2', 'dns-server3', 'dns-service', - 'domain', 'exclude-range', 'filename', - 'forticlient-on-net-status', 'id', 'interface', - 'ip-mode', 'ip-range', 'ipsec-lease-hold', - 'lease-time', 'mac-acl-default-action', 'netmask', - 'next-server', 'ntp-server1', 'ntp-server2', - 'ntp-server3', 'ntp-service', 'options', - 'reserved-address', 'server-type', 'status', - 'tftp-server', 'timezone', 'timezone-option', - 'vci-match', 'vci-string', 'wifi-ac1', - 'wifi-ac2', 'wifi-ac3', 'wins-server1', - 'wins-server2'] + option_list = ['auto_configuration', 'conflicted_ip_timeout', 'ddns_auth', + 'ddns_key', 'ddns_keyname', 'ddns_server_ip', + 'ddns_ttl', 'ddns_update', 'ddns_update_override', + 'ddns_zone', 'default_gateway', 'dns_server1', + 'dns_server2', 'dns_server3', 'dns_service', + 'domain', 'exclude_range', 'filename', + 'forticlient_on_net_status', 'id', 'interface', + 'ip_mode', 'ip_range', 'ipsec_lease_hold', + 'lease_time', 'mac_acl_default_action', 'netmask', + 'next_server', 'ntp_server1', 'ntp_server2', + 'ntp_server3', 'ntp_service', 'options', + 'reserved_address', 'server_type', 'status', + 'tftp_server', 'timezone', 'timezone_option', + 'vci_match', 'vci_string', 'wifi_ac1', + 'wifi_ac2', 'wifi_ac3', 'wins_server1', + 'wins_server2'] dictionary = {} for attribute in option_list: @@ -617,111 +693,116 @@ def filter_system_dhcp_server_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 system_dhcp_server(data, fos): vdom = data['vdom'] + state = data['state'] system_dhcp_server_data = data['system_dhcp_server'] - flattened_data = flatten_multilists_attributes(system_dhcp_server_data) - filtered_data = filter_system_dhcp_server_data(flattened_data) - if system_dhcp_server_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_dhcp_server_data(system_dhcp_server_data)) + + if state == "present": return fos.set('system.dhcp', 'server', data=filtered_data, vdom=vdom) - elif system_dhcp_server_data['state'] == "absent": + elif state == "absent": return fos.delete('system.dhcp', 'server', 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_system_dhcp(data, fos): - login(data) if data['system_dhcp_server']: resp = system_dhcp_server(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_dhcp_server": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "auto-configuration": {"required": False, "type": "str", + "auto_configuration": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "conflicted-ip-timeout": {"required": False, "type": "int"}, - "ddns-auth": {"required": False, "type": "str", + "conflicted_ip_timeout": {"required": False, "type": "int"}, + "ddns_auth": {"required": False, "type": "str", "choices": ["disable", "tsig"]}, - "ddns-key": {"required": False, "type": "str"}, - "ddns-keyname": {"required": False, "type": "str"}, - "ddns-server-ip": {"required": False, "type": "str"}, - "ddns-ttl": {"required": False, "type": "int"}, - "ddns-update": {"required": False, "type": "str", + "ddns_key": {"required": False, "type": "str"}, + "ddns_keyname": {"required": False, "type": "str"}, + "ddns_server_ip": {"required": False, "type": "str"}, + "ddns_ttl": {"required": False, "type": "int"}, + "ddns_update": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "ddns-update-override": {"required": False, "type": "str", + "ddns_update_override": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "ddns-zone": {"required": False, "type": "str"}, - "default-gateway": {"required": False, "type": "str"}, - "dns-server1": {"required": False, "type": "str"}, - "dns-server2": {"required": False, "type": "str"}, - "dns-server3": {"required": False, "type": "str"}, - "dns-service": {"required": False, "type": "str", + "ddns_zone": {"required": False, "type": "str"}, + "default_gateway": {"required": False, "type": "str"}, + "dns_server1": {"required": False, "type": "str"}, + "dns_server2": {"required": False, "type": "str"}, + "dns_server3": {"required": False, "type": "str"}, + "dns_service": {"required": False, "type": "str", "choices": ["local", "default", "specify"]}, "domain": {"required": False, "type": "str"}, - "exclude-range": {"required": False, "type": "list", + "exclude_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"} }}, "filename": {"required": False, "type": "str"}, - "forticlient-on-net-status": {"required": False, "type": "str", + "forticlient_on_net_status": {"required": False, "type": "str", "choices": ["disable", "enable"]}, "id": {"required": True, "type": "int"}, "interface": {"required": False, "type": "str"}, - "ip-mode": {"required": False, "type": "str", + "ip_mode": {"required": False, "type": "str", "choices": ["range", "usrgrp"]}, - "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"} }}, - "ipsec-lease-hold": {"required": False, "type": "int"}, - "lease-time": {"required": False, "type": "int"}, - "mac-acl-default-action": {"required": False, "type": "str", + "ipsec_lease_hold": {"required": False, "type": "int"}, + "lease_time": {"required": False, "type": "int"}, + "mac_acl_default_action": {"required": False, "type": "str", "choices": ["assign", "block"]}, "netmask": {"required": False, "type": "str"}, - "next-server": {"required": False, "type": "str"}, - "ntp-server1": {"required": False, "type": "str"}, - "ntp-server2": {"required": False, "type": "str"}, - "ntp-server3": {"required": False, "type": "str"}, - "ntp-service": {"required": False, "type": "str", + "next_server": {"required": False, "type": "str"}, + "ntp_server1": {"required": False, "type": "str"}, + "ntp_server2": {"required": False, "type": "str"}, + "ntp_server3": {"required": False, "type": "str"}, + "ntp_service": {"required": False, "type": "str", "choices": ["local", "default", "specify"]}, "options": {"required": False, "type": "list", "options": { @@ -729,10 +810,11 @@ def main(): "id": {"required": True, "type": "int"}, "ip": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", - "choices": ["hex", "string", "ip"]}, + "choices": ["hex", "string", "ip", + "fqdn"]}, "value": {"required": False, "type": "str"} }}, - "reserved-address": {"required": False, "type": "list", + "reserved_address": {"required": False, "type": "list", "options": { "action": {"required": False, "type": "str", "choices": ["assign", "block", "reserved"]}, @@ -741,13 +823,13 @@ def main(): "ip": {"required": False, "type": "str"}, "mac": {"required": False, "type": "str"} }}, - "server-type": {"required": False, "type": "str", + "server_type": {"required": False, "type": "str", "choices": ["regular", "ipsec"]}, "status": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "tftp-server": {"required": False, "type": "list", + "tftp_server": {"required": False, "type": "list", "options": { - "tftp-server": {"required": True, "type": "str"} + "tftp_server": {"required": False, "type": "str"} }}, "timezone": {"required": False, "type": "str", "choices": ["01", "02", "03", @@ -780,19 +862,19 @@ def main(): "71", "72", "00", "82", "73", "86", "76"]}, - "timezone-option": {"required": False, "type": "str", + "timezone_option": {"required": False, "type": "str", "choices": ["disable", "default", "specify"]}, - "vci-match": {"required": False, "type": "str", + "vci_match": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "vci-string": {"required": False, "type": "list", + "vci_string": {"required": False, "type": "list", "options": { - "vci-string": {"required": True, "type": "str"} + "vci_string": {"required": False, "type": "str"} }}, - "wifi-ac1": {"required": False, "type": "str"}, - "wifi-ac2": {"required": False, "type": "str"}, - "wifi-ac3": {"required": False, "type": "str"}, - "wins-server1": {"required": False, "type": "str"}, - "wins-server2": {"required": False, "type": "str"} + "wifi_ac1": {"required": False, "type": "str"}, + "wifi_ac2": {"required": False, "type": "str"}, + "wifi_ac3": {"required": False, "type": "str"}, + "wins_server1": {"required": False, "type": "str"}, + "wins_server2": {"required": False, "type": "str"} } } @@ -800,15 +882,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system_dhcp(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_system_dhcp(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system_dhcp(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_system_dns.py b/lib/ansible/modules/network/fortios/fortios_system_dns.py index 374d0bd1894..0c36b96e1e9 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_dns.py +++ b/lib/ansible/modules/network/fortios/fortios_system_dns.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_system_dns short_description: Configure DNS in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and dns category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,64 +41,97 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 system_dns: description: - Configure DNS. default: null + type: dict suboptions: - cache-notfound-responses: + cache_notfound_responses: description: - Enable/disable response from the DNS server when a record is not in cache. + type: str choices: - disable - enable - dns-cache-limit: + dns_cache_limit: description: - Maximum number of records in the DNS cache. - dns-cache-ttl: + type: int + dns_cache_ttl: description: - Duration in seconds that the DNS cache retains information. + type: int domain: description: - - Domain name suffix for the IP addresses of the DNS server. - ip6-primary: + - Search suffix list for hostname lookup. + type: list + suboptions: + domain: + description: + - DNS search domain list separated by space (maximum 8 domains) + required: true + type: str + ip6_primary: description: - Primary DNS server IPv6 address. - ip6-secondary: + type: str + ip6_secondary: description: - Secondary DNS server IPv6 address. + type: str primary: description: - - Primary DNS server IP address, default is FortiGuard server at 208.81.112.53. + - Primary DNS server IP address. + type: str + retry: + description: + - Number of times to retry (0 - 5). + type: int secondary: description: - - Secondary DNS server IP address, default is FortiGuard server at 208.81.112.52. - source-ip: + - Secondary DNS server IP address. + type: str + source_ip: description: - IP address used by the DNS server as its source IP. + type: str + timeout: + description: + - DNS query timeout interval in seconds (1 - 10). + type: int ''' EXAMPLES = ''' @@ -111,6 +141,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure DNS. fortios_system_dns: @@ -120,15 +151,19 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" system_dns: - cache-notfound-responses: "disable" - dns-cache-limit: "4" - dns-cache-ttl: "5" - domain: "" - ip6-primary: "" - ip6-secondary: "" + cache_notfound_responses: "disable" + dns_cache_limit: "4" + dns_cache_ttl: "5" + domain: + - + domain: "" + ip6_primary: "" + ip6_secondary: "" primary: "" + retry: "11" secondary: "" - source-ip: "84.230.14.43" + source_ip: "84.230.14.43" + timeout: "14" ''' RETURN = ''' @@ -191,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']: @@ -206,13 +243,14 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_dns_data(json): - option_list = ['cache-notfound-responses', 'dns-cache-limit', 'dns-cache-ttl', - 'domain', 'ip6-primary', 'ip6-secondary', - 'primary', 'secondary', 'source-ip'] + option_list = ['cache_notfound_responses', 'dns_cache_limit', 'dns_cache_ttl', + 'domain', 'ip6_primary', 'ip6_secondary', + 'primary', 'retry', 'secondary', + 'source_ip', 'timeout'] dictionary = {} for attribute in option_list: @@ -222,17 +260,15 @@ def filter_system_dns_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 @@ -240,44 +276,55 @@ def flatten_multilists_attributes(data): def system_dns(data, fos): vdom = data['vdom'] system_dns_data = data['system_dns'] - flattened_data = flatten_multilists_attributes(system_dns_data) - filtered_data = filter_system_dns_data(flattened_data) + filtered_data = underscore_to_hyphen(filter_system_dns_data(system_dns_data)) + return fos.set('system', 'dns', 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_system(data, fos): - login(data) if data['system_dns']: resp = system_dns(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "system_dns": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "cache-notfound-responses": {"required": False, "type": "str", + "cache_notfound_responses": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "dns-cache-limit": {"required": False, "type": "int"}, - "dns-cache-ttl": {"required": False, "type": "int"}, - "domain": {"required": False, "type": "str"}, - "ip6-primary": {"required": False, "type": "str"}, - "ip6-secondary": {"required": False, "type": "str"}, + "dns_cache_limit": {"required": False, "type": "int"}, + "dns_cache_ttl": {"required": False, "type": "int"}, + "domain": {"required": False, "type": "list", + "options": { + "domain": {"required": True, "type": "str"} + }}, + "ip6_primary": {"required": False, "type": "str"}, + "ip6_secondary": {"required": False, "type": "str"}, "primary": {"required": False, "type": "str"}, + "retry": {"required": False, "type": "int"}, "secondary": {"required": False, "type": "str"}, - "source-ip": {"required": False, "type": "str"} + "source_ip": {"required": False, "type": "str"}, + "timeout": {"required": False, "type": "int"} } } @@ -285,15 +332,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_global.py b/lib/ansible/modules/network/fortios/fortios_system_global.py index b55dc94fd3e..11b7fab3c89 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_global.py +++ b/lib/ansible/modules/network/fortios/fortios_system_global.py @@ -26,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_system_global short_description: Configure global attributes in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and global category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -41,275 +41,333 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 system_global: description: - Configure global attributes. default: null + type: dict suboptions: - admin-concurrent: + admin_concurrent: description: - Enable/disable concurrent administrator logins. (Use policy-auth-concurrent for firewall authenticated users.) + type: str choices: - enable - disable - admin-console-timeout: + admin_console_timeout: description: - Console login timeout that overrides the admintimeout value. (15 - 300 seconds) (15 seconds to 5 minutes). 0 the default, disables this timeout. - admin-https-pki-required: + type: int + admin_https_pki_required: description: - Enable/disable admin login method. Enable to force administrators to provide a valid certificate to log in if PKI is enabled. Disable to allow administrators to log in with a certificate or password. + type: str choices: - enable - disable - admin-https-ssl-versions: + admin_https_ssl_versions: description: - Allowed TLS versions for web administration. + type: list choices: - tlsv1-0 - tlsv1-1 - tlsv1-2 - admin-lockout-duration: + admin_lockout_duration: description: - Amount of time in seconds that an administrator account is locked out after reaching the admin-lockout-threshold for repeated failed login attempts. - admin-lockout-threshold: + type: int + admin_lockout_threshold: description: - Number of failed login attempts before an administrator account is locked out for the admin-lockout-duration. - admin-login-max: + type: int + admin_login_max: description: - - Maximum number of administrators who can be logged in at the same time (1 - 100, default = 100) - admin-maintainer: + - Maximum number of administrators who can be logged in at the same time (1 - 100) + type: int + admin_maintainer: description: - Enable/disable maintainer administrator login. When enabled, the maintainer account can be used to log in from the console after a hard reboot. The password is "bcpb" followed by the FortiGate unit serial number. You have limited time to complete this login. + type: str choices: - enable - disable - admin-port: + admin_port: description: - - Administrative access port for HTTP. (1 - 65535, default = 80). - admin-restrict-local: + - Administrative access port for HTTP. (1 - 65535). + type: int + admin_restrict_local: description: - - Enable/disable local admin authentication restriction when remote authenticator is up and running. (default = disable) + - Enable/disable local admin authentication restriction when remote authenticator is up and running. + type: str choices: - enable - disable - admin-scp: + admin_scp: description: - Enable/disable using SCP to download the system configuration. You can use SCP as an alternative method for backing up the configuration. + type: str choices: - enable - disable - admin-server-cert: + admin_server_cert: description: - Server certificate that the FortiGate uses for HTTPS administrative connections. Source certificate.local.name. - admin-sport: + type: str + admin_sport: description: - - Administrative access port for HTTPS. (1 - 65535, default = 443). - admin-ssh-grace-time: + - Administrative access port for HTTPS. (1 - 65535). + type: int + admin_ssh_grace_time: description: - - Maximum time in seconds permitted between making an SSH connection to the FortiGate unit and authenticating (10 - 3600 sec (1 hour), - default 120). - admin-ssh-password: + - Maximum time in seconds permitted between making an SSH connection to the FortiGate unit and authenticating (10 - 3600 sec (1 hour)). + type: int + admin_ssh_password: description: - Enable/disable password authentication for SSH admin access. + type: str choices: - enable - disable - admin-ssh-port: + admin_ssh_port: description: - - Administrative access port for SSH. (1 - 65535, default = 22). - admin-ssh-v1: + - Administrative access port for SSH. (1 - 65535). + type: int + admin_ssh_v1: description: - Enable/disable SSH v1 compatibility. + type: str choices: - enable - disable - admin-telnet-port: + admin_telnet_port: description: - - Administrative access port for TELNET. (1 - 65535, default = 23). + - Administrative access port for TELNET. (1 - 65535). + type: int admintimeout: description: - - Number of minutes before an idle administrator session times out (5 - 480 minutes (8 hours), default = 5). A shorter idle timeout is - more secure. + - Number of minutes before an idle administrator session times out (5 - 480 minutes (8 hours)). A shorter idle timeout is more secure. + type: int alias: description: - Alias for your FortiGate unit. - allow-traffic-redirect: + type: str + allow_traffic_redirect: description: - Disable to allow traffic to be routed back on a different interface. + type: str choices: - enable - disable - anti-replay: + anti_replay: description: - Level of checking for packet replay and TCP sequence checking. + type: str choices: - disable - loose - strict - arp-max-entry: + arp_max_entry: description: - - Maximum number of dynamically learned MAC addresses that can be added to the ARP table (131072 - 2147483647, default = 131072). + - Maximum number of dynamically learned MAC addresses that can be added to the ARP table (131072 - 2147483647). + type: int asymroute: description: - Enable/disable asymmetric route. + type: str choices: - enable - disable - auth-cert: + auth_cert: description: - Server certificate that the FortiGate uses for HTTPS firewall authentication connections. Source certificate.local.name. - auth-http-port: + type: str + auth_http_port: description: - - User authentication HTTP port. (1 - 65535, default = 80). - auth-https-port: + - User authentication HTTP port. (1 - 65535). + type: int + auth_https_port: description: - - User authentication HTTPS port. (1 - 65535, default = 443). - auth-keepalive: + - User authentication HTTPS port. (1 - 65535). + type: int + auth_keepalive: description: - Enable to prevent user authentication sessions from timing out when idle. + type: str choices: - enable - disable - auth-session-limit: + auth_session_limit: description: - Action to take when the number of allowed user authenticated sessions is reached. + type: str choices: - block-new - logout-inactive - auto-auth-extension-device: + auto_auth_extension_device: description: - Enable/disable automatic authorization of dedicated Fortinet extension devices. + type: str choices: - enable - disable - av-affinity: + av_affinity: description: - Affinity setting for AV scanning (hexadecimal value up to 256 bits in the format of xxxxxxxxxxxxxxxx). - av-failopen: + type: str + av_failopen: description: - Set the action to take if the FortiGate is running low on memory or the proxy connection limit has been reached. + type: str choices: - pass - off - one-shot - av-failopen-session: + av_failopen_session: description: - When enabled and a proxy for a protocol runs out of room in its session table, that protocol goes into failopen mode and enacts the action specified by av-failopen. + type: str choices: - enable - disable - batch-cmdb: + batch_cmdb: description: - Enable/disable batch mode, allowing you to enter a series of CLI commands that will execute as a group once they are loaded. + type: str choices: - enable - disable - block-session-timer: + block_session_timer: description: - - Duration in seconds for blocked sessions (1 - 300 sec (5 minutes), default = 30). - br-fdb-max-entry: + - Duration in seconds for blocked sessions (1 - 300 sec (5 minutes)). + type: int + br_fdb_max_entry: description: - Maximum number of bridge forwarding database (FDB) entries. - cert-chain-max: + type: int + cert_chain_max: description: - Maximum number of certificates that can be traversed in a certificate chain. - cfg-revert-timeout: + type: int + cfg_revert_timeout: description: - Time-out for reverting to the last saved configuration. - cfg-save: + type: int + cfg_save: description: - Configuration file save mode for CLI changes. + type: str choices: - automatic - manual - revert - check-protocol-header: + check_protocol_header: description: - Level of checking performed on protocol headers. Strict checking is more thorough but may affect performance. Loose checking is ok in most cases. + type: str choices: - loose - strict - check-reset-range: + check_reset_range: description: - Configure ICMP error message verification. You can either apply strict RST range checking or disable it. + type: str choices: - strict - disable - cli-audit-log: + cli_audit_log: description: - Enable/disable CLI audit log. + type: str choices: - enable - disable - clt-cert-req: + clt_cert_req: description: - Enable/disable requiring administrators to have a client certificate to log into the GUI using HTTPS. + type: str choices: - enable - disable - compliance-check: + compliance_check: description: - Enable/disable global PCI DSS compliance check. + type: str choices: - enable - disable - compliance-check-time: + compliance_check_time: description: - Time of day to run scheduled PCI DSS compliance checks. - cpu-use-threshold: + type: str + cpu_use_threshold: description: - - Threshold at which CPU usage is reported. (% of total CPU, default = 90). - csr-ca-attribute: + - Threshold at which CPU usage is reported. (% of total CPU). + type: int + csr_ca_attribute: description: - Enable/disable the CA attribute in certificates. Some CA servers reject CSRs that have the CA attribute. + type: str choices: - enable - disable - daily-restart: + daily_restart: description: - Enable/disable daily restart of FortiGate unit. Use the restart-time option to set the time of day for the restart. + type: str choices: - enable - disable - device-identification-active-scan-delay: + device_identification_active_scan_delay: description: - - Number of seconds to passively scan a device before performing an active scan. (20 - 3600 sec, (20 sec to 1 hour), default = 90). - device-idle-timeout: + - Number of seconds to passively scan a device before performing an active scan. (20 - 3600 sec, (20 sec to 1 hour)). + type: int + device_idle_timeout: description: - - Time in seconds that a device must be idle to automatically log the device user out. (30 - 31536000 sec (30 sec to 1 year), default = - 300). - dh-params: + - Time in seconds that a device must be idle to automatically log the device user out. (30 - 31536000 sec (30 sec to 1 year)). + type: int + dh_params: description: - Number of bits to use in the Diffie-Hellman exchange for HTTPS/SSH protocols. + type: str choices: - 1024 - 1536 @@ -318,37 +376,48 @@ options: - 4096 - 6144 - 8192 + dnsproxy_worker_count: + description: + - DNS proxy worker count. + type: int dst: description: - Enable/disable daylight saving time. + type: str choices: - enable - disable - endpoint-control-fds-access: + endpoint_control_fds_access: description: - Enable/disable access to the FortiGuard network for non-compliant endpoints. + type: str choices: - enable - disable - endpoint-control-portal-port: + endpoint_control_portal_port: description: - Endpoint control portal port (1 - 65535). + type: int failtime: description: - Fail-time for server lost. - fds-statistics: + type: int + fds_statistics: description: - Enable/disable sending IPS, Application Control, and AntiVirus data to FortiGuard. This data is used to improve FortiGuard services and is not shared with external parties and is protected by Fortinet's privacy policy. + type: str choices: - enable - disable - fds-statistics-period: + fds_statistics_period: description: - - FortiGuard statistics collection period in minutes. (1 - 1440 min (1 min to 24 hours), default = 60). - fgd-alert-subscription: + - FortiGuard statistics collection period in minutes. (1 - 1440 min (1 min to 24 hours)). + type: int + fgd_alert_subscription: description: - Type of alert to retrieve from FortiGuard. + type: str choices: - advisory - latest-threat @@ -359,37 +428,43 @@ options: fortiextender: description: - Enable/disable FortiExtender. + type: str choices: - enable - disable - fortiextender-data-port: + fortiextender_data_port: description: - - FortiExtender data port (1024 - 49150, default = 25246). - fortiextender-vlan-mode: + - FortiExtender data port (1024 - 49150). + type: int + fortiextender_vlan_mode: description: - Enable/disable FortiExtender VLAN mode. + type: str choices: - enable - disable - fortiservice-port: + fortiservice_port: description: - - FortiService port (1 - 65535, default = 8013). Used by FortiClient endpoint compliance. Older versions of FortiClient used a different - port. - gui-certificates: + - FortiService port (1 - 65535). Used by FortiClient endpoint compliance. Older versions of FortiClient used a different port. + type: int + gui_certificates: description: - Enable/disable the System > Certificate GUI page, allowing you to add and configure certificates from the GUI. + type: str choices: - enable - disable - gui-custom-language: + gui_custom_language: description: - Enable/disable custom languages in GUI. + type: str choices: - enable - disable - gui-date-format: + gui_date_format: description: - Default date format used throughout GUI. + type: str choices: - yyyy/MM/dd - dd/MM/yyyy @@ -397,95 +472,114 @@ options: - yyyy-MM-dd - dd-MM-yyyy - MM-dd-yyyy - gui-device-latitude: + gui_device_latitude: description: - Add the latitude of the location of this FortiGate to position it on the Threat Map. - gui-device-longitude: + type: str + gui_device_longitude: description: - Add the longitude of the location of this FortiGate to position it on the Threat Map. - gui-display-hostname: + type: str + gui_display_hostname: description: - Enable/disable displaying the FortiGate's hostname on the GUI login page. + type: str choices: - enable - disable - gui-ipv6: + gui_ipv6: description: - Enable/disable IPv6 settings on the GUI. + type: str choices: - enable - disable - gui-lines-per-page: + gui_lines_per_page: description: - Number of lines to display per page for web administration. - gui-theme: + type: int + gui_theme: description: - Color scheme for the administration GUI. + type: str choices: - green - red - blue - melongene - mariner - gui-wireless-opensecurity: + gui_wireless_opensecurity: description: - Enable/disable wireless open security option on the GUI. + type: str choices: - enable - disable - honor-df: + honor_df: description: - Enable/disable honoring of Don't-Fragment (DF) flag. + type: str choices: - enable - disable hostname: description: - FortiGate unit's hostname. Most models will truncate names longer than 24 characters. Some models support hostnames up to 35 characters. - igmp-state-limit: + type: str + igmp_state_limit: description: - - Maximum number of IGMP memberships (96 - 64000, default = 3200). + - Maximum number of IGMP memberships (96 - 64000). + type: int interval: description: - Dead gateway detection interval. - ip-src-port-range: + type: int + ip_src_port_range: description: - IP source port range used for traffic originating from the FortiGate unit. - ips-affinity: + type: str + ips_affinity: description: - Affinity setting for IPS (hexadecimal value up to 256 bits in the format of xxxxxxxxxxxxxxxx; allowed CPUs must be less than total number of IPS engine daemons). - ipsec-asic-offload: + type: str + ipsec_asic_offload: description: - Enable/disable ASIC offloading (hardware acceleration) for IPsec VPN traffic. Hardware acceleration can offload IPsec VPN sessions and accelerate encryption and decryption. + type: str choices: - enable - disable - ipsec-hmac-offload: + ipsec_hmac_offload: description: - Enable/disable offloading (hardware acceleration) of HMAC processing for IPsec VPN. + type: str choices: - enable - disable - ipsec-soft-dec-async: + ipsec_soft_dec_async: description: - Enable/disable software decryption asynchronization (using multiple CPUs to do decryption) for IPsec VPN traffic. + type: str choices: - enable - disable - ipv6-accept-dad: + ipv6_accept_dad: description: - Enable/disable acceptance of IPv6 Duplicate Address Detection (DAD). - ipv6-allow-anycast-probe: + type: int + ipv6_allow_anycast_probe: description: - Enable/disable IPv6 address probe through Anycast. + type: str choices: - enable - disable language: description: - GUI display language. + type: str choices: - english - french @@ -497,319 +591,415 @@ options: - korean ldapconntimeout: description: - - Global timeout for connections with remote LDAP servers in milliseconds (0 - 4294967295, default 500). - lldp-transmission: + - Global timeout for connections with remote LDAP servers in milliseconds (1 - 300000). + type: int + lldp_transmission: description: - Enable/disable Link Layer Discovery Protocol (LLDP) transmission. + type: str choices: - enable - disable - log-ssl-connection: + log_ssl_connection: description: - Enable/disable logging of SSL connection events. + type: str choices: - enable - disable - log-uuid: + log_uuid: description: - Whether UUIDs are added to traffic logs. You can disable UUIDs, add firewall policy UUIDs to traffic logs, or add all UUIDs to traffic logs. + type: str choices: - disable - policy-only - extended - login-timestamp: + login_timestamp: description: - Enable/disable login time recording. + type: str choices: - enable - disable - long-vdom-name: + long_vdom_name: description: - Enable/disable long VDOM name support. + type: str choices: - enable - disable - management-vdom: + management_vdom: description: - Management virtual domain name. Source system.vdom.name. - max-dlpstat-memory: + type: str + max_dlpstat_memory: description: - Maximum DLP stat memory (0 - 4294967295). - max-route-cache-size: + type: int + max_route_cache_size: description: - Maximum number of IP route cache entries (0 - 2147483647). - mc-ttl-notchange: + type: int + mc_ttl_notchange: description: - Enable/disable no modification of multicast TTL. + type: str choices: - enable - disable - memory-use-threshold-extreme: + memory_use_threshold_extreme: description: - - Threshold at which memory usage is considered extreme (new sessions are dropped) (% of total RAM, default = 95). - memory-use-threshold-green: + - Threshold at which memory usage is considered extreme (new sessions are dropped) (% of total RAM). + type: int + memory_use_threshold_green: description: - - Threshold at which memory usage forces the FortiGate to exit conserve mode (% of total RAM, default = 82). - memory-use-threshold-red: + - Threshold at which memory usage forces the FortiGate to exit conserve mode (% of total RAM). + type: int + memory_use_threshold_red: description: - - Threshold at which memory usage forces the FortiGate to enter conserve mode (% of total RAM, default = 88). - miglog-affinity: + - Threshold at which memory usage forces the FortiGate to enter conserve mode (% of total RAM). + type: int + miglog_affinity: description: - Affinity setting for logging (64-bit hexadecimal value in the format of xxxxxxxxxxxxxxxx). - miglogd-children: + type: str + miglogd_children: description: - Number of logging (miglogd) processes to be allowed to run. Higher number can reduce performance; lower number can slow log processing time. No logs will be dropped or lost if the number is changed. - multi-factor-authentication: + type: int + multi_factor_authentication: description: - - Enforce all login methods to require an additional authentication factor (default = optional). + - Enforce all login methods to require an additional authentication factor . + type: str choices: - optional - mandatory - multicast-forward: + multicast_forward: description: - Enable/disable multicast forwarding. + type: str choices: - enable - disable - ndp-max-entry: + ndp_max_entry: description: - Maximum number of NDP table entries (set to 65,536 or higher; if set to 0, kernel holds 65,536 entries). - per-user-bwl: + type: int + per_user_bwl: description: - Enable/disable per-user black/white list filter. + type: str choices: - enable - disable - policy-auth-concurrent: + policy_auth_concurrent: description: - - Number of concurrent firewall use logins from the same user (1 - 100, default = 0 means no limit). - post-login-banner: + - Number of concurrent firewall use logins from the same user (1 - 100). + type: int + post_login_banner: description: - Enable/disable displaying the administrator access disclaimer message after an administrator successfully logs in. + type: str choices: - disable - enable - pre-login-banner: + pre_login_banner: description: - Enable/disable displaying the administrator access disclaimer message on the login page before an administrator logs in. + type: str choices: - enable - disable - private-data-encryption: + private_data_encryption: description: - Enable/disable private data encryption using an AES 128-bit key. + type: str choices: - disable - enable - proxy-auth-lifetime: + proxy_auth_lifetime: description: - Enable/disable authenticated users lifetime control. This is a cap on the total time a proxy user can be authenticated for after which re-authentication will take place. + type: str choices: - enable - disable - proxy-auth-lifetime-timeout: + proxy_auth_lifetime_timeout: description: - - Lifetime timeout in minutes for authenticated users (5 - 65535 min, default=480 (8 hours)). - proxy-auth-timeout: + - Lifetime timeout in minutes for authenticated users (5 - 65535 min). + type: int + proxy_auth_timeout: description: - - Authentication timeout in minutes for authenticated users (1 - 3600 sec, default = 300). - proxy-cipher-hardware-acceleration: + - Authentication timeout in minutes for authenticated users (1 - 300 min). + type: int + proxy_cipher_hardware_acceleration: description: - Enable/disable using content processor (CP8 or CP9) hardware acceleration to encrypt and decrypt IPsec and SSL traffic. + type: str choices: - disable - enable - proxy-kxp-hardware-acceleration: + proxy_kxp_hardware_acceleration: description: - Enable/disable using the content processor to accelerate KXP traffic. + type: str choices: - disable - enable - proxy-re-authentication-mode: + proxy_re_authentication_mode: description: - Control if users must re-authenticate after a session is closed, traffic has been idle, or from the point at which the user was first created. + type: str choices: - session - traffic - absolute - proxy-worker-count: + proxy_worker_count: description: - Proxy worker count. - radius-port: + type: int + radius_port: description: - RADIUS service port number. - reboot-upon-config-restore: + type: int + reboot_upon_config_restore: description: - Enable/disable reboot of system upon restoring configuration. + type: str choices: - enable - disable refresh: description: - Statistics refresh interval in GUI. + type: int remoteauthtimeout: description: - - Number of seconds that the FortiGate waits for responses from remote RADIUS, LDAP, or TACACS+ authentication servers. (0-300 sec, - default = 5, 0 means no timeout). - reset-sessionless-tcp: + - Number of seconds that the FortiGate waits for responses from remote RADIUS, LDAP, or TACACS+ authentication servers. (0-300 sec). + type: int + reset_sessionless_tcp: description: - Action to perform if the FortiGate receives a TCP packet but cannot find a corresponding session in its session table. NAT/Route mode only. + type: str choices: - enable - disable - restart-time: + restart_time: description: - "Daily restart time (hh:mm)." - revision-backup-on-logout: + type: str + revision_backup_on_logout: description: - Enable/disable back-up of the latest configuration revision when an administrator logs out of the CLI or GUI. + type: str choices: - enable - disable - revision-image-auto-backup: + revision_image_auto_backup: description: - Enable/disable back-up of the latest configuration revision after the firmware is upgraded. + type: str choices: - enable - disable - scanunit-count: + scanunit_count: description: - Number of scanunits. The range and the default depend on the number of CPUs. Only available on FortiGate units with multiple CPUs. - security-rating-result-submission: + type: int + security_rating_result_submission: description: - Enable/disable the submission of Security Rating results to FortiGuard. + type: str choices: - enable - disable - security-rating-run-on-schedule: + security_rating_run_on_schedule: description: - Enable/disable scheduled runs of Security Rating. + type: str choices: - enable - disable - send-pmtu-icmp: + send_pmtu_icmp: description: - Enable/disable sending of path maximum transmission unit (PMTU) - ICMP destination unreachable packet and to support PMTUD protocol on your network to reduce fragmentation of packets. + type: str choices: - enable - disable - snat-route-change: + snat_route_change: description: - Enable/disable the ability to change the static NAT route. + type: str choices: - enable - disable - special-file-23-support: + special_file_23_support: description: - Enable/disable IPS detection of HIBUN format files when using Data Leak Protection. + type: str choices: - disable - enable - ssh-cbc-cipher: + ssd_trim_date: + description: + - Date within a month to run ssd trim. + type: int + ssd_trim_freq: + description: + - How often to run SSD Trim . SSD Trim prevents SSD drive data loss by finding and isolating errors. + type: str + choices: + - never + - hourly + - daily + - weekly + - monthly + ssd_trim_hour: + description: + - Hour of the day on which to run SSD Trim (0 - 23). + type: int + ssd_trim_min: + description: + - Minute of the hour on which to run SSD Trim (0 - 59, 60 for random). + type: int + ssd_trim_weekday: + description: + - Day of week to run SSD Trim. + type: str + choices: + - sunday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday + ssh_cbc_cipher: description: - Enable/disable CBC cipher for SSH access. + type: str choices: - enable - disable - ssh-hmac-md5: + ssh_hmac_md5: description: - Enable/disable HMAC-MD5 for SSH access. + type: str choices: - enable - disable - ssh-kex-sha1: + ssh_kex_sha1: description: - Enable/disable SHA1 key exchange for SSH access. + type: str choices: - enable - disable - ssl-min-proto-version: + ssl_min_proto_version: description: - - Minimum supported protocol version for SSL/TLS connections (default = TLSv1.2). + - Minimum supported protocol version for SSL/TLS connections . + type: str choices: - SSLv3 - TLSv1 - TLSv1-1 - TLSv1-2 - ssl-static-key-ciphers: + ssl_static_key_ciphers: description: - Enable/disable static key ciphers in SSL/TLS connections (e.g. AES128-SHA, AES256-SHA, AES128-SHA256, AES256-SHA256). + type: str choices: - enable - disable - sslvpn-cipher-hardware-acceleration: + sslvpn_cipher_hardware_acceleration: description: - Enable/disable SSL VPN hardware acceleration. + type: str choices: - enable - disable - sslvpn-kxp-hardware-acceleration: + sslvpn_kxp_hardware_acceleration: description: - Enable/disable SSL VPN KXP hardware acceleration. + type: str choices: - enable - disable - sslvpn-max-worker-count: + sslvpn_max_worker_count: description: - Maximum number of SSL VPN processes. Upper limit for this value is the number of CPUs and depends on the model. - sslvpn-plugin-version-check: + type: int + sslvpn_plugin_version_check: description: - Enable/disable checking browser's plugin version by SSL VPN. + type: str choices: - enable - disable - strict-dirty-session-check: + strict_dirty_session_check: description: - Enable to check the session against the original policy when revalidating. This can prevent dropping of redirected sessions when web-filtering and authentication are enabled together. If this option is enabled, the FortiGate unit deletes a session if a routing or policy change causes the session to no longer match the policy that originally allowed the session. + type: str choices: - enable - disable - strong-crypto: + strong_crypto: description: - Enable to use strong encryption and only allow strong ciphers (AES, 3DES) and digest (SHA1) for HTTPS/SSH/TLS/SSL functions. + type: str choices: - enable - disable - switch-controller: + switch_controller: description: - Enable/disable switch controller feature. Switch controller allows you to manage FortiSwitch from the FortiGate itself. + type: str choices: - disable - enable - switch-controller-reserved-network: + switch_controller_reserved_network: description: - Enable reserved network subnet for controlled switches. This is available when the switch controller is enabled. - sys-perf-log-interval: + type: str + sys_perf_log_interval: description: - - Time in minutes between updates of performance statistics logging. (1 - 15 min, default = 5, 0 = disabled). - tcp-halfclose-timer: + - Time in minutes between updates of performance statistics logging. (1 - 15 min). + type: int + tcp_halfclose_timer: description: - Number of seconds the FortiGate unit should wait to close a session after one peer has sent a FIN packet but the other has not responded - (1 - 86400 sec (1 day), default = 120). - tcp-halfopen-timer: + (1 - 86400 sec (1 day)). + type: int + tcp_halfopen_timer: description: - Number of seconds the FortiGate unit should wait to close a session after one peer has sent an open session packet but the other has not - responded (1 - 86400 sec (1 day), default = 10). - tcp-option: + responded (1 - 86400 sec (1 day)). + type: int + tcp_option: description: - Enable SACK, timestamp and MSS TCP options. + type: str choices: - enable - disable - tcp-timewait-timer: + tcp_timewait_timer: description: - Length of the TCP TIME-WAIT state in seconds. + type: int tftp: description: - Enable/disable TFTP. + type: str choices: - enable - disable @@ -817,6 +1007,7 @@ options: description: - Number corresponding to your time zone from 00 to 86. Enter set timezone ? to view the list of time zones and the numbers that represent them. + type: str choices: - 01 - 02 @@ -906,109 +1097,132 @@ options: - 73 - 86 - 76 - tp-mc-skip-policy: + tp_mc_skip_policy: description: - Enable/disable skip policy check and allow multicast through. + type: str choices: - enable - disable - traffic-priority: + traffic_priority: description: - Choose Type of Service (ToS) or Differentiated Services Code Point (DSCP) for traffic prioritization in traffic shaping. + type: str choices: - tos - dscp - traffic-priority-level: + traffic_priority_level: description: - Default system-wide level of priority for traffic prioritization. + type: str choices: - low - medium - high - two-factor-email-expiry: + two_factor_email_expiry: description: - - Email-based two-factor authentication session timeout (30 - 300 seconds (5 minutes), default = 60). - two-factor-fac-expiry: + - Email-based two-factor authentication session timeout (30 - 300 seconds (5 minutes)). + type: int + two_factor_fac_expiry: description: - - FortiAuthenticator token authentication session timeout (10 - 3600 seconds (1 hour), default = 60). - two-factor-ftk-expiry: + - FortiAuthenticator token authentication session timeout (10 - 3600 seconds (1 hour)). + type: int + two_factor_ftk_expiry: description: - - FortiToken authentication session timeout (60 - 600 sec (10 minutes), default = 60). - two-factor-ftm-expiry: + - FortiToken authentication session timeout (60 - 600 sec (10 minutes)). + type: int + two_factor_ftm_expiry: description: - - FortiToken Mobile session timeout (1 - 168 hours (7 days), default = 72). - two-factor-sms-expiry: + - FortiToken Mobile session timeout (1 - 168 hours (7 days)). + type: int + two_factor_sms_expiry: description: - - SMS-based two-factor authentication session timeout (30 - 300 sec, default = 60). - udp-idle-timer: + - SMS-based two-factor authentication session timeout (30 - 300 sec). + type: int + udp_idle_timer: description: - - UDP connection session timeout. This command can be useful in managing CPU and memory resources (1 - 86400 seconds (1 day), default = - 60). - user-server-cert: + - UDP connection session timeout. This command can be useful in managing CPU and memory resources (1 - 86400 seconds (1 day)). + type: int + user_server_cert: description: - Certificate to use for https user authentication. Source certificate.local.name. - vdom-admin: + type: str + vdom_admin: description: - Enable/disable support for multiple virtual domains (VDOMs). + type: str choices: - enable - disable - vip-arp-range: + vip_arp_range: description: - Controls the number of ARPs that the FortiGate sends for a Virtual IP (VIP) address range. + type: str choices: - unlimited - restricted - virtual-server-count: + virtual_server_count: description: - Maximum number of virtual server processes to create. The maximum is the number of CPU cores. This is not available on single-core CPUs. - virtual-server-hardware-acceleration: + type: int + virtual_server_hardware_acceleration: description: - Enable/disable virtual server hardware acceleration. + type: str choices: - disable - enable - wad-affinity: + wad_affinity: description: - Affinity setting for wad (hexadecimal value up to 256 bits in the format of xxxxxxxxxxxxxxxx). - wad-csvc-cs-count: + type: str + wad_csvc_cs_count: description: - Number of concurrent WAD-cache-service object-cache processes. - wad-csvc-db-count: + type: int + wad_csvc_db_count: description: - Number of concurrent WAD-cache-service byte-cache processes. - wad-source-affinity: + type: int + wad_source_affinity: description: - Enable/disable dispatching traffic to WAD workers based on source affinity. + type: str choices: - disable - enable - wad-worker-count: + wad_worker_count: description: - Number of explicit proxy WAN optimization daemon (WAD) processes. By default WAN optimization, explicit proxy, and web caching is handled by all of the CPU cores in a FortiGate unit. - wifi-ca-certificate: + type: int + wifi_ca_certificate: description: - CA certificate that verifies the WiFi certificate. Source certificate.ca.name. - wifi-certificate: + type: str + wifi_certificate: description: - Certificate to use for WiFi authentication. Source certificate.local.name. - wimax-4g-usb: + type: str + wimax_4g_usb: description: - Enable/disable comparability with WiMAX 4G USB devices. + type: str choices: - enable - disable - wireless-controller: + wireless_controller: description: - Enable/disable the wireless controller feature to use the FortiGate unit to manage FortiAPs. + type: str choices: - enable - disable - wireless-controller-port: + wireless_controller_port: description: - Port used for the control channel in wireless controller mode (wireless-mode is ac). The data channel port is the control channel port - number plus one (1024 - 49150, default = 5246). + number plus one (1024 - 49150). + type: int ''' EXAMPLES = ''' @@ -1018,6 +1232,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure global attributes. fortios_system_global: @@ -1027,178 +1242,184 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" system_global: - admin-concurrent: "enable" - admin-console-timeout: "4" - admin-https-pki-required: "enable" - admin-https-ssl-versions: "tlsv1-0" - admin-lockout-duration: "7" - admin-lockout-threshold: "8" - admin-login-max: "9" - admin-maintainer: "enable" - admin-port: "11" - admin-restrict-local: "enable" - admin-scp: "enable" - admin-server-cert: " (source certificate.local.name)" - admin-sport: "15" - admin-ssh-grace-time: "16" - admin-ssh-password: "enable" - admin-ssh-port: "18" - admin-ssh-v1: "enable" - admin-telnet-port: "20" + admin_concurrent: "enable" + admin_console_timeout: "4" + admin_https_pki_required: "enable" + admin_https_ssl_versions: "tlsv1-0" + admin_lockout_duration: "7" + admin_lockout_threshold: "8" + admin_login_max: "9" + admin_maintainer: "enable" + admin_port: "11" + admin_restrict_local: "enable" + admin_scp: "enable" + admin_server_cert: " (source certificate.local.name)" + admin_sport: "15" + admin_ssh_grace_time: "16" + admin_ssh_password: "enable" + admin_ssh_port: "18" + admin_ssh_v1: "enable" + admin_telnet_port: "20" admintimeout: "21" alias: "" - allow-traffic-redirect: "enable" - anti-replay: "disable" - arp-max-entry: "25" + allow_traffic_redirect: "enable" + anti_replay: "disable" + arp_max_entry: "25" asymroute: "enable" - auth-cert: " (source certificate.local.name)" - auth-http-port: "28" - auth-https-port: "29" - auth-keepalive: "enable" - auth-session-limit: "block-new" - auto-auth-extension-device: "enable" - av-affinity: "" - av-failopen: "pass" - av-failopen-session: "enable" - batch-cmdb: "enable" - block-session-timer: "37" - br-fdb-max-entry: "38" - cert-chain-max: "39" - cfg-revert-timeout: "40" - cfg-save: "automatic" - check-protocol-header: "loose" - check-reset-range: "strict" - cli-audit-log: "enable" - clt-cert-req: "enable" - compliance-check: "enable" - compliance-check-time: "" - cpu-use-threshold: "48" - csr-ca-attribute: "enable" - daily-restart: "enable" - device-identification-active-scan-delay: "51" - device-idle-timeout: "52" - dh-params: "1024" + auth_cert: " (source certificate.local.name)" + auth_http_port: "28" + auth_https_port: "29" + auth_keepalive: "enable" + auth_session_limit: "block-new" + auto_auth_extension_device: "enable" + av_affinity: "" + av_failopen: "pass" + av_failopen_session: "enable" + batch_cmdb: "enable" + block_session_timer: "37" + br_fdb_max_entry: "38" + cert_chain_max: "39" + cfg_revert_timeout: "40" + cfg_save: "automatic" + check_protocol_header: "loose" + check_reset_range: "strict" + cli_audit_log: "enable" + clt_cert_req: "enable" + compliance_check: "enable" + compliance_check_time: "" + cpu_use_threshold: "48" + csr_ca_attribute: "enable" + daily_restart: "enable" + device_identification_active_scan_delay: "51" + device_idle_timeout: "52" + dh_params: "1024" + dnsproxy_worker_count: "54" dst: "enable" - endpoint-control-fds-access: "enable" - endpoint-control-portal-port: "56" - failtime: "57" - fds-statistics: "enable" - fds-statistics-period: "59" - fgd-alert-subscription: "advisory" + endpoint_control_fds_access: "enable" + endpoint_control_portal_port: "57" + failtime: "58" + fds_statistics: "enable" + fds_statistics_period: "60" + fgd_alert_subscription: "advisory" fortiextender: "enable" - fortiextender-data-port: "62" - fortiextender-vlan-mode: "enable" - fortiservice-port: "64" - gui-certificates: "enable" - gui-custom-language: "enable" - gui-date-format: "yyyy/MM/dd" - gui-device-latitude: "" - gui-device-longitude: "" - gui-display-hostname: "enable" - gui-ipv6: "enable" - gui-lines-per-page: "72" - gui-theme: "green" - gui-wireless-opensecurity: "enable" - honor-df: "enable" + fortiextender_data_port: "63" + fortiextender_vlan_mode: "enable" + fortiservice_port: "65" + gui_certificates: "enable" + gui_custom_language: "enable" + gui_date_format: "yyyy/MM/dd" + gui_device_latitude: "" + gui_device_longitude: "" + gui_display_hostname: "enable" + gui_ipv6: "enable" + gui_lines_per_page: "73" + gui_theme: "green" + gui_wireless_opensecurity: "enable" + honor_df: "enable" hostname: "myhostname" - igmp-state-limit: "77" - interval: "78" - ip-src-port-range: "" - ips-affinity: "" - ipsec-asic-offload: "enable" - ipsec-hmac-offload: "enable" - ipsec-soft-dec-async: "enable" - ipv6-accept-dad: "84" - ipv6-allow-anycast-probe: "enable" + igmp_state_limit: "78" + interval: "79" + ip_src_port_range: "" + ips_affinity: "" + ipsec_asic_offload: "enable" + ipsec_hmac_offload: "enable" + ipsec_soft_dec_async: "enable" + ipv6_accept_dad: "85" + ipv6_allow_anycast_probe: "enable" language: "english" - ldapconntimeout: "87" - lldp-transmission: "enable" - log-ssl-connection: "enable" - log-uuid: "disable" - login-timestamp: "enable" - long-vdom-name: "enable" - management-vdom: " (source system.vdom.name)" - max-dlpstat-memory: "94" - max-route-cache-size: "95" - mc-ttl-notchange: "enable" - memory-use-threshold-extreme: "97" - memory-use-threshold-green: "98" - memory-use-threshold-red: "99" - miglog-affinity: "" - miglogd-children: "101" - multi-factor-authentication: "optional" - multicast-forward: "enable" - ndp-max-entry: "104" - per-user-bwl: "enable" - policy-auth-concurrent: "106" - post-login-banner: "disable" - pre-login-banner: "enable" - private-data-encryption: "disable" - proxy-auth-lifetime: "enable" - proxy-auth-lifetime-timeout: "111" - proxy-auth-timeout: "112" - proxy-cipher-hardware-acceleration: "disable" - proxy-kxp-hardware-acceleration: "disable" - proxy-re-authentication-mode: "session" - proxy-worker-count: "116" - radius-port: "117" - reboot-upon-config-restore: "enable" - refresh: "119" - remoteauthtimeout: "120" - reset-sessionless-tcp: "enable" - restart-time: "" - revision-backup-on-logout: "enable" - revision-image-auto-backup: "enable" - scanunit-count: "125" - security-rating-result-submission: "enable" - security-rating-run-on-schedule: "enable" - send-pmtu-icmp: "enable" - snat-route-change: "enable" - special-file-23-support: "disable" - ssh-cbc-cipher: "enable" - ssh-hmac-md5: "enable" - ssh-kex-sha1: "enable" - ssl-min-proto-version: "SSLv3" - ssl-static-key-ciphers: "enable" - sslvpn-cipher-hardware-acceleration: "enable" - sslvpn-kxp-hardware-acceleration: "enable" - sslvpn-max-worker-count: "138" - sslvpn-plugin-version-check: "enable" - strict-dirty-session-check: "enable" - strong-crypto: "enable" - switch-controller: "disable" - switch-controller-reserved-network: "" - sys-perf-log-interval: "144" - tcp-halfclose-timer: "145" - tcp-halfopen-timer: "146" - tcp-option: "enable" - tcp-timewait-timer: "148" + ldapconntimeout: "88" + lldp_transmission: "enable" + log_ssl_connection: "enable" + log_uuid: "disable" + login_timestamp: "enable" + long_vdom_name: "enable" + management_vdom: " (source system.vdom.name)" + max_dlpstat_memory: "95" + max_route_cache_size: "96" + mc_ttl_notchange: "enable" + memory_use_threshold_extreme: "98" + memory_use_threshold_green: "99" + memory_use_threshold_red: "100" + miglog_affinity: "" + miglogd_children: "102" + multi_factor_authentication: "optional" + multicast_forward: "enable" + ndp_max_entry: "105" + per_user_bwl: "enable" + policy_auth_concurrent: "107" + post_login_banner: "disable" + pre_login_banner: "enable" + private_data_encryption: "disable" + proxy_auth_lifetime: "enable" + proxy_auth_lifetime_timeout: "112" + proxy_auth_timeout: "113" + proxy_cipher_hardware_acceleration: "disable" + proxy_kxp_hardware_acceleration: "disable" + proxy_re_authentication_mode: "session" + proxy_worker_count: "117" + radius_port: "118" + reboot_upon_config_restore: "enable" + refresh: "120" + remoteauthtimeout: "121" + reset_sessionless_tcp: "enable" + restart_time: "" + revision_backup_on_logout: "enable" + revision_image_auto_backup: "enable" + scanunit_count: "126" + security_rating_result_submission: "enable" + security_rating_run_on_schedule: "enable" + send_pmtu_icmp: "enable" + snat_route_change: "enable" + special_file_23_support: "disable" + ssd_trim_date: "132" + ssd_trim_freq: "never" + ssd_trim_hour: "134" + ssd_trim_min: "135" + ssd_trim_weekday: "sunday" + ssh_cbc_cipher: "enable" + ssh_hmac_md5: "enable" + ssh_kex_sha1: "enable" + ssl_min_proto_version: "SSLv3" + ssl_static_key_ciphers: "enable" + sslvpn_cipher_hardware_acceleration: "enable" + sslvpn_kxp_hardware_acceleration: "enable" + sslvpn_max_worker_count: "144" + sslvpn_plugin_version_check: "enable" + strict_dirty_session_check: "enable" + strong_crypto: "enable" + switch_controller: "disable" + switch_controller_reserved_network: "" + sys_perf_log_interval: "150" + tcp_halfclose_timer: "151" + tcp_halfopen_timer: "152" + tcp_option: "enable" + tcp_timewait_timer: "154" tftp: "enable" timezone: "01" - tp-mc-skip-policy: "enable" - traffic-priority: "tos" - traffic-priority-level: "low" - two-factor-email-expiry: "154" - two-factor-fac-expiry: "155" - two-factor-ftk-expiry: "156" - two-factor-ftm-expiry: "157" - two-factor-sms-expiry: "158" - udp-idle-timer: "159" - user-server-cert: " (source certificate.local.name)" - vdom-admin: "enable" - vip-arp-range: "unlimited" - virtual-server-count: "163" - virtual-server-hardware-acceleration: "disable" - wad-affinity: "" - wad-csvc-cs-count: "166" - wad-csvc-db-count: "167" - wad-source-affinity: "disable" - wad-worker-count: "169" - wifi-ca-certificate: " (source certificate.ca.name)" - wifi-certificate: " (source certificate.local.name)" - wimax-4g-usb: "enable" - wireless-controller: "enable" - wireless-controller-port: "174" + tp_mc_skip_policy: "enable" + traffic_priority: "tos" + traffic_priority_level: "low" + two_factor_email_expiry: "160" + two_factor_fac_expiry: "161" + two_factor_ftk_expiry: "162" + two_factor_ftm_expiry: "163" + two_factor_sms_expiry: "164" + udp_idle_timer: "165" + user_server_cert: " (source certificate.local.name)" + vdom_admin: "enable" + vip_arp_range: "unlimited" + virtual_server_count: "169" + virtual_server_hardware_acceleration: "disable" + wad_affinity: "" + wad_csvc_cs_count: "172" + wad_csvc_db_count: "173" + wad_source_affinity: "disable" + wad_worker_count: "175" + wifi_ca_certificate: " (source certificate.ca.name)" + wifi_certificate: " (source certificate.local.name)" + wimax_4g_usb: "enable" + wireless_controller: "enable" + wireless_controller_port: "180" ''' RETURN = ''' @@ -1261,12 +1482,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 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']: @@ -1274,68 +1499,70 @@ def login(data, fos): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_global_data(json): - option_list = ['admin-concurrent', 'admin-console-timeout', 'admin-https-pki-required', - 'admin-https-ssl-versions', 'admin-lockout-duration', 'admin-lockout-threshold', - 'admin-login-max', 'admin-maintainer', 'admin-port', - 'admin-restrict-local', 'admin-scp', 'admin-server-cert', - 'admin-sport', 'admin-ssh-grace-time', 'admin-ssh-password', - 'admin-ssh-port', 'admin-ssh-v1', 'admin-telnet-port', - 'admintimeout', 'alias', 'allow-traffic-redirect', - 'anti-replay', 'arp-max-entry', 'asymroute', - 'auth-cert', 'auth-http-port', 'auth-https-port', - 'auth-keepalive', 'auth-session-limit', 'auto-auth-extension-device', - 'av-affinity', 'av-failopen', 'av-failopen-session', - 'batch-cmdb', 'block-session-timer', 'br-fdb-max-entry', - 'cert-chain-max', 'cfg-revert-timeout', 'cfg-save', - 'check-protocol-header', 'check-reset-range', 'cli-audit-log', - 'clt-cert-req', 'compliance-check', 'compliance-check-time', - 'cpu-use-threshold', 'csr-ca-attribute', 'daily-restart', - 'device-identification-active-scan-delay', 'device-idle-timeout', 'dh-params', - 'dst', 'endpoint-control-fds-access', 'endpoint-control-portal-port', - 'failtime', 'fds-statistics', 'fds-statistics-period', - 'fgd-alert-subscription', 'fortiextender', 'fortiextender-data-port', - 'fortiextender-vlan-mode', 'fortiservice-port', 'gui-certificates', - 'gui-custom-language', 'gui-date-format', 'gui-device-latitude', - 'gui-device-longitude', 'gui-display-hostname', 'gui-ipv6', - 'gui-lines-per-page', 'gui-theme', 'gui-wireless-opensecurity', - 'honor-df', 'hostname', 'igmp-state-limit', - 'interval', 'ip-src-port-range', 'ips-affinity', - 'ipsec-asic-offload', 'ipsec-hmac-offload', 'ipsec-soft-dec-async', - 'ipv6-accept-dad', 'ipv6-allow-anycast-probe', 'language', - 'ldapconntimeout', 'lldp-transmission', 'log-ssl-connection', - 'log-uuid', 'login-timestamp', 'long-vdom-name', - 'management-vdom', 'max-dlpstat-memory', 'max-route-cache-size', - 'mc-ttl-notchange', 'memory-use-threshold-extreme', 'memory-use-threshold-green', - 'memory-use-threshold-red', 'miglog-affinity', 'miglogd-children', - 'multi-factor-authentication', 'multicast-forward', 'ndp-max-entry', - 'per-user-bwl', 'policy-auth-concurrent', 'post-login-banner', - 'pre-login-banner', 'private-data-encryption', 'proxy-auth-lifetime', - 'proxy-auth-lifetime-timeout', 'proxy-auth-timeout', 'proxy-cipher-hardware-acceleration', - 'proxy-kxp-hardware-acceleration', 'proxy-re-authentication-mode', 'proxy-worker-count', - 'radius-port', 'reboot-upon-config-restore', 'refresh', - 'remoteauthtimeout', 'reset-sessionless-tcp', 'restart-time', - 'revision-backup-on-logout', 'revision-image-auto-backup', 'scanunit-count', - 'security-rating-result-submission', 'security-rating-run-on-schedule', 'send-pmtu-icmp', - 'snat-route-change', 'special-file-23-support', 'ssh-cbc-cipher', - 'ssh-hmac-md5', 'ssh-kex-sha1', 'ssl-min-proto-version', - 'ssl-static-key-ciphers', 'sslvpn-cipher-hardware-acceleration', 'sslvpn-kxp-hardware-acceleration', - 'sslvpn-max-worker-count', 'sslvpn-plugin-version-check', 'strict-dirty-session-check', - 'strong-crypto', 'switch-controller', 'switch-controller-reserved-network', - 'sys-perf-log-interval', 'tcp-halfclose-timer', 'tcp-halfopen-timer', - 'tcp-option', 'tcp-timewait-timer', 'tftp', - 'timezone', 'tp-mc-skip-policy', 'traffic-priority', - 'traffic-priority-level', 'two-factor-email-expiry', 'two-factor-fac-expiry', - 'two-factor-ftk-expiry', 'two-factor-ftm-expiry', 'two-factor-sms-expiry', - 'udp-idle-timer', 'user-server-cert', 'vdom-admin', - 'vip-arp-range', 'virtual-server-count', 'virtual-server-hardware-acceleration', - 'wad-affinity', 'wad-csvc-cs-count', 'wad-csvc-db-count', - 'wad-source-affinity', 'wad-worker-count', 'wifi-ca-certificate', - 'wifi-certificate', 'wimax-4g-usb', 'wireless-controller', - 'wireless-controller-port'] + option_list = ['admin_concurrent', 'admin_console_timeout', 'admin_https_pki_required', + 'admin_https_ssl_versions', 'admin_lockout_duration', 'admin_lockout_threshold', + 'admin_login_max', 'admin_maintainer', 'admin_port', + 'admin_restrict_local', 'admin_scp', 'admin_server_cert', + 'admin_sport', 'admin_ssh_grace_time', 'admin_ssh_password', + 'admin_ssh_port', 'admin_ssh_v1', 'admin_telnet_port', + 'admintimeout', 'alias', 'allow_traffic_redirect', + 'anti_replay', 'arp_max_entry', 'asymroute', + 'auth_cert', 'auth_http_port', 'auth_https_port', + 'auth_keepalive', 'auth_session_limit', 'auto_auth_extension_device', + 'av_affinity', 'av_failopen', 'av_failopen_session', + 'batch_cmdb', 'block_session_timer', 'br_fdb_max_entry', + 'cert_chain_max', 'cfg_revert_timeout', 'cfg_save', + 'check_protocol_header', 'check_reset_range', 'cli_audit_log', + 'clt_cert_req', 'compliance_check', 'compliance_check_time', + 'cpu_use_threshold', 'csr_ca_attribute', 'daily_restart', + 'device_identification_active_scan_delay', 'device_idle_timeout', 'dh_params', + 'dnsproxy_worker_count', 'dst', 'endpoint_control_fds_access', + 'endpoint_control_portal_port', 'failtime', 'fds_statistics', + 'fds_statistics_period', 'fgd_alert_subscription', 'fortiextender', + 'fortiextender_data_port', 'fortiextender_vlan_mode', 'fortiservice_port', + 'gui_certificates', 'gui_custom_language', 'gui_date_format', + 'gui_device_latitude', 'gui_device_longitude', 'gui_display_hostname', + 'gui_ipv6', 'gui_lines_per_page', 'gui_theme', + 'gui_wireless_opensecurity', 'honor_df', 'hostname', + 'igmp_state_limit', 'interval', 'ip_src_port_range', + 'ips_affinity', 'ipsec_asic_offload', 'ipsec_hmac_offload', + 'ipsec_soft_dec_async', 'ipv6_accept_dad', 'ipv6_allow_anycast_probe', + 'language', 'ldapconntimeout', 'lldp_transmission', + 'log_ssl_connection', 'log_uuid', 'login_timestamp', + 'long_vdom_name', 'management_vdom', 'max_dlpstat_memory', + 'max_route_cache_size', 'mc_ttl_notchange', 'memory_use_threshold_extreme', + 'memory_use_threshold_green', 'memory_use_threshold_red', 'miglog_affinity', + 'miglogd_children', 'multi_factor_authentication', 'multicast_forward', + 'ndp_max_entry', 'per_user_bwl', 'policy_auth_concurrent', + 'post_login_banner', 'pre_login_banner', 'private_data_encryption', + 'proxy_auth_lifetime', 'proxy_auth_lifetime_timeout', 'proxy_auth_timeout', + 'proxy_cipher_hardware_acceleration', 'proxy_kxp_hardware_acceleration', 'proxy_re_authentication_mode', + 'proxy_worker_count', 'radius_port', 'reboot_upon_config_restore', + 'refresh', 'remoteauthtimeout', 'reset_sessionless_tcp', + 'restart_time', 'revision_backup_on_logout', 'revision_image_auto_backup', + 'scanunit_count', 'security_rating_result_submission', 'security_rating_run_on_schedule', + 'send_pmtu_icmp', 'snat_route_change', 'special_file_23_support', + 'ssd_trim_date', 'ssd_trim_freq', 'ssd_trim_hour', + 'ssd_trim_min', 'ssd_trim_weekday', 'ssh_cbc_cipher', + 'ssh_hmac_md5', 'ssh_kex_sha1', 'ssl_min_proto_version', + 'ssl_static_key_ciphers', 'sslvpn_cipher_hardware_acceleration', 'sslvpn_kxp_hardware_acceleration', + 'sslvpn_max_worker_count', 'sslvpn_plugin_version_check', 'strict_dirty_session_check', + 'strong_crypto', 'switch_controller', 'switch_controller_reserved_network', + 'sys_perf_log_interval', 'tcp_halfclose_timer', 'tcp_halfopen_timer', + 'tcp_option', 'tcp_timewait_timer', 'tftp', + 'timezone', 'tp_mc_skip_policy', 'traffic_priority', + 'traffic_priority_level', 'two_factor_email_expiry', 'two_factor_fac_expiry', + 'two_factor_ftk_expiry', 'two_factor_ftm_expiry', 'two_factor_sms_expiry', + 'udp_idle_timer', 'user_server_cert', 'vdom_admin', + 'vip_arp_range', 'virtual_server_count', 'virtual_server_hardware_acceleration', + 'wad_affinity', 'wad_csvc_cs_count', 'wad_csvc_db_count', + 'wad_source_affinity', 'wad_worker_count', 'wifi_ca_certificate', + 'wifi_certificate', 'wimax_4g_usb', 'wireless_controller', + 'wireless_controller_port'] dictionary = {} for attribute in option_list: @@ -1346,7 +1573,7 @@ def filter_system_global_data(json): def flatten_multilists_attributes(data): - multilist_attrs = [[u'admin-https-ssl-versions']] + multilist_attrs = [[u'admin_https_ssl_versions']] for attr in multilist_attrs: try: @@ -1360,11 +1587,24 @@ def flatten_multilists_attributes(data): return data +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 system_global(data, fos): vdom = data['vdom'] system_global_data = data['system_global'] system_global_data = flatten_multilists_attributes(system_global_data) - filtered_data = filter_system_global_data(system_global_data) + filtered_data = underscore_to_hyphen(filter_system_global_data(system_global_data)) return fos.set('system', 'global', @@ -1372,262 +1612,279 @@ def system_global(data, fos): vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_system(data, fos): - login(data, fos) if data['system_global']: resp = system_global(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "system_global": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "admin-concurrent": {"required": False, "type": "str", + "admin_concurrent": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-console-timeout": {"required": False, "type": "int"}, - "admin-https-pki-required": {"required": False, "type": "str", + "admin_console_timeout": {"required": False, "type": "int"}, + "admin_https_pki_required": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-https-ssl-versions": {"required": False, "type": "list", + "admin_https_ssl_versions": {"required": False, "type": "list", "choices": ["tlsv1-0", "tlsv1-1", "tlsv1-2"]}, - "admin-lockout-duration": {"required": False, "type": "int"}, - "admin-lockout-threshold": {"required": False, "type": "int"}, - "admin-login-max": {"required": False, "type": "int"}, - "admin-maintainer": {"required": False, "type": "str", + "admin_lockout_duration": {"required": False, "type": "int"}, + "admin_lockout_threshold": {"required": False, "type": "int"}, + "admin_login_max": {"required": False, "type": "int"}, + "admin_maintainer": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-port": {"required": False, "type": "int"}, - "admin-restrict-local": {"required": False, "type": "str", + "admin_port": {"required": False, "type": "int"}, + "admin_restrict_local": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-scp": {"required": False, "type": "str", + "admin_scp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-server-cert": {"required": False, "type": "str"}, - "admin-sport": {"required": False, "type": "int"}, - "admin-ssh-grace-time": {"required": False, "type": "int"}, - "admin-ssh-password": {"required": False, "type": "str", + "admin_server_cert": {"required": False, "type": "str"}, + "admin_sport": {"required": False, "type": "int"}, + "admin_ssh_grace_time": {"required": False, "type": "int"}, + "admin_ssh_password": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-ssh-port": {"required": False, "type": "int"}, - "admin-ssh-v1": {"required": False, "type": "str", + "admin_ssh_port": {"required": False, "type": "int"}, + "admin_ssh_v1": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "admin-telnet-port": {"required": False, "type": "int"}, + "admin_telnet_port": {"required": False, "type": "int"}, "admintimeout": {"required": False, "type": "int"}, "alias": {"required": False, "type": "str"}, - "allow-traffic-redirect": {"required": False, "type": "str", + "allow_traffic_redirect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "anti-replay": {"required": False, "type": "str", + "anti_replay": {"required": False, "type": "str", "choices": ["disable", "loose", "strict"]}, - "arp-max-entry": {"required": False, "type": "int"}, + "arp_max_entry": {"required": False, "type": "int"}, "asymroute": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "auth-cert": {"required": False, "type": "str"}, - "auth-http-port": {"required": False, "type": "int"}, - "auth-https-port": {"required": False, "type": "int"}, - "auth-keepalive": {"required": False, "type": "str", + "auth_cert": {"required": False, "type": "str"}, + "auth_http_port": {"required": False, "type": "int"}, + "auth_https_port": {"required": False, "type": "int"}, + "auth_keepalive": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "auth-session-limit": {"required": False, "type": "str", + "auth_session_limit": {"required": False, "type": "str", "choices": ["block-new", "logout-inactive"]}, - "auto-auth-extension-device": {"required": False, "type": "str", + "auto_auth_extension_device": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "av-affinity": {"required": False, "type": "str"}, - "av-failopen": {"required": False, "type": "str", + "av_affinity": {"required": False, "type": "str"}, + "av_failopen": {"required": False, "type": "str", "choices": ["pass", "off", "one-shot"]}, - "av-failopen-session": {"required": False, "type": "str", + "av_failopen_session": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "batch-cmdb": {"required": False, "type": "str", + "batch_cmdb": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "block-session-timer": {"required": False, "type": "int"}, - "br-fdb-max-entry": {"required": False, "type": "int"}, - "cert-chain-max": {"required": False, "type": "int"}, - "cfg-revert-timeout": {"required": False, "type": "int"}, - "cfg-save": {"required": False, "type": "str", + "block_session_timer": {"required": False, "type": "int"}, + "br_fdb_max_entry": {"required": False, "type": "int"}, + "cert_chain_max": {"required": False, "type": "int"}, + "cfg_revert_timeout": {"required": False, "type": "int"}, + "cfg_save": {"required": False, "type": "str", "choices": ["automatic", "manual", "revert"]}, - "check-protocol-header": {"required": False, "type": "str", + "check_protocol_header": {"required": False, "type": "str", "choices": ["loose", "strict"]}, - "check-reset-range": {"required": False, "type": "str", + "check_reset_range": {"required": False, "type": "str", "choices": ["strict", "disable"]}, - "cli-audit-log": {"required": False, "type": "str", + "cli_audit_log": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "clt-cert-req": {"required": False, "type": "str", + "clt_cert_req": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "compliance-check": {"required": False, "type": "str", + "compliance_check": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "compliance-check-time": {"required": False, "type": "str"}, - "cpu-use-threshold": {"required": False, "type": "int"}, - "csr-ca-attribute": {"required": False, "type": "str", + "compliance_check_time": {"required": False, "type": "str"}, + "cpu_use_threshold": {"required": False, "type": "int"}, + "csr_ca_attribute": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "daily-restart": {"required": False, "type": "str", + "daily_restart": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "device-identification-active-scan-delay": {"required": False, "type": "int"}, - "device-idle-timeout": {"required": False, "type": "int"}, - "dh-params": {"required": False, "type": "str", + "device_identification_active_scan_delay": {"required": False, "type": "int"}, + "device_idle_timeout": {"required": False, "type": "int"}, + "dh_params": {"required": False, "type": "str", "choices": ["1024", "1536", "2048", "3072", "4096", "6144", "8192"]}, + "dnsproxy_worker_count": {"required": False, "type": "int"}, "dst": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "endpoint-control-fds-access": {"required": False, "type": "str", + "endpoint_control_fds_access": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "endpoint-control-portal-port": {"required": False, "type": "int"}, + "endpoint_control_portal_port": {"required": False, "type": "int"}, "failtime": {"required": False, "type": "int"}, - "fds-statistics": {"required": False, "type": "str", + "fds_statistics": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fds-statistics-period": {"required": False, "type": "int"}, - "fgd-alert-subscription": {"required": False, "type": "str", + "fds_statistics_period": {"required": False, "type": "int"}, + "fgd_alert_subscription": {"required": False, "type": "str", "choices": ["advisory", "latest-threat", "latest-virus", "latest-attack", "new-antivirus-db", "new-attack-db"]}, "fortiextender": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fortiextender-data-port": {"required": False, "type": "int"}, - "fortiextender-vlan-mode": {"required": False, "type": "str", + "fortiextender_data_port": {"required": False, "type": "int"}, + "fortiextender_vlan_mode": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fortiservice-port": {"required": False, "type": "int"}, - "gui-certificates": {"required": False, "type": "str", + "fortiservice_port": {"required": False, "type": "int"}, + "gui_certificates": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "gui-custom-language": {"required": False, "type": "str", + "gui_custom_language": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "gui-date-format": {"required": False, "type": "str", + "gui_date_format": {"required": False, "type": "str", "choices": ["yyyy/MM/dd", "dd/MM/yyyy", "MM/dd/yyyy", "yyyy-MM-dd", "dd-MM-yyyy", "MM-dd-yyyy"]}, - "gui-device-latitude": {"required": False, "type": "str"}, - "gui-device-longitude": {"required": False, "type": "str"}, - "gui-display-hostname": {"required": False, "type": "str", + "gui_device_latitude": {"required": False, "type": "str"}, + "gui_device_longitude": {"required": False, "type": "str"}, + "gui_display_hostname": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "gui-ipv6": {"required": False, "type": "str", + "gui_ipv6": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "gui-lines-per-page": {"required": False, "type": "int"}, - "gui-theme": {"required": False, "type": "str", + "gui_lines_per_page": {"required": False, "type": "int"}, + "gui_theme": {"required": False, "type": "str", "choices": ["green", "red", "blue", "melongene", "mariner"]}, - "gui-wireless-opensecurity": {"required": False, "type": "str", + "gui_wireless_opensecurity": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "honor-df": {"required": False, "type": "str", + "honor_df": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "hostname": {"required": False, "type": "str"}, - "igmp-state-limit": {"required": False, "type": "int"}, + "igmp_state_limit": {"required": False, "type": "int"}, "interval": {"required": False, "type": "int"}, - "ip-src-port-range": {"required": False, "type": "str"}, - "ips-affinity": {"required": False, "type": "str"}, - "ipsec-asic-offload": {"required": False, "type": "str", + "ip_src_port_range": {"required": False, "type": "str"}, + "ips_affinity": {"required": False, "type": "str"}, + "ipsec_asic_offload": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ipsec-hmac-offload": {"required": False, "type": "str", + "ipsec_hmac_offload": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ipsec-soft-dec-async": {"required": False, "type": "str", + "ipsec_soft_dec_async": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ipv6-accept-dad": {"required": False, "type": "int"}, - "ipv6-allow-anycast-probe": {"required": False, "type": "str", + "ipv6_accept_dad": {"required": False, "type": "int"}, + "ipv6_allow_anycast_probe": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "language": {"required": False, "type": "str", "choices": ["english", "french", "spanish", "portuguese", "japanese", "trach", "simch", "korean"]}, "ldapconntimeout": {"required": False, "type": "int"}, - "lldp-transmission": {"required": False, "type": "str", + "lldp_transmission": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "log-ssl-connection": {"required": False, "type": "str", + "log_ssl_connection": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "log-uuid": {"required": False, "type": "str", + "log_uuid": {"required": False, "type": "str", "choices": ["disable", "policy-only", "extended"]}, - "login-timestamp": {"required": False, "type": "str", + "login_timestamp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "long-vdom-name": {"required": False, "type": "str", + "long_vdom_name": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "management-vdom": {"required": False, "type": "str"}, - "max-dlpstat-memory": {"required": False, "type": "int"}, - "max-route-cache-size": {"required": False, "type": "int"}, - "mc-ttl-notchange": {"required": False, "type": "str", + "management_vdom": {"required": False, "type": "str"}, + "max_dlpstat_memory": {"required": False, "type": "int"}, + "max_route_cache_size": {"required": False, "type": "int"}, + "mc_ttl_notchange": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "memory-use-threshold-extreme": {"required": False, "type": "int"}, - "memory-use-threshold-green": {"required": False, "type": "int"}, - "memory-use-threshold-red": {"required": False, "type": "int"}, - "miglog-affinity": {"required": False, "type": "str"}, - "miglogd-children": {"required": False, "type": "int"}, - "multi-factor-authentication": {"required": False, "type": "str", + "memory_use_threshold_extreme": {"required": False, "type": "int"}, + "memory_use_threshold_green": {"required": False, "type": "int"}, + "memory_use_threshold_red": {"required": False, "type": "int"}, + "miglog_affinity": {"required": False, "type": "str"}, + "miglogd_children": {"required": False, "type": "int"}, + "multi_factor_authentication": {"required": False, "type": "str", "choices": ["optional", "mandatory"]}, - "multicast-forward": {"required": False, "type": "str", + "multicast_forward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ndp-max-entry": {"required": False, "type": "int"}, - "per-user-bwl": {"required": False, "type": "str", + "ndp_max_entry": {"required": False, "type": "int"}, + "per_user_bwl": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "policy-auth-concurrent": {"required": False, "type": "int"}, - "post-login-banner": {"required": False, "type": "str", + "policy_auth_concurrent": {"required": False, "type": "int"}, + "post_login_banner": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "pre-login-banner": {"required": False, "type": "str", + "pre_login_banner": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "private-data-encryption": {"required": False, "type": "str", + "private_data_encryption": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "proxy-auth-lifetime": {"required": False, "type": "str", + "proxy_auth_lifetime": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "proxy-auth-lifetime-timeout": {"required": False, "type": "int"}, - "proxy-auth-timeout": {"required": False, "type": "int"}, - "proxy-cipher-hardware-acceleration": {"required": False, "type": "str", + "proxy_auth_lifetime_timeout": {"required": False, "type": "int"}, + "proxy_auth_timeout": {"required": False, "type": "int"}, + "proxy_cipher_hardware_acceleration": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "proxy-kxp-hardware-acceleration": {"required": False, "type": "str", + "proxy_kxp_hardware_acceleration": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "proxy-re-authentication-mode": {"required": False, "type": "str", + "proxy_re_authentication_mode": {"required": False, "type": "str", "choices": ["session", "traffic", "absolute"]}, - "proxy-worker-count": {"required": False, "type": "int"}, - "radius-port": {"required": False, "type": "int"}, - "reboot-upon-config-restore": {"required": False, "type": "str", + "proxy_worker_count": {"required": False, "type": "int"}, + "radius_port": {"required": False, "type": "int"}, + "reboot_upon_config_restore": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "refresh": {"required": False, "type": "int"}, "remoteauthtimeout": {"required": False, "type": "int"}, - "reset-sessionless-tcp": {"required": False, "type": "str", + "reset_sessionless_tcp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "restart-time": {"required": False, "type": "str"}, - "revision-backup-on-logout": {"required": False, "type": "str", + "restart_time": {"required": False, "type": "str"}, + "revision_backup_on_logout": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "revision-image-auto-backup": {"required": False, "type": "str", + "revision_image_auto_backup": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "scanunit-count": {"required": False, "type": "int"}, - "security-rating-result-submission": {"required": False, "type": "str", + "scanunit_count": {"required": False, "type": "int"}, + "security_rating_result_submission": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "security-rating-run-on-schedule": {"required": False, "type": "str", + "security_rating_run_on_schedule": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "send-pmtu-icmp": {"required": False, "type": "str", + "send_pmtu_icmp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "snat-route-change": {"required": False, "type": "str", + "snat_route_change": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "special-file-23-support": {"required": False, "type": "str", + "special_file_23_support": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "ssh-cbc-cipher": {"required": False, "type": "str", + "ssd_trim_date": {"required": False, "type": "int"}, + "ssd_trim_freq": {"required": False, "type": "str", + "choices": ["never", "hourly", "daily", + "weekly", "monthly"]}, + "ssd_trim_hour": {"required": False, "type": "int"}, + "ssd_trim_min": {"required": False, "type": "int"}, + "ssd_trim_weekday": {"required": False, "type": "str", + "choices": ["sunday", "monday", "tuesday", + "wednesday", "thursday", "friday", + "saturday"]}, + "ssh_cbc_cipher": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ssh-hmac-md5": {"required": False, "type": "str", + "ssh_hmac_md5": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ssh-kex-sha1": {"required": False, "type": "str", + "ssh_kex_sha1": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ssl-min-proto-version": {"required": False, "type": "str", + "ssl_min_proto_version": {"required": False, "type": "str", "choices": ["SSLv3", "TLSv1", "TLSv1-1", "TLSv1-2"]}, - "ssl-static-key-ciphers": {"required": False, "type": "str", + "ssl_static_key_ciphers": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "sslvpn-cipher-hardware-acceleration": {"required": False, "type": "str", + "sslvpn_cipher_hardware_acceleration": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "sslvpn-kxp-hardware-acceleration": {"required": False, "type": "str", + "sslvpn_kxp_hardware_acceleration": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "sslvpn-max-worker-count": {"required": False, "type": "int"}, - "sslvpn-plugin-version-check": {"required": False, "type": "str", + "sslvpn_max_worker_count": {"required": False, "type": "int"}, + "sslvpn_plugin_version_check": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "strict-dirty-session-check": {"required": False, "type": "str", + "strict_dirty_session_check": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "strong-crypto": {"required": False, "type": "str", + "strong_crypto": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller": {"required": False, "type": "str", + "switch_controller": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "switch-controller-reserved-network": {"required": False, "type": "str"}, - "sys-perf-log-interval": {"required": False, "type": "int"}, - "tcp-halfclose-timer": {"required": False, "type": "int"}, - "tcp-halfopen-timer": {"required": False, "type": "int"}, - "tcp-option": {"required": False, "type": "str", + "switch_controller_reserved_network": {"required": False, "type": "str"}, + "sys_perf_log_interval": {"required": False, "type": "int"}, + "tcp_halfclose_timer": {"required": False, "type": "int"}, + "tcp_halfopen_timer": {"required": False, "type": "int"}, + "tcp_option": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "tcp-timewait-timer": {"required": False, "type": "int"}, + "tcp_timewait_timer": {"required": False, "type": "int"}, "tftp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "timezone": {"required": False, "type": "str", @@ -1661,39 +1918,39 @@ def main(): "71", "72", "00", "82", "73", "86", "76"]}, - "tp-mc-skip-policy": {"required": False, "type": "str", + "tp_mc_skip_policy": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "traffic-priority": {"required": False, "type": "str", + "traffic_priority": {"required": False, "type": "str", "choices": ["tos", "dscp"]}, - "traffic-priority-level": {"required": False, "type": "str", + "traffic_priority_level": {"required": False, "type": "str", "choices": ["low", "medium", "high"]}, - "two-factor-email-expiry": {"required": False, "type": "int"}, - "two-factor-fac-expiry": {"required": False, "type": "int"}, - "two-factor-ftk-expiry": {"required": False, "type": "int"}, - "two-factor-ftm-expiry": {"required": False, "type": "int"}, - "two-factor-sms-expiry": {"required": False, "type": "int"}, - "udp-idle-timer": {"required": False, "type": "int"}, - "user-server-cert": {"required": False, "type": "str"}, - "vdom-admin": {"required": False, "type": "str", + "two_factor_email_expiry": {"required": False, "type": "int"}, + "two_factor_fac_expiry": {"required": False, "type": "int"}, + "two_factor_ftk_expiry": {"required": False, "type": "int"}, + "two_factor_ftm_expiry": {"required": False, "type": "int"}, + "two_factor_sms_expiry": {"required": False, "type": "int"}, + "udp_idle_timer": {"required": False, "type": "int"}, + "user_server_cert": {"required": False, "type": "str"}, + "vdom_admin": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "vip-arp-range": {"required": False, "type": "str", + "vip_arp_range": {"required": False, "type": "str", "choices": ["unlimited", "restricted"]}, - "virtual-server-count": {"required": False, "type": "int"}, - "virtual-server-hardware-acceleration": {"required": False, "type": "str", + "virtual_server_count": {"required": False, "type": "int"}, + "virtual_server_hardware_acceleration": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "wad-affinity": {"required": False, "type": "str"}, - "wad-csvc-cs-count": {"required": False, "type": "int"}, - "wad-csvc-db-count": {"required": False, "type": "int"}, - "wad-source-affinity": {"required": False, "type": "str", + "wad_affinity": {"required": False, "type": "str"}, + "wad_csvc_cs_count": {"required": False, "type": "int"}, + "wad_csvc_db_count": {"required": False, "type": "int"}, + "wad_source_affinity": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "wad-worker-count": {"required": False, "type": "int"}, - "wifi-ca-certificate": {"required": False, "type": "str"}, - "wifi-certificate": {"required": False, "type": "str"}, - "wimax-4g-usb": {"required": False, "type": "str", + "wad_worker_count": {"required": False, "type": "int"}, + "wifi_ca_certificate": {"required": False, "type": "str"}, + "wifi_certificate": {"required": False, "type": "str"}, + "wimax_4g_usb": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "wireless-controller": {"required": False, "type": "str", + "wireless_controller": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "wireless-controller-port": {"required": False, "type": "int"} + "wireless_controller_port": {"required": False, "type": "int"} } } @@ -1701,14 +1958,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_interface.py b/lib/ansible/modules/network/fortios/fortios_system_interface.py index 5a1da7590b5..004b6650ceb 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_interface.py +++ b/lib/ansible/modules/network/fortios/fortios_system_interface.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_system_interface short_description: Configure interfaces in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and interface category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,49 +41,65 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_interface: description: - Configure interfaces. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - ac-name: + ac_name: description: - PPPoE server name. + type: str aggregate: description: - Aggregate interface. + type: str algorithm: description: - Frame distribution algorithm. + type: str choices: - L2 - L3 @@ -94,9 +107,11 @@ options: alias: description: - Alias will be displayed with the interface name to make it easier to distinguish. + type: str allowaccess: description: - Permitted types of management access to this interface. + type: list choices: - ping - https @@ -109,91 +124,109 @@ options: - probe-response - capwap - ftm - ap-discover: + ap_discover: description: - Enable/disable automatic registration of unknown FortiAP devices. + type: str choices: - enable - disable arpforward: description: - Enable/disable ARP forwarding. + type: str choices: - enable - disable - auth-type: + auth_type: description: - PPP authentication type to use. + type: str choices: - auto - pap - chap - mschapv1 - mschapv2 - auto-auth-extension-device: + auto_auth_extension_device: description: - Enable/disable automatic authorization of dedicated Fortinet extension device on this interface. + type: str choices: - enable - disable bfd: description: - Bidirectional Forwarding Detection (BFD) settings. + type: str choices: - global - enable - disable - bfd-desired-min-tx: + bfd_desired_min_tx: description: - BFD desired minimal transmit interval. - bfd-detect-mult: + type: int + bfd_detect_mult: description: - BFD detection multiplier. - bfd-required-min-rx: + type: int + bfd_required_min_rx: description: - BFD required minimal receive interval. - broadcast-forticlient-discovery: + type: int + broadcast_forticlient_discovery: description: - Enable/disable broadcasting FortiClient discovery messages. + type: str choices: - enable - disable - broadcast-forward: + broadcast_forward: description: - Enable/disable broadcast forwarding. + type: str choices: - enable - disable - captive-portal: + captive_portal: description: - Enable/disable captive portal. - cli-conn-status: + type: int + cli_conn_status: description: - CLI connection status. + type: int color: description: - Color of icon on the GUI. - dedicated-to: + type: int + dedicated_to: description: - Configure interface for single purpose. + type: str choices: - none - management defaultgw: description: - Enable to get the gateway IP from the DHCP or PPPoE server. + type: str choices: - enable - disable description: description: - Description. - detected-peer-mtu: + type: str + detected_peer_mtu: description: - MTU of detected peer (0 - 4294967295). + type: int detectprotocol: description: - Protocols used to detect the server. + type: str choices: - ping - tcp-echo @@ -201,305 +234,370 @@ options: detectserver: description: - Gateway's ping server for this IP. - device-access-list: + type: str + device_access_list: description: - Device access list. - device-identification: + type: str + device_identification: description: - Enable/disable passively gathering of device identity information about the devices on the network connected to this interface. + type: str choices: - enable - disable - device-identification-active-scan: + device_identification_active_scan: description: - Enable/disable active gathering of device identity information about the devices on the network connected to this interface. + type: str choices: - enable - disable - device-netscan: + device_netscan: description: - Enable/disable inclusion of devices detected on this interface in network vulnerability scans. + type: str choices: - disable - enable - device-user-identification: + device_user_identification: description: - Enable/disable passive gathering of user identity information about users on this interface. + type: str choices: - enable - disable devindex: description: - Device Index. - dhcp-client-identifier: + type: int + dhcp_client_identifier: description: - DHCP client identifier. - dhcp-relay-agent-option: + type: str + dhcp_relay_agent_option: description: - Enable/disable DHCP relay agent option. + type: str choices: - enable - disable - dhcp-relay-ip: + dhcp_relay_ip: description: - DHCP relay IP address. - dhcp-relay-service: + type: str + dhcp_relay_service: description: - Enable/disable allowing this interface to act as a DHCP relay. + type: str choices: - disable - enable - dhcp-relay-type: + dhcp_relay_type: description: - DHCP relay type (regular or IPsec). + type: str choices: - regular - ipsec - dhcp-renew-time: + dhcp_renew_time: description: - DHCP renew time in seconds (300-604800), 0 means use the renew time provided by the server. - disc-retry-timeout: + type: int + disc_retry_timeout: description: - Time in seconds to wait before retrying to start a PPPoE discovery, 0 means no timeout. - disconnect-threshold: + type: int + disconnect_threshold: description: - Time in milliseconds to wait before sending a notification that this interface is down or disconnected. + type: int distance: description: - Distance for routes learned through PPPoE or DHCP, lower distance indicates preferred route. - dns-server-override: + type: int + dns_server_override: description: - Enable/disable use DNS acquired by DHCP or PPPoE. + type: str choices: - enable - disable - drop-fragment: + drop_fragment: description: - Enable/disable drop fragment packets. + type: str choices: - enable - disable - drop-overlapped-fragment: + drop_overlapped_fragment: description: - Enable/disable drop overlapped fragment packets. + type: str choices: - enable - disable - egress-shaping-profile: + egress_shaping_profile: description: - Outgoing traffic shaping profile. - endpoint-compliance: + type: str + endpoint_compliance: description: - Enable/disable endpoint compliance enforcement. + type: str choices: - enable - disable - estimated-downstream-bandwidth: + estimated_downstream_bandwidth: description: - Estimated maximum downstream bandwidth (kbps). Used to estimate link utilization. - estimated-upstream-bandwidth: + type: int + estimated_upstream_bandwidth: description: - Estimated maximum upstream bandwidth (kbps). Used to estimate link utilization. - explicit-ftp-proxy: + type: int + explicit_ftp_proxy: description: - Enable/disable the explicit FTP proxy on this interface. + type: str choices: - enable - disable - explicit-web-proxy: + explicit_web_proxy: description: - Enable/disable the explicit web proxy on this interface. + type: str choices: - enable - disable external: description: - Enable/disable identifying the interface as an external interface (which usually means it's connected to the Internet). + type: str choices: - enable - disable - fail-action-on-extender: + fail_action_on_extender: description: - Action on extender when interface fail . + type: str choices: - soft-restart - hard-restart - reboot - fail-alert-interfaces: + fail_alert_interfaces: description: - Names of the FortiGate interfaces from which the link failure alert is sent for this interface. + type: list suboptions: name: description: - Names of the physical interfaces belonging to the aggregate or redundant interface. Source system.interface.name. required: true - fail-alert-method: + type: str + fail_alert_method: description: - Select link-failed-signal or link-down method to alert about a failed link. + type: str choices: - link-failed-signal - link-down - fail-detect: + fail_detect: description: - Enable/disable fail detection features for this interface. + type: str choices: - enable - disable - fail-detect-option: + fail_detect_option: description: - Options for detecting that this interface has failed. + type: str choices: - detectserver - link-down fortiheartbeat: description: - Enable/disable FortiHeartBeat (FortiTelemetry on GUI). + type: str choices: - enable - disable fortilink: description: - Enable FortiLink to dedicate this interface to manage other Fortinet devices. + type: str choices: - enable - disable - fortilink-backup-link: + fortilink_backup_link: description: - fortilink split interface backup link. - fortilink-split-interface: + type: int + fortilink_split_interface: description: - Enable/disable FortiLink split interface to connect member link to different FortiSwitch in stack for uplink redundancy (maximum 2 interfaces in the "members" command). + type: str choices: - enable - disable - fortilink-stacking: + fortilink_stacking: description: - Enable/disable FortiLink switch-stacking on this interface. + type: str choices: - enable - disable - forward-domain: + forward_domain: description: - Transparent mode forward domain. + type: int gwdetect: description: - Enable/disable detect gateway alive for first. + type: str choices: - enable - disable - ha-priority: + ha_priority: description: - HA election priority for the PING server. - icmp-accept-redirect: + type: int + icmp_accept_redirect: description: - Enable/disable ICMP accept redirect. + type: str choices: - enable - disable - icmp-send-redirect: + icmp_send_redirect: description: - Enable/disable ICMP send redirect. + type: str choices: - enable - disable - ident-accept: + ident_accept: description: - Enable/disable authentication for this interface. + type: str choices: - enable - disable - idle-timeout: + idle_timeout: description: - PPPoE auto disconnect after idle timeout seconds, 0 means no timeout. + type: int inbandwidth: description: - Bandwidth limit for incoming traffic (0 - 16776000 kbps), 0 means unlimited. - ingress-spillover-threshold: + type: int + ingress_spillover_threshold: description: - Ingress Spillover threshold (0 - 16776000 kbps). + type: int interface: description: - Interface name. Source system.interface.name. + type: str internal: description: - Implicitly created. + type: int ip: description: - "Interface IPv4 address and subnet mask, syntax: X.X.X.X/24." + type: str ipmac: description: - Enable/disable IP/MAC binding. + type: str choices: - enable - disable - ips-sniffer-mode: + ips_sniffer_mode: description: - Enable/disable the use of this interface as a one-armed sniffer. + type: str choices: - enable - disable ipunnumbered: description: - Unnumbered IP used for PPPoE interfaces for which no unique local address is provided. + type: str ipv6: description: - IPv6 of interface. + type: dict suboptions: autoconf: description: - Enable/disable address auto config. + type: str choices: - enable - disable - dhcp6-client-options: + dhcp6_client_options: description: - DHCPv6 client options. + type: str choices: - rapid - iapd - iana - dhcp6-information-request: + dhcp6_information_request: description: - Enable/disable DHCPv6 information request. + type: str choices: - enable - disable - dhcp6-prefix-delegation: + dhcp6_prefix_delegation: description: - Enable/disable DHCPv6 prefix delegation. + type: str choices: - enable - disable - dhcp6-prefix-hint: + dhcp6_prefix_hint: description: - DHCPv6 prefix that will be used as a hint to the upstream DHCPv6 server. - dhcp6-prefix-hint-plt: + type: str + dhcp6_prefix_hint_plt: description: - DHCPv6 prefix hint preferred life time (sec), 0 means unlimited lease time. - dhcp6-prefix-hint-vlt: + type: int + dhcp6_prefix_hint_vlt: description: - DHCPv6 prefix hint valid life time (sec). - dhcp6-relay-ip: + type: int + dhcp6_relay_ip: description: - DHCPv6 relay IP address. - dhcp6-relay-service: + type: str + dhcp6_relay_service: description: - Enable/disable DHCPv6 relay. + type: str choices: - disable - enable - dhcp6-relay-type: + dhcp6_relay_type: description: - DHCPv6 relay type. + type: str choices: - regular - ip6-address: + ip6_address: description: - "Primary IPv6 address prefix, syntax: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xxx" - ip6-allowaccess: + type: str + ip6_allowaccess: description: - Allow management access to the interface. + type: list choices: - ping - https @@ -509,35 +607,41 @@ options: - telnet - fgfm - capwap - ip6-default-life: + ip6_default_life: description: - Default life (sec). - ip6-delegated-prefix-list: + type: int + ip6_delegated_prefix_list: description: - Advertised IPv6 delegated prefix list. + type: list suboptions: - autonomous-flag: + autonomous_flag: description: - Enable/disable the autonomous flag. + type: str choices: - enable - disable - onlink-flag: + onlink_flag: description: - Enable/disable the onlink flag. + type: str choices: - enable - disable - prefix-id: + prefix_id: description: - Prefix ID. - required: true + type: int rdnss: description: - Recursive DNS server option. - rdnss-service: + type: str + rdnss_service: description: - Recursive DNS service option. + type: str choices: - delegated - default @@ -545,221 +649,274 @@ options: subnet: description: - Add subnet ID to routing prefix. - upstream-interface: + type: str + upstream_interface: description: - Name of the interface that provides delegated information. Source system.interface.name. - ip6-dns-server-override: + type: str + ip6_dns_server_override: description: - Enable/disable using the DNS server acquired by DHCP. + type: str choices: - enable - disable - ip6-extra-addr: + ip6_extra_addr: description: - Extra IPv6 address prefixes of interface. + type: list suboptions: prefix: description: - IPv6 address prefix. required: true - ip6-hop-limit: + type: str + ip6_hop_limit: description: - Hop limit (0 means unspecified). - ip6-link-mtu: + type: int + ip6_link_mtu: description: - IPv6 link MTU. - ip6-manage-flag: + type: int + ip6_manage_flag: description: - Enable/disable the managed flag. + type: str choices: - enable - disable - ip6-max-interval: + ip6_max_interval: description: - IPv6 maximum interval (4 to 1800 sec). - ip6-min-interval: + type: int + ip6_min_interval: description: - IPv6 minimum interval (3 to 1350 sec). - ip6-mode: + type: int + ip6_mode: description: - Addressing mode (static, DHCP, delegated). + type: str choices: - static - dhcp - pppoe - delegated - ip6-other-flag: + ip6_other_flag: description: - Enable/disable the other IPv6 flag. + type: str choices: - enable - disable - ip6-prefix-list: + ip6_prefix_list: description: - Advertised prefix list. + type: list suboptions: - autonomous-flag: + autonomous_flag: description: - Enable/disable the autonomous flag. + type: str choices: - enable - disable dnssl: description: - DNS search list option. + type: list suboptions: domain: description: - Domain name. required: true - onlink-flag: + type: str + onlink_flag: description: - Enable/disable the onlink flag. + type: str choices: - enable - disable - preferred-life-time: + preferred_life_time: description: - Preferred life time (sec). + type: int prefix: description: - IPv6 prefix. required: true + type: str rdnss: description: - Recursive DNS server option. - valid-life-time: + type: str + valid_life_time: description: - Valid life time (sec). - ip6-reachable-time: + type: int + ip6_reachable_time: description: - IPv6 reachable time (milliseconds; 0 means unspecified). - ip6-retrans-time: + type: int + ip6_retrans_time: description: - IPv6 retransmit time (milliseconds; 0 means unspecified). - ip6-send-adv: + type: int + ip6_send_adv: description: - Enable/disable sending advertisements about the interface. + type: str choices: - enable - disable - ip6-subnet: + ip6_subnet: description: - " Subnet to routing prefix, syntax: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xxx" - ip6-upstream-interface: + type: str + ip6_upstream_interface: description: - Interface name providing delegated information. Source system.interface.name. - nd-cert: + type: str + nd_cert: description: - Neighbor discovery certificate. Source certificate.local.name. - nd-cga-modifier: + type: str + nd_cga_modifier: description: - Neighbor discovery CGA modifier. - nd-mode: + type: str + nd_mode: description: - Neighbor discovery mode. + type: str choices: - basic - SEND-compatible - nd-security-level: + nd_security_level: description: - - Neighbor discovery security level (0 - 7; 0 = least secure, default = 0). - nd-timestamp-delta: + - Neighbor discovery security level (0 - 7; 0 = least secure). + type: int + nd_timestamp_delta: description: - - Neighbor discovery timestamp delta value (1 - 3600 sec; default = 300). - nd-timestamp-fuzz: + - Neighbor discovery timestamp delta value (1 - 3600 sec; ). + type: int + nd_timestamp_fuzz: description: - - Neighbor discovery timestamp fuzz factor (1 - 60 sec; default = 1). + - Neighbor discovery timestamp fuzz factor (1 - 60 sec; ). + type: int vrip6_link_local: description: - Link-local IPv6 address of virtual router. - vrrp-virtual-mac6: + type: str + vrrp_virtual_mac6: description: - Enable/disable virtual MAC for VRRP. + type: str choices: - enable - disable vrrp6: description: - IPv6 VRRP configuration. + type: list suboptions: - accept-mode: + accept_mode: description: - Enable/disable accept mode. + type: str choices: - enable - disable - adv-interval: + adv_interval: description: - Advertisement interval (1 - 255 seconds). + type: int preempt: description: - Enable/disable preempt mode. + type: str choices: - enable - disable priority: description: - Priority of the virtual router (1 - 255). - start-time: + type: int + start_time: description: - Startup time (1 - 255 seconds). + type: int status: description: - Enable/disable VRRP. + type: str choices: - enable - disable vrdst6: description: - Monitor the route to this destination. + type: str vrgrp: description: - VRRP group ID (1 - 65535). + type: int vrid: description: - Virtual router identifier (1 - 255). required: true + type: int vrip6: description: - IPv6 address of the virtual router. + type: str l2forward: description: - Enable/disable l2 forwarding. + type: str choices: - enable - disable - lacp-ha-slave: + lacp_ha_slave: description: - LACP HA slave. + type: str choices: - enable - disable - lacp-mode: + lacp_mode: description: - LACP mode. + type: str choices: - static - passive - active - lacp-speed: + lacp_speed: description: - How often the interface sends LACP messages. + type: str choices: - slow - fast - lcp-echo-interval: + lcp_echo_interval: description: - Time in seconds between PPPoE Link Control Protocol (LCP) echo requests. - lcp-max-echo-fails: + type: int + lcp_max_echo_fails: description: - Maximum missed LCP echo messages before disconnect. - link-up-delay: + type: int + link_up_delay: description: - Number of milliseconds to wait before considering a link is up. - lldp-transmission: + type: int + lldp_transmission: description: - Enable/disable Link Layer Discovery Protocol (LLDP) transmission. + type: str choices: - enable - disable @@ -767,37 +924,45 @@ options: macaddr: description: - Change the interface's MAC address. - managed-device: + type: str + managed_device: description: - Available when FortiLink is enabled, used for managed devices through FortiLink interface. + type: list suboptions: name: description: - Managed dev identifier. required: true - management-ip: + type: str + management_ip: description: - High Availability in-band management IP address of this interface. + type: str member: description: - Physical interfaces that belong to the aggregate or redundant interface. + type: list suboptions: - interface-name: + interface_name: description: - Physical interface name. Source system.interface.name. - required: true - min-links: + type: str + min_links: description: - Minimum number of aggregated ports that must be up. - min-links-down: + type: int + min_links_down: description: - Action to take when less than the configured minimum number of links are active. + type: str choices: - operational - administrative mode: description: - Addressing mode (static, DHCP, PPPoE). + type: str choices: - static - dhcp @@ -805,9 +970,11 @@ options: mtu: description: - MTU value for this interface. - mtu-override: + type: int + mtu_override: description: - Enable to set a custom MTU for this interface. + type: str choices: - enable - disable @@ -815,21 +982,25 @@ options: description: - Name. required: true + type: str ndiscforward: description: - Enable/disable NDISC forwarding. + type: str choices: - enable - disable - netbios-forward: + netbios_forward: description: - Enable/disable NETBIOS forwarding. + type: str choices: - disable - enable - netflow-sampler: + netflow_sampler: description: - Enable/disable NetFlow on this interface and set the data that NetFlow collects (rx, tx, or both). + type: str choices: - disable - tx @@ -838,119 +1009,145 @@ options: outbandwidth: description: - Bandwidth limit for outgoing traffic (0 - 16776000 kbps). - padt-retry-timeout: + type: int + padt_retry_timeout: description: - PPPoE Active Discovery Terminate (PADT) used to terminate sessions after an idle time. + type: int password: description: - PPPoE account's password. - ping-serv-status: + type: str + ping_serv_status: description: - PING server status. - polling-interval: + type: int + polling_interval: description: - sFlow polling interval (1 - 255 sec). - pppoe-unnumbered-negotiate: + type: int + pppoe_unnumbered_negotiate: description: - Enable/disable PPPoE unnumbered negotiation. + type: str choices: - enable - disable - pptp-auth-type: + pptp_auth_type: description: - PPTP authentication type. + type: str choices: - auto - pap - chap - mschapv1 - mschapv2 - pptp-client: + pptp_client: description: - Enable/disable PPTP client. + type: str choices: - enable - disable - pptp-password: + pptp_password: description: - PPTP password. - pptp-server-ip: + type: str + pptp_server_ip: description: - PPTP server IP address. - pptp-timeout: + type: str + pptp_timeout: description: - Idle timer in minutes (0 for disabled). - pptp-user: + type: int + pptp_user: description: - PPTP user name. - preserve-session-route: + type: str + preserve_session_route: description: - Enable/disable preservation of session route when dirty. + type: str choices: - enable - disable priority: description: - Priority of learned routes. - priority-override: + type: int + priority_override: description: - Enable/disable fail back to higher priority port once recovered. + type: str choices: - enable - disable - proxy-captive-portal: + proxy_captive_portal: description: - Enable/disable proxy captive portal on this interface. + type: str choices: - enable - disable - redundant-interface: + redundant_interface: description: - Redundant interface. - remote-ip: + type: str + remote_ip: description: - Remote IP address of tunnel. - replacemsg-override-group: + type: str + replacemsg_override_group: description: - Replacement message override group. + type: str role: description: - Interface role. + type: str choices: - lan - wan - dmz - undefined - sample-direction: + sample_direction: description: - Data that NetFlow collects (rx, tx, or both). + type: str choices: - tx - rx - both - sample-rate: + sample_rate: description: - sFlow sample rate (10 - 99999). - scan-botnet-connections: + type: int + scan_botnet_connections: description: - Enable monitoring or blocking connections to Botnet servers through this interface. + type: str choices: - disable - block - monitor - secondary-IP: + secondary_IP: description: - Enable/disable adding a secondary IP to this interface. + type: str choices: - enable - disable secondaryip: description: - Second IP address of interface. + type: list suboptions: allowaccess: description: - Management access settings for the secondary IP address. + type: str choices: - ping - https @@ -966,6 +1163,7 @@ options: detectprotocol: description: - Protocols used to detect the server. + type: str choices: - ping - tcp-echo @@ -973,73 +1171,91 @@ options: detectserver: description: - Gateway's ping server for this IP. + type: str gwdetect: description: - Enable/disable detect gateway alive for first. + type: str choices: - enable - disable - ha-priority: + ha_priority: description: - HA election priority for the PING server. + type: int id: description: - ID. required: true + type: int ip: description: - Secondary IP address of the interface. - ping-serv-status: + type: str + ping_serv_status: description: - PING server status. - security-exempt-list: + type: int + security_exempt_list: description: - Name of security-exempt-list. - security-external-logout: + type: str + security_external_logout: description: - URL of external authentication logout server. - security-external-web: + type: str + security_external_web: description: - URL of external authentication web server. - security-groups: + type: str + security_groups: description: - User groups that can authenticate with the captive portal. + type: list suboptions: name: description: - Names of user groups that can authenticate with the captive portal. required: true - security-mac-auth-bypass: + type: str + security_mac_auth_bypass: description: - Enable/disable MAC authentication bypass. + type: str choices: - enable - disable - security-mode: + security_mode: description: - Turn on captive portal authentication for this interface. + type: str choices: - none - captive-portal - 802.1X - security-redirect-url: + security_redirect_url: description: - URL redirection after disclaimer/authentication. - service-name: + type: str + service_name: description: - PPPoE service name. - sflow-sampler: + type: str + sflow_sampler: description: - Enable/disable sFlow on this interface. + type: str choices: - enable - disable - snmp-index: + snmp_index: description: - Permanent SNMP Index of the interface. + type: int speed: description: - Interface speed. The default setting and the options available depend on the interface hardware. + type: str choices: - auto - 10full @@ -1049,30 +1265,35 @@ options: - 1000full - 1000half - 1000auto - spillover-threshold: + spillover_threshold: description: - Egress Spillover threshold (0 - 16776000 kbps), 0 means unlimited. - src-check: + type: int + src_check: description: - Enable/disable source IP check. + type: str choices: - enable - disable status: description: - Bring the interface up or shut the interface down. + type: str choices: - up - down stpforward: description: - Enable/disable STP forwarding. + type: str choices: - enable - disable - stpforward-mode: + stpforward_mode: description: - Configure STP forwarding mode. + type: str choices: - rpl-all-ext-id - rpl-bridge-ext-id @@ -1080,97 +1301,120 @@ options: subst: description: - Enable to always send packets from this interface to a destination MAC address. + type: str choices: - enable - disable - substitute-dst-mac: + substitute_dst_mac: description: - Destination MAC address that all packets are sent to from this interface. + type: str switch: description: - Contained in switch. - switch-controller-access-vlan: + type: str + switch_controller_access_vlan: description: - Block FortiSwitch port-to-port traffic. + type: str choices: - enable - disable - switch-controller-arp-inspection: + switch_controller_arp_inspection: description: - Enable/disable FortiSwitch ARP inspection. + type: str choices: - enable - disable - switch-controller-dhcp-snooping: + switch_controller_dhcp_snooping: description: - Switch controller DHCP snooping. + type: str choices: - enable - disable - switch-controller-dhcp-snooping-option82: + switch_controller_dhcp_snooping_option82: description: - Switch controller DHCP snooping option82. + type: str choices: - enable - disable - switch-controller-dhcp-snooping-verify-mac: + switch_controller_dhcp_snooping_verify_mac: description: - Switch controller DHCP snooping verify MAC. + type: str choices: - enable - disable - switch-controller-igmp-snooping: + switch_controller_igmp_snooping: description: - Switch controller IGMP snooping. + type: str choices: - enable - disable - switch-controller-learning-limit: + switch_controller_learning_limit: description: - Limit the number of dynamic MAC addresses on this VLAN (1 - 128, 0 = no limit, default). + type: int 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 - tcp-mss: + type: str + tcp_mss: description: - TCP maximum segment size. 0 means do not change segment size. - trust-ip-1: + type: int + trust_ip_1: description: - Trusted host for dedicated management traffic (0.0.0.0/24 for all hosts). - trust-ip-2: + type: str + trust_ip_2: description: - Trusted host for dedicated management traffic (0.0.0.0/24 for all hosts). - trust-ip-3: + type: str + trust_ip_3: description: - Trusted host for dedicated management traffic (0.0.0.0/24 for all hosts). - trust-ip6-1: + type: str + trust_ip6_1: description: - "Trusted IPv6 host for dedicated management traffic (::/0 for all hosts)." - trust-ip6-2: + type: str + trust_ip6_2: description: - "Trusted IPv6 host for dedicated management traffic (::/0 for all hosts)." - trust-ip6-3: + type: str + trust_ip6_3: description: - "Trusted IPv6 host for dedicated management traffic (::/0 for all hosts)." + type: str type: description: - Interface type. + type: str choices: - physical - vlan @@ -1190,106 +1434,139 @@ options: username: description: - Username of the PPPoE account, provided by your ISP. + type: str vdom: description: - Interface is in this virtual domain (VDOM). Source system.vdom.name. + type: str vindex: description: - Switch control interface VLAN ID. + type: int vlanforward: description: - Enable/disable traffic forwarding between VLANs on this interface. + type: str choices: - enable - disable vlanid: description: - VLAN ID (1 - 4094). + type: int vrf: description: - Virtual Routing Forwarding ID. + type: int vrrp: description: - VRRP configuration. + type: list suboptions: - accept-mode: + accept_mode: description: - Enable/disable accept mode. + type: str choices: - enable - disable - adv-interval: + adv_interval: description: - Advertisement interval (1 - 255 seconds). + type: int + ignore_default_route: + description: + - Enable/disable ignoring of default route when checking destination. + type: str + choices: + - enable + - disable preempt: description: - Enable/disable preempt mode. + type: str choices: - enable - disable priority: description: - Priority of the virtual router (1 - 255). - proxy-arp: + type: int + proxy_arp: description: - VRRP Proxy ARP configuration. + type: list suboptions: id: description: - ID. required: true + type: int ip: description: - Set IP addresses of proxy ARP. - start-time: + type: str + start_time: description: - Startup time (1 - 255 seconds). + type: int status: description: - Enable/disable this VRRP configuration. + type: str choices: - enable - disable version: description: - VRRP version. + type: str choices: - 2 - 3 vrdst: description: - Monitor the route to this destination. - vrdst-priority: + type: str + vrdst_priority: description: - Priority of the virtual router when the virtual router destination becomes unreachable (0 - 254). + type: int vrgrp: description: - VRRP group ID (1 - 65535). + type: int vrid: description: - Virtual router identifier (1 - 255). required: true + type: int vrip: description: - IP address of the virtual router. - vrrp-virtual-mac: + type: str + vrrp_virtual_mac: description: - Enable/disable use of virtual MAC for VRRP. + type: str choices: - enable - disable wccp: description: - Enable/disable WCCP on this interface. Used for encapsulated WCCP communication between WCCP clients and servers. + type: str choices: - enable - disable weight: description: - Default weight for static routes (if route has no weight configured). - wins-ip: + type: int + wins_ip: description: - WINS server IP. + type: str ''' EXAMPLES = ''' @@ -1299,6 +1576,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure interfaces. fortios_system_interface: @@ -1307,241 +1585,241 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_interface: - state: "present" - ac-name: "" + ac_name: "" aggregate: "" algorithm: "L2" alias: "" allowaccess: "ping" - ap-discover: "enable" + ap_discover: "enable" arpforward: "enable" - auth-type: "auto" - auto-auth-extension-device: "enable" + auth_type: "auto" + auto_auth_extension_device: "enable" bfd: "global" - bfd-desired-min-tx: "13" - bfd-detect-mult: "14" - bfd-required-min-rx: "15" - broadcast-forticlient-discovery: "enable" - broadcast-forward: "enable" - captive-portal: "18" - cli-conn-status: "19" + bfd_desired_min_tx: "13" + bfd_detect_mult: "14" + bfd_required_min_rx: "15" + broadcast_forticlient_discovery: "enable" + broadcast_forward: "enable" + captive_portal: "18" + cli_conn_status: "19" color: "20" - dedicated-to: "none" + dedicated_to: "none" defaultgw: "enable" description: "" - detected-peer-mtu: "24" + detected_peer_mtu: "24" detectprotocol: "ping" detectserver: "" - device-access-list: "" - device-identification: "enable" - device-identification-active-scan: "enable" - device-netscan: "disable" - device-user-identification: "enable" + device_access_list: "" + device_identification: "enable" + device_identification_active_scan: "enable" + device_netscan: "disable" + device_user_identification: "enable" devindex: "32" - dhcp-client-identifier: "myId_33" - dhcp-relay-agent-option: "enable" - dhcp-relay-ip: "" - dhcp-relay-service: "disable" - dhcp-relay-type: "regular" - dhcp-renew-time: "38" - disc-retry-timeout: "39" - disconnect-threshold: "40" + dhcp_client_identifier: "myId_33" + dhcp_relay_agent_option: "enable" + dhcp_relay_ip: "" + dhcp_relay_service: "disable" + dhcp_relay_type: "regular" + dhcp_renew_time: "38" + disc_retry_timeout: "39" + disconnect_threshold: "40" distance: "41" - dns-server-override: "enable" - drop-fragment: "enable" - drop-overlapped-fragment: "enable" - egress-shaping-profile: "" - endpoint-compliance: "enable" - estimated-downstream-bandwidth: "47" - estimated-upstream-bandwidth: "48" - explicit-ftp-proxy: "enable" - explicit-web-proxy: "enable" + dns_server_override: "enable" + drop_fragment: "enable" + drop_overlapped_fragment: "enable" + egress_shaping_profile: "" + endpoint_compliance: "enable" + estimated_downstream_bandwidth: "47" + estimated_upstream_bandwidth: "48" + explicit_ftp_proxy: "enable" + explicit_web_proxy: "enable" external: "enable" - fail-action-on-extender: "soft-restart" - fail-alert-interfaces: + fail_action_on_extender: "soft-restart" + fail_alert_interfaces: - name: "default_name_54 (source system.interface.name)" - fail-alert-method: "link-failed-signal" - fail-detect: "enable" - fail-detect-option: "detectserver" + fail_alert_method: "link-failed-signal" + fail_detect: "enable" + fail_detect_option: "detectserver" fortiheartbeat: "enable" fortilink: "enable" - fortilink-backup-link: "60" - fortilink-split-interface: "enable" - fortilink-stacking: "enable" - forward-domain: "63" + fortilink_backup_link: "60" + fortilink_split_interface: "enable" + fortilink_stacking: "enable" + forward_domain: "63" gwdetect: "enable" - ha-priority: "65" - icmp-accept-redirect: "enable" - icmp-send-redirect: "enable" - ident-accept: "enable" - idle-timeout: "69" + ha_priority: "65" + icmp_accept_redirect: "enable" + icmp_send_redirect: "enable" + ident_accept: "enable" + idle_timeout: "69" inbandwidth: "70" - ingress-spillover-threshold: "71" + ingress_spillover_threshold: "71" interface: " (source system.interface.name)" internal: "73" ip: "" ipmac: "enable" - ips-sniffer-mode: "enable" + ips_sniffer_mode: "enable" ipunnumbered: "" ipv6: autoconf: "enable" - dhcp6-client-options: "rapid" - dhcp6-information-request: "enable" - dhcp6-prefix-delegation: "enable" - dhcp6-prefix-hint: "" - dhcp6-prefix-hint-plt: "84" - dhcp6-prefix-hint-vlt: "85" - dhcp6-relay-ip: "" - dhcp6-relay-service: "disable" - dhcp6-relay-type: "regular" - ip6-address: "" - ip6-allowaccess: "ping" - ip6-default-life: "91" - ip6-delegated-prefix-list: + dhcp6_client_options: "rapid" + dhcp6_information_request: "enable" + dhcp6_prefix_delegation: "enable" + dhcp6_prefix_hint: "" + dhcp6_prefix_hint_plt: "84" + dhcp6_prefix_hint_vlt: "85" + dhcp6_relay_ip: "" + dhcp6_relay_service: "disable" + dhcp6_relay_type: "regular" + ip6_address: "" + ip6_allowaccess: "ping" + ip6_default_life: "91" + ip6_delegated_prefix_list: - - autonomous-flag: "enable" - onlink-flag: "enable" - prefix-id: "95" + autonomous_flag: "enable" + onlink_flag: "enable" + prefix_id: "95" rdnss: "" - rdnss-service: "delegated" + rdnss_service: "delegated" subnet: "" - upstream-interface: " (source system.interface.name)" - ip6-dns-server-override: "enable" - ip6-extra-addr: + upstream_interface: " (source system.interface.name)" + ip6_dns_server_override: "enable" + ip6_extra_addr: - prefix: "" - ip6-hop-limit: "103" - ip6-link-mtu: "104" - ip6-manage-flag: "enable" - ip6-max-interval: "106" - ip6-min-interval: "107" - ip6-mode: "static" - ip6-other-flag: "enable" - ip6-prefix-list: + ip6_hop_limit: "103" + ip6_link_mtu: "104" + ip6_manage_flag: "enable" + ip6_max_interval: "106" + ip6_min_interval: "107" + ip6_mode: "static" + ip6_other_flag: "enable" + ip6_prefix_list: - - autonomous-flag: "enable" + autonomous_flag: "enable" dnssl: - domain: "" - onlink-flag: "enable" - preferred-life-time: "115" + onlink_flag: "enable" + preferred_life_time: "115" prefix: "" rdnss: "" - valid-life-time: "118" - ip6-reachable-time: "119" - ip6-retrans-time: "120" - ip6-send-adv: "enable" - ip6-subnet: "" - ip6-upstream-interface: " (source system.interface.name)" - nd-cert: " (source certificate.local.name)" - nd-cga-modifier: "" - nd-mode: "basic" - nd-security-level: "127" - nd-timestamp-delta: "128" - nd-timestamp-fuzz: "129" + valid_life_time: "118" + ip6_reachable_time: "119" + ip6_retrans_time: "120" + ip6_send_adv: "enable" + ip6_subnet: "" + ip6_upstream_interface: " (source system.interface.name)" + nd_cert: " (source certificate.local.name)" + nd_cga_modifier: "" + nd_mode: "basic" + nd_security_level: "127" + nd_timestamp_delta: "128" + nd_timestamp_fuzz: "129" vrip6_link_local: "" - vrrp-virtual-mac6: "enable" + vrrp_virtual_mac6: "enable" vrrp6: - - accept-mode: "enable" - adv-interval: "134" + accept_mode: "enable" + adv_interval: "134" preempt: "enable" priority: "136" - start-time: "137" + start_time: "137" status: "enable" vrdst6: "" vrgrp: "140" vrid: "141" vrip6: "" l2forward: "enable" - lacp-ha-slave: "enable" - lacp-mode: "static" - lacp-speed: "slow" - lcp-echo-interval: "147" - lcp-max-echo-fails: "148" - link-up-delay: "149" - lldp-transmission: "enable" + lacp_ha_slave: "enable" + lacp_mode: "static" + lacp_speed: "slow" + lcp_echo_interval: "147" + lcp_max_echo_fails: "148" + link_up_delay: "149" + lldp_transmission: "enable" macaddr: "" - managed-device: + managed_device: - name: "default_name_153" - management-ip: "" + management_ip: "" member: - - interface-name: " (source system.interface.name)" - min-links: "157" - min-links-down: "operational" + interface_name: " (source system.interface.name)" + min_links: "157" + min_links_down: "operational" mode: "static" mtu: "160" - mtu-override: "enable" + mtu_override: "enable" name: "default_name_162" ndiscforward: "enable" - netbios-forward: "disable" - netflow-sampler: "disable" + netbios_forward: "disable" + netflow_sampler: "disable" outbandwidth: "166" - padt-retry-timeout: "167" + padt_retry_timeout: "167" password: "" - ping-serv-status: "169" - polling-interval: "170" - pppoe-unnumbered-negotiate: "enable" - pptp-auth-type: "auto" - pptp-client: "enable" - pptp-password: "" - pptp-server-ip: "" - pptp-timeout: "176" - pptp-user: "" - preserve-session-route: "enable" + ping_serv_status: "169" + polling_interval: "170" + pppoe_unnumbered_negotiate: "enable" + pptp_auth_type: "auto" + pptp_client: "enable" + pptp_password: "" + pptp_server_ip: "" + pptp_timeout: "176" + pptp_user: "" + preserve_session_route: "enable" priority: "179" - priority-override: "enable" - proxy-captive-portal: "enable" - redundant-interface: "" - remote-ip: "" - replacemsg-override-group: "" + priority_override: "enable" + proxy_captive_portal: "enable" + redundant_interface: "" + remote_ip: "" + replacemsg_override_group: "" role: "lan" - sample-direction: "tx" - sample-rate: "187" - scan-botnet-connections: "disable" - secondary-IP: "enable" + sample_direction: "tx" + sample_rate: "187" + scan_botnet_connections: "disable" + secondary_IP: "enable" secondaryip: - allowaccess: "ping" detectprotocol: "ping" detectserver: "" gwdetect: "enable" - ha-priority: "195" + ha_priority: "195" id: "196" ip: "" - ping-serv-status: "198" - security-exempt-list: "" - security-external-logout: "" - security-external-web: "" - security-groups: + ping_serv_status: "198" + security_exempt_list: "" + security_external_logout: "" + security_external_web: "" + security_groups: - name: "default_name_203" - security-mac-auth-bypass: "enable" - security-mode: "none" - security-redirect-url: "" - service-name: "" - sflow-sampler: "enable" - snmp-index: "209" + security_mac_auth_bypass: "enable" + security_mode: "none" + security_redirect_url: "" + service_name: "" + sflow_sampler: "enable" + snmp_index: "209" speed: "auto" - spillover-threshold: "211" - src-check: "enable" + spillover_threshold: "211" + src_check: "enable" status: "up" stpforward: "enable" - stpforward-mode: "rpl-all-ext-id" + stpforward_mode: "rpl-all-ext-id" subst: "enable" - substitute-dst-mac: "" + substitute_dst_mac: "" switch: "" - switch-controller-access-vlan: "enable" - switch-controller-arp-inspection: "enable" - switch-controller-dhcp-snooping: "enable" - switch-controller-dhcp-snooping-option82: "enable" - switch-controller-dhcp-snooping-verify-mac: "enable" - switch-controller-igmp-snooping: "enable" - switch-controller-learning-limit: "225" + switch_controller_access_vlan: "enable" + switch_controller_arp_inspection: "enable" + switch_controller_dhcp_snooping: "enable" + switch_controller_dhcp_snooping_option82: "enable" + switch_controller_dhcp_snooping_verify_mac: "enable" + switch_controller_igmp_snooping: "enable" + switch_controller_learning_limit: "225" tagging: - category: " (source system.object-tagging.category)" @@ -1549,13 +1827,13 @@ EXAMPLES = ''' tags: - name: "default_name_230 (source system.object-tagging.tags.name)" - tcp-mss: "231" - trust-ip-1: "" - trust-ip-2: "" - trust-ip-3: "" - trust-ip6-1: "" - trust-ip6-2: "" - trust-ip6-3: "" + tcp_mss: "231" + trust_ip_1: "" + trust_ip_2: "" + trust_ip_3: "" + trust_ip6_1: "" + trust_ip6_2: "" + trust_ip6_3: "" type: "physical" username: "" vdom: " (source system.vdom.name)" @@ -1565,26 +1843,27 @@ EXAMPLES = ''' vrf: "244" vrrp: - - accept-mode: "enable" - adv-interval: "247" + accept_mode: "enable" + adv_interval: "247" + ignore_default_route: "enable" preempt: "enable" - priority: "249" - proxy-arp: + priority: "250" + proxy_arp: - - id: "251" + id: "252" ip: "" - start-time: "253" + start_time: "254" status: "enable" version: "2" vrdst: "" - vrdst-priority: "257" - vrgrp: "258" - vrid: "259" + vrdst_priority: "258" + vrgrp: "259" + vrid: "260" vrip: "" - vrrp-virtual-mac: "enable" + vrrp_virtual_mac: "enable" wccp: "enable" - weight: "263" - wins-ip: "" + weight: "264" + wins_ip: "" ''' RETURN = ''' @@ -1647,14 +1926,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']: @@ -1662,66 +1943,66 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_interface_data(json): - option_list = ['ac-name', 'aggregate', 'algorithm', - 'alias', 'allowaccess', 'ap-discover', - 'arpforward', 'auth-type', 'auto-auth-extension-device', - 'bfd', 'bfd-desired-min-tx', 'bfd-detect-mult', - 'bfd-required-min-rx', 'broadcast-forticlient-discovery', 'broadcast-forward', - 'captive-portal', 'cli-conn-status', 'color', - 'dedicated-to', 'defaultgw', 'description', - 'detected-peer-mtu', 'detectprotocol', 'detectserver', - 'device-access-list', 'device-identification', 'device-identification-active-scan', - 'device-netscan', 'device-user-identification', 'devindex', - 'dhcp-client-identifier', 'dhcp-relay-agent-option', 'dhcp-relay-ip', - 'dhcp-relay-service', 'dhcp-relay-type', 'dhcp-renew-time', - 'disc-retry-timeout', 'disconnect-threshold', 'distance', - 'dns-server-override', 'drop-fragment', 'drop-overlapped-fragment', - 'egress-shaping-profile', 'endpoint-compliance', 'estimated-downstream-bandwidth', - 'estimated-upstream-bandwidth', 'explicit-ftp-proxy', 'explicit-web-proxy', - 'external', 'fail-action-on-extender', 'fail-alert-interfaces', - 'fail-alert-method', 'fail-detect', 'fail-detect-option', - 'fortiheartbeat', 'fortilink', 'fortilink-backup-link', - 'fortilink-split-interface', 'fortilink-stacking', 'forward-domain', - 'gwdetect', 'ha-priority', 'icmp-accept-redirect', - 'icmp-send-redirect', 'ident-accept', 'idle-timeout', - 'inbandwidth', 'ingress-spillover-threshold', 'interface', + option_list = ['ac_name', 'aggregate', 'algorithm', + 'alias', 'allowaccess', 'ap_discover', + 'arpforward', 'auth_type', 'auto_auth_extension_device', + 'bfd', 'bfd_desired_min_tx', 'bfd_detect_mult', + 'bfd_required_min_rx', 'broadcast_forticlient_discovery', 'broadcast_forward', + 'captive_portal', 'cli_conn_status', 'color', + 'dedicated_to', 'defaultgw', 'description', + 'detected_peer_mtu', 'detectprotocol', 'detectserver', + 'device_access_list', 'device_identification', 'device_identification_active_scan', + 'device_netscan', 'device_user_identification', 'devindex', + 'dhcp_client_identifier', 'dhcp_relay_agent_option', 'dhcp_relay_ip', + 'dhcp_relay_service', 'dhcp_relay_type', 'dhcp_renew_time', + 'disc_retry_timeout', 'disconnect_threshold', 'distance', + 'dns_server_override', 'drop_fragment', 'drop_overlapped_fragment', + 'egress_shaping_profile', 'endpoint_compliance', 'estimated_downstream_bandwidth', + 'estimated_upstream_bandwidth', 'explicit_ftp_proxy', 'explicit_web_proxy', + 'external', 'fail_action_on_extender', 'fail_alert_interfaces', + 'fail_alert_method', 'fail_detect', 'fail_detect_option', + 'fortiheartbeat', 'fortilink', 'fortilink_backup_link', + 'fortilink_split_interface', 'fortilink_stacking', 'forward_domain', + 'gwdetect', 'ha_priority', 'icmp_accept_redirect', + 'icmp_send_redirect', 'ident_accept', 'idle_timeout', + 'inbandwidth', 'ingress_spillover_threshold', 'interface', 'internal', 'ip', 'ipmac', - 'ips-sniffer-mode', 'ipunnumbered', 'ipv6', - 'l2forward', 'lacp-ha-slave', 'lacp-mode', - 'lacp-speed', 'lcp-echo-interval', 'lcp-max-echo-fails', - 'link-up-delay', 'lldp-transmission', 'macaddr', - 'managed-device', 'management-ip', 'member', - 'min-links', 'min-links-down', 'mode', - 'mtu', 'mtu-override', 'name', - 'ndiscforward', 'netbios-forward', 'netflow-sampler', - 'outbandwidth', 'padt-retry-timeout', 'password', - 'ping-serv-status', 'polling-interval', 'pppoe-unnumbered-negotiate', - 'pptp-auth-type', 'pptp-client', 'pptp-password', - 'pptp-server-ip', 'pptp-timeout', 'pptp-user', - 'preserve-session-route', 'priority', 'priority-override', - 'proxy-captive-portal', 'redundant-interface', 'remote-ip', - 'replacemsg-override-group', 'role', 'sample-direction', - 'sample-rate', 'scan-botnet-connections', 'secondary-IP', - 'secondaryip', 'security-exempt-list', 'security-external-logout', - 'security-external-web', 'security-groups', 'security-mac-auth-bypass', - 'security-mode', 'security-redirect-url', 'service-name', - 'sflow-sampler', 'snmp-index', 'speed', - 'spillover-threshold', 'src-check', 'status', - 'stpforward', 'stpforward-mode', 'subst', - 'substitute-dst-mac', 'switch', 'switch-controller-access-vlan', - 'switch-controller-arp-inspection', 'switch-controller-dhcp-snooping', 'switch-controller-dhcp-snooping-option82', - 'switch-controller-dhcp-snooping-verify-mac', 'switch-controller-igmp-snooping', 'switch-controller-learning-limit', - 'tagging', 'tcp-mss', 'trust-ip-1', - 'trust-ip-2', 'trust-ip-3', 'trust-ip6-1', - 'trust-ip6-2', 'trust-ip6-3', 'type', + 'ips_sniffer_mode', 'ipunnumbered', 'ipv6', + 'l2forward', 'lacp_ha_slave', 'lacp_mode', + 'lacp_speed', 'lcp_echo_interval', 'lcp_max_echo_fails', + 'link_up_delay', 'lldp_transmission', 'macaddr', + 'managed_device', 'management_ip', 'member', + 'min_links', 'min_links_down', 'mode', + 'mtu', 'mtu_override', 'name', + 'ndiscforward', 'netbios_forward', 'netflow_sampler', + 'outbandwidth', 'padt_retry_timeout', 'password', + 'ping_serv_status', 'polling_interval', 'pppoe_unnumbered_negotiate', + 'pptp_auth_type', 'pptp_client', 'pptp_password', + 'pptp_server_ip', 'pptp_timeout', 'pptp_user', + 'preserve_session_route', 'priority', 'priority_override', + 'proxy_captive_portal', 'redundant_interface', 'remote_ip', + 'replacemsg_override_group', 'role', 'sample_direction', + 'sample_rate', 'scan_botnet_connections', 'secondary_IP', + 'secondaryip', 'security_exempt_list', 'security_external_logout', + 'security_external_web', 'security_groups', 'security_mac_auth_bypass', + 'security_mode', 'security_redirect_url', 'service_name', + 'sflow_sampler', 'snmp_index', 'speed', + 'spillover_threshold', 'src_check', 'status', + 'stpforward', 'stpforward_mode', 'subst', + 'substitute_dst_mac', 'switch', 'switch_controller_access_vlan', + 'switch_controller_arp_inspection', 'switch_controller_dhcp_snooping', 'switch_controller_dhcp_snooping_option82', + 'switch_controller_dhcp_snooping_verify_mac', 'switch_controller_igmp_snooping', 'switch_controller_learning_limit', + 'tagging', 'tcp_mss', 'trust_ip_1', + 'trust_ip_2', 'trust_ip_3', 'trust_ip6_1', + 'trust_ip6_2', 'trust_ip6_3', 'type', 'username', 'vdom', 'vindex', 'vlanforward', 'vlanid', 'vrf', - 'vrrp', 'vrrp-virtual-mac', 'wccp', - 'weight', 'wins-ip'] + 'vrrp', 'vrrp_virtual_mac', 'wccp', + 'weight', 'wins_ip'] dictionary = {} for attribute in option_list: @@ -1732,7 +2013,7 @@ def filter_system_interface_data(json): def flatten_multilists_attributes(data): - multilist_attrs = [[u'allowaccess'], [u'ipv6', u'ip6-allowaccess']] + multilist_attrs = [[u'allowaccess'], [u'ipv6', u'ip6_allowaccess']] for attr in multilist_attrs: try: @@ -1746,47 +2027,68 @@ def flatten_multilists_attributes(data): return data +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 system_interface(data, fos): vdom = data['vdom'] + state = data['state'] system_interface_data = data['system_interface'] - flattened_data = flatten_multilists_attributes(system_interface_data) - filtered_data = filter_system_interface_data(flattened_data) - if system_interface_data['state'] == "present": + system_interface_data = flatten_multilists_attributes(system_interface_data) + filtered_data = underscore_to_hyphen(filter_system_interface_data(system_interface_data)) + + if state == "present": return fos.set('system', 'interface', data=filtered_data, vdom=vdom) - elif system_interface_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'interface', 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_system(data, fos): - login(data) if data['system_interface']: resp = system_interface(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_interface": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "ac-name": {"required": False, "type": "str"}, + "ac_name": {"required": False, "type": "str"}, "aggregate": {"required": False, "type": "str"}, "algorithm": {"required": False, "type": "str", "choices": ["L2", "L3", "L4"]}, @@ -1796,211 +2098,211 @@ def main(): "snmp", "http", "telnet", "fgfm", "radius-acct", "probe-response", "capwap", "ftm"]}, - "ap-discover": {"required": False, "type": "str", + "ap_discover": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "arpforward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "auth-type": {"required": False, "type": "str", + "auth_type": {"required": False, "type": "str", "choices": ["auto", "pap", "chap", "mschapv1", "mschapv2"]}, - "auto-auth-extension-device": {"required": False, "type": "str", + "auto_auth_extension_device": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "bfd": {"required": False, "type": "str", "choices": ["global", "enable", "disable"]}, - "bfd-desired-min-tx": {"required": False, "type": "int"}, - "bfd-detect-mult": {"required": False, "type": "int"}, - "bfd-required-min-rx": {"required": False, "type": "int"}, - "broadcast-forticlient-discovery": {"required": False, "type": "str", + "bfd_desired_min_tx": {"required": False, "type": "int"}, + "bfd_detect_mult": {"required": False, "type": "int"}, + "bfd_required_min_rx": {"required": False, "type": "int"}, + "broadcast_forticlient_discovery": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "broadcast-forward": {"required": False, "type": "str", + "broadcast_forward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "captive-portal": {"required": False, "type": "int"}, - "cli-conn-status": {"required": False, "type": "int"}, + "captive_portal": {"required": False, "type": "int"}, + "cli_conn_status": {"required": False, "type": "int"}, "color": {"required": False, "type": "int"}, - "dedicated-to": {"required": False, "type": "str", + "dedicated_to": {"required": False, "type": "str", "choices": ["none", "management"]}, "defaultgw": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "description": {"required": False, "type": "str"}, - "detected-peer-mtu": {"required": False, "type": "int"}, + "detected_peer_mtu": {"required": False, "type": "int"}, "detectprotocol": {"required": False, "type": "str", "choices": ["ping", "tcp-echo", "udp-echo"]}, "detectserver": {"required": False, "type": "str"}, - "device-access-list": {"required": False, "type": "str"}, - "device-identification": {"required": False, "type": "str", + "device_access_list": {"required": False, "type": "str"}, + "device_identification": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "device-identification-active-scan": {"required": False, "type": "str", + "device_identification_active_scan": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "device-netscan": {"required": False, "type": "str", + "device_netscan": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "device-user-identification": {"required": False, "type": "str", + "device_user_identification": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "devindex": {"required": False, "type": "int"}, - "dhcp-client-identifier": {"required": False, "type": "str"}, - "dhcp-relay-agent-option": {"required": False, "type": "str", + "dhcp_client_identifier": {"required": False, "type": "str"}, + "dhcp_relay_agent_option": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dhcp-relay-ip": {"required": False, "type": "str"}, - "dhcp-relay-service": {"required": False, "type": "str", + "dhcp_relay_ip": {"required": False, "type": "str"}, + "dhcp_relay_service": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "dhcp-relay-type": {"required": False, "type": "str", + "dhcp_relay_type": {"required": False, "type": "str", "choices": ["regular", "ipsec"]}, - "dhcp-renew-time": {"required": False, "type": "int"}, - "disc-retry-timeout": {"required": False, "type": "int"}, - "disconnect-threshold": {"required": False, "type": "int"}, + "dhcp_renew_time": {"required": False, "type": "int"}, + "disc_retry_timeout": {"required": False, "type": "int"}, + "disconnect_threshold": {"required": False, "type": "int"}, "distance": {"required": False, "type": "int"}, - "dns-server-override": {"required": False, "type": "str", + "dns_server_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "drop-fragment": {"required": False, "type": "str", + "drop_fragment": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "drop-overlapped-fragment": {"required": False, "type": "str", + "drop_overlapped_fragment": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "egress-shaping-profile": {"required": False, "type": "str"}, - "endpoint-compliance": {"required": False, "type": "str", + "egress_shaping_profile": {"required": False, "type": "str"}, + "endpoint_compliance": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "estimated-downstream-bandwidth": {"required": False, "type": "int"}, - "estimated-upstream-bandwidth": {"required": False, "type": "int"}, - "explicit-ftp-proxy": {"required": False, "type": "str", + "estimated_downstream_bandwidth": {"required": False, "type": "int"}, + "estimated_upstream_bandwidth": {"required": False, "type": "int"}, + "explicit_ftp_proxy": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "explicit-web-proxy": {"required": False, "type": "str", + "explicit_web_proxy": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "external": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fail-action-on-extender": {"required": False, "type": "str", + "fail_action_on_extender": {"required": False, "type": "str", "choices": ["soft-restart", "hard-restart", "reboot"]}, - "fail-alert-interfaces": {"required": False, "type": "list", + "fail_alert_interfaces": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "fail-alert-method": {"required": False, "type": "str", + "fail_alert_method": {"required": False, "type": "str", "choices": ["link-failed-signal", "link-down"]}, - "fail-detect": {"required": False, "type": "str", + "fail_detect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fail-detect-option": {"required": False, "type": "str", + "fail_detect_option": {"required": False, "type": "str", "choices": ["detectserver", "link-down"]}, "fortiheartbeat": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "fortilink": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fortilink-backup-link": {"required": False, "type": "int"}, - "fortilink-split-interface": {"required": False, "type": "str", + "fortilink_backup_link": {"required": False, "type": "int"}, + "fortilink_split_interface": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "fortilink-stacking": {"required": False, "type": "str", + "fortilink_stacking": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "forward-domain": {"required": False, "type": "int"}, + "forward_domain": {"required": False, "type": "int"}, "gwdetect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ha-priority": {"required": False, "type": "int"}, - "icmp-accept-redirect": {"required": False, "type": "str", + "ha_priority": {"required": False, "type": "int"}, + "icmp_accept_redirect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "icmp-send-redirect": {"required": False, "type": "str", + "icmp_send_redirect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ident-accept": {"required": False, "type": "str", + "ident_accept": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "idle-timeout": {"required": False, "type": "int"}, + "idle_timeout": {"required": False, "type": "int"}, "inbandwidth": {"required": False, "type": "int"}, - "ingress-spillover-threshold": {"required": False, "type": "int"}, + "ingress_spillover_threshold": {"required": False, "type": "int"}, "interface": {"required": False, "type": "str"}, "internal": {"required": False, "type": "int"}, "ip": {"required": False, "type": "str"}, "ipmac": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ips-sniffer-mode": {"required": False, "type": "str", + "ips_sniffer_mode": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "ipunnumbered": {"required": False, "type": "str"}, "ipv6": {"required": False, "type": "dict", "options": { "autoconf": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dhcp6-client-options": {"required": False, "type": "str", + "dhcp6_client_options": {"required": False, "type": "str", "choices": ["rapid", "iapd", "iana"]}, - "dhcp6-information-request": {"required": False, "type": "str", + "dhcp6_information_request": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dhcp6-prefix-delegation": {"required": False, "type": "str", + "dhcp6_prefix_delegation": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dhcp6-prefix-hint": {"required": False, "type": "str"}, - "dhcp6-prefix-hint-plt": {"required": False, "type": "int"}, - "dhcp6-prefix-hint-vlt": {"required": False, "type": "int"}, - "dhcp6-relay-ip": {"required": False, "type": "str"}, - "dhcp6-relay-service": {"required": False, "type": "str", + "dhcp6_prefix_hint": {"required": False, "type": "str"}, + "dhcp6_prefix_hint_plt": {"required": False, "type": "int"}, + "dhcp6_prefix_hint_vlt": {"required": False, "type": "int"}, + "dhcp6_relay_ip": {"required": False, "type": "str"}, + "dhcp6_relay_service": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "dhcp6-relay-type": {"required": False, "type": "str", + "dhcp6_relay_type": {"required": False, "type": "str", "choices": ["regular"]}, - "ip6-address": {"required": False, "type": "str"}, - "ip6-allowaccess": {"required": False, "type": "list", + "ip6_address": {"required": False, "type": "str"}, + "ip6_allowaccess": {"required": False, "type": "list", "choices": ["ping", "https", "ssh", "snmp", "http", "telnet", "fgfm", "capwap"]}, - "ip6-default-life": {"required": False, "type": "int"}, - "ip6-delegated-prefix-list": {"required": False, "type": "list", + "ip6_default_life": {"required": False, "type": "int"}, + "ip6_delegated_prefix_list": {"required": False, "type": "list", "options": { - "autonomous-flag": {"required": False, "type": "str", + "autonomous_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "onlink-flag": {"required": False, "type": "str", + "onlink_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "prefix-id": {"required": True, "type": "int"}, + "prefix_id": {"required": False, "type": "int"}, "rdnss": {"required": False, "type": "str"}, - "rdnss-service": {"required": False, "type": "str", + "rdnss_service": {"required": False, "type": "str", "choices": ["delegated", "default", "specify"]}, "subnet": {"required": False, "type": "str"}, - "upstream-interface": {"required": False, "type": "str"} + "upstream_interface": {"required": False, "type": "str"} }}, - "ip6-dns-server-override": {"required": False, "type": "str", + "ip6_dns_server_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ip6-extra-addr": {"required": False, "type": "list", + "ip6_extra_addr": {"required": False, "type": "list", "options": { "prefix": {"required": True, "type": "str"} }}, - "ip6-hop-limit": {"required": False, "type": "int"}, - "ip6-link-mtu": {"required": False, "type": "int"}, - "ip6-manage-flag": {"required": False, "type": "str", + "ip6_hop_limit": {"required": False, "type": "int"}, + "ip6_link_mtu": {"required": False, "type": "int"}, + "ip6_manage_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ip6-max-interval": {"required": False, "type": "int"}, - "ip6-min-interval": {"required": False, "type": "int"}, - "ip6-mode": {"required": False, "type": "str", + "ip6_max_interval": {"required": False, "type": "int"}, + "ip6_min_interval": {"required": False, "type": "int"}, + "ip6_mode": {"required": False, "type": "str", "choices": ["static", "dhcp", "pppoe", "delegated"]}, - "ip6-other-flag": {"required": False, "type": "str", + "ip6_other_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ip6-prefix-list": {"required": False, "type": "list", + "ip6_prefix_list": {"required": False, "type": "list", "options": { - "autonomous-flag": {"required": False, "type": "str", + "autonomous_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "dnssl": {"required": False, "type": "list", "options": { "domain": {"required": True, "type": "str"} }}, - "onlink-flag": {"required": False, "type": "str", + "onlink_flag": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "preferred-life-time": {"required": False, "type": "int"}, + "preferred_life_time": {"required": False, "type": "int"}, "prefix": {"required": True, "type": "str"}, "rdnss": {"required": False, "type": "str"}, - "valid-life-time": {"required": False, "type": "int"} + "valid_life_time": {"required": False, "type": "int"} }}, - "ip6-reachable-time": {"required": False, "type": "int"}, - "ip6-retrans-time": {"required": False, "type": "int"}, - "ip6-send-adv": {"required": False, "type": "str", + "ip6_reachable_time": {"required": False, "type": "int"}, + "ip6_retrans_time": {"required": False, "type": "int"}, + "ip6_send_adv": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ip6-subnet": {"required": False, "type": "str"}, - "ip6-upstream-interface": {"required": False, "type": "str"}, - "nd-cert": {"required": False, "type": "str"}, - "nd-cga-modifier": {"required": False, "type": "str"}, - "nd-mode": {"required": False, "type": "str", + "ip6_subnet": {"required": False, "type": "str"}, + "ip6_upstream_interface": {"required": False, "type": "str"}, + "nd_cert": {"required": False, "type": "str"}, + "nd_cga_modifier": {"required": False, "type": "str"}, + "nd_mode": {"required": False, "type": "str", "choices": ["basic", "SEND-compatible"]}, - "nd-security-level": {"required": False, "type": "int"}, - "nd-timestamp-delta": {"required": False, "type": "int"}, - "nd-timestamp-fuzz": {"required": False, "type": "int"}, + "nd_security_level": {"required": False, "type": "int"}, + "nd_timestamp_delta": {"required": False, "type": "int"}, + "nd_timestamp_fuzz": {"required": False, "type": "int"}, "vrip6_link_local": {"required": False, "type": "str"}, - "vrrp-virtual-mac6": {"required": False, "type": "str", + "vrrp_virtual_mac6": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "vrrp6": {"required": False, "type": "list", "options": { - "accept-mode": {"required": False, "type": "str", + "accept_mode": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "adv-interval": {"required": False, "type": "int"}, + "adv_interval": {"required": False, "type": "int"}, "preempt": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "priority": {"required": False, "type": "int"}, - "start-time": {"required": False, "type": "int"}, + "start_time": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "vrdst6": {"required": False, "type": "str"}, @@ -2011,78 +2313,78 @@ def main(): }}, "l2forward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "lacp-ha-slave": {"required": False, "type": "str", + "lacp_ha_slave": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "lacp-mode": {"required": False, "type": "str", + "lacp_mode": {"required": False, "type": "str", "choices": ["static", "passive", "active"]}, - "lacp-speed": {"required": False, "type": "str", + "lacp_speed": {"required": False, "type": "str", "choices": ["slow", "fast"]}, - "lcp-echo-interval": {"required": False, "type": "int"}, - "lcp-max-echo-fails": {"required": False, "type": "int"}, - "link-up-delay": {"required": False, "type": "int"}, - "lldp-transmission": {"required": False, "type": "str", + "lcp_echo_interval": {"required": False, "type": "int"}, + "lcp_max_echo_fails": {"required": False, "type": "int"}, + "link_up_delay": {"required": False, "type": "int"}, + "lldp_transmission": {"required": False, "type": "str", "choices": ["enable", "disable", "vdom"]}, "macaddr": {"required": False, "type": "str"}, - "managed-device": {"required": False, "type": "list", + "managed_device": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "management-ip": {"required": False, "type": "str"}, + "management_ip": {"required": False, "type": "str"}, "member": {"required": False, "type": "list", "options": { - "interface-name": {"required": True, "type": "str"} + "interface_name": {"required": False, "type": "str"} }}, - "min-links": {"required": False, "type": "int"}, - "min-links-down": {"required": False, "type": "str", + "min_links": {"required": False, "type": "int"}, + "min_links_down": {"required": False, "type": "str", "choices": ["operational", "administrative"]}, "mode": {"required": False, "type": "str", "choices": ["static", "dhcp", "pppoe"]}, "mtu": {"required": False, "type": "int"}, - "mtu-override": {"required": False, "type": "str", + "mtu_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "name": {"required": True, "type": "str"}, "ndiscforward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "netbios-forward": {"required": False, "type": "str", + "netbios_forward": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "netflow-sampler": {"required": False, "type": "str", + "netflow_sampler": {"required": False, "type": "str", "choices": ["disable", "tx", "rx", "both"]}, "outbandwidth": {"required": False, "type": "int"}, - "padt-retry-timeout": {"required": False, "type": "int"}, + "padt_retry_timeout": {"required": False, "type": "int"}, "password": {"required": False, "type": "str"}, - "ping-serv-status": {"required": False, "type": "int"}, - "polling-interval": {"required": False, "type": "int"}, - "pppoe-unnumbered-negotiate": {"required": False, "type": "str", + "ping_serv_status": {"required": False, "type": "int"}, + "polling_interval": {"required": False, "type": "int"}, + "pppoe_unnumbered_negotiate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "pptp-auth-type": {"required": False, "type": "str", + "pptp_auth_type": {"required": False, "type": "str", "choices": ["auto", "pap", "chap", "mschapv1", "mschapv2"]}, - "pptp-client": {"required": False, "type": "str", + "pptp_client": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "pptp-password": {"required": False, "type": "str"}, - "pptp-server-ip": {"required": False, "type": "str"}, - "pptp-timeout": {"required": False, "type": "int"}, - "pptp-user": {"required": False, "type": "str"}, - "preserve-session-route": {"required": False, "type": "str", + "pptp_password": {"required": False, "type": "str"}, + "pptp_server_ip": {"required": False, "type": "str"}, + "pptp_timeout": {"required": False, "type": "int"}, + "pptp_user": {"required": False, "type": "str"}, + "preserve_session_route": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "priority": {"required": False, "type": "int"}, - "priority-override": {"required": False, "type": "str", + "priority_override": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "proxy-captive-portal": {"required": False, "type": "str", + "proxy_captive_portal": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "redundant-interface": {"required": False, "type": "str"}, - "remote-ip": {"required": False, "type": "str"}, - "replacemsg-override-group": {"required": False, "type": "str"}, + "redundant_interface": {"required": False, "type": "str"}, + "remote_ip": {"required": False, "type": "str"}, + "replacemsg_override_group": {"required": False, "type": "str"}, "role": {"required": False, "type": "str", "choices": ["lan", "wan", "dmz", "undefined"]}, - "sample-direction": {"required": False, "type": "str", + "sample_direction": {"required": False, "type": "str", "choices": ["tx", "rx", "both"]}, - "sample-rate": {"required": False, "type": "int"}, - "scan-botnet-connections": {"required": False, "type": "str", + "sample_rate": {"required": False, "type": "int"}, + "scan_botnet_connections": {"required": False, "type": "str", "choices": ["disable", "block", "monitor"]}, - "secondary-IP": {"required": False, "type": "str", + "secondary_IP": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "secondaryip": {"required": False, "type": "list", "options": { @@ -2096,57 +2398,57 @@ def main(): "detectserver": {"required": False, "type": "str"}, "gwdetect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "ha-priority": {"required": False, "type": "int"}, + "ha_priority": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, "ip": {"required": False, "type": "str"}, - "ping-serv-status": {"required": False, "type": "int"} + "ping_serv_status": {"required": False, "type": "int"} }}, - "security-exempt-list": {"required": False, "type": "str"}, - "security-external-logout": {"required": False, "type": "str"}, - "security-external-web": {"required": False, "type": "str"}, - "security-groups": {"required": False, "type": "list", + "security_exempt_list": {"required": False, "type": "str"}, + "security_external_logout": {"required": False, "type": "str"}, + "security_external_web": {"required": False, "type": "str"}, + "security_groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "security-mac-auth-bypass": {"required": False, "type": "str", + "security_mac_auth_bypass": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "security-mode": {"required": False, "type": "str", + "security_mode": {"required": False, "type": "str", "choices": ["none", "captive-portal", "802.1X"]}, - "security-redirect-url": {"required": False, "type": "str"}, - "service-name": {"required": False, "type": "str"}, - "sflow-sampler": {"required": False, "type": "str", + "security_redirect_url": {"required": False, "type": "str"}, + "service_name": {"required": False, "type": "str"}, + "sflow_sampler": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "snmp-index": {"required": False, "type": "int"}, + "snmp_index": {"required": False, "type": "int"}, "speed": {"required": False, "type": "str", "choices": ["auto", "10full", "10half", "100full", "100half", "1000full", "1000half", "1000auto"]}, - "spillover-threshold": {"required": False, "type": "int"}, - "src-check": {"required": False, "type": "str", + "spillover_threshold": {"required": False, "type": "int"}, + "src_check": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "status": {"required": False, "type": "str", "choices": ["up", "down"]}, "stpforward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "stpforward-mode": {"required": False, "type": "str", + "stpforward_mode": {"required": False, "type": "str", "choices": ["rpl-all-ext-id", "rpl-bridge-ext-id", "rpl-nothing"]}, "subst": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "substitute-dst-mac": {"required": False, "type": "str"}, + "substitute_dst_mac": {"required": False, "type": "str"}, "switch": {"required": False, "type": "str"}, - "switch-controller-access-vlan": {"required": False, "type": "str", + "switch_controller_access_vlan": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-arp-inspection": {"required": False, "type": "str", + "switch_controller_arp_inspection": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-dhcp-snooping": {"required": False, "type": "str", + "switch_controller_dhcp_snooping": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-dhcp-snooping-option82": {"required": False, "type": "str", + "switch_controller_dhcp_snooping_option82": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-dhcp-snooping-verify-mac": {"required": False, "type": "str", + "switch_controller_dhcp_snooping_verify_mac": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-igmp-snooping": {"required": False, "type": "str", + "switch_controller_igmp_snooping": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "switch-controller-learning-limit": {"required": False, "type": "int"}, + "switch_controller_learning_limit": {"required": False, "type": "int"}, "tagging": {"required": False, "type": "list", "options": { "category": {"required": False, "type": "str"}, @@ -2156,13 +2458,13 @@ def main(): "name": {"required": True, "type": "str"} }} }}, - "tcp-mss": {"required": False, "type": "int"}, - "trust-ip-1": {"required": False, "type": "str"}, - "trust-ip-2": {"required": False, "type": "str"}, - "trust-ip-3": {"required": False, "type": "str"}, - "trust-ip6-1": {"required": False, "type": "str"}, - "trust-ip6-2": {"required": False, "type": "str"}, - "trust-ip6-3": {"required": False, "type": "str"}, + "tcp_mss": {"required": False, "type": "int"}, + "trust_ip_1": {"required": False, "type": "str"}, + "trust_ip_2": {"required": False, "type": "str"}, + "trust_ip_3": {"required": False, "type": "str"}, + "trust_ip6_1": {"required": False, "type": "str"}, + "trust_ip6_2": {"required": False, "type": "str"}, + "trust_ip6_3": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", "choices": ["physical", "vlan", "aggregate", "redundant", "tunnel", "vdom-link", @@ -2178,34 +2480,36 @@ def main(): "vrf": {"required": False, "type": "int"}, "vrrp": {"required": False, "type": "list", "options": { - "accept-mode": {"required": False, "type": "str", + "accept_mode": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "adv-interval": {"required": False, "type": "int"}, + "adv_interval": {"required": False, "type": "int"}, + "ignore_default_route": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, "preempt": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "priority": {"required": False, "type": "int"}, - "proxy-arp": {"required": False, "type": "list", + "proxy_arp": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, "ip": {"required": False, "type": "str"} }}, - "start-time": {"required": False, "type": "int"}, + "start_time": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "version": {"required": False, "type": "str", "choices": ["2", "3"]}, "vrdst": {"required": False, "type": "str"}, - "vrdst-priority": {"required": False, "type": "int"}, + "vrdst_priority": {"required": False, "type": "int"}, "vrgrp": {"required": False, "type": "int"}, "vrid": {"required": True, "type": "int"}, "vrip": {"required": False, "type": "str"} }}, - "vrrp-virtual-mac": {"required": False, "type": "str", + "vrrp_virtual_mac": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "wccp": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "weight": {"required": False, "type": "int"}, - "wins-ip": {"required": False, "type": "str"} + "wins_ip": {"required": False, "type": "str"} } } @@ -2213,15 +2517,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_sdn_connector.py b/lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py index a9bbbdfd400..5e5d75c3912 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py +++ b/lib/ansible/modules/network/fortios/fortios_system_sdn_connector.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_system_sdn_connector -short_description: Configure connection to SDN Connector. +short_description: Configure connection to SDN Connector in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by - allowing the user to configure system feature and sdn_connector category. - Examples includes all options and need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the + user to set and modify system feature and sdn_connector 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,106 +41,142 @@ 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 + required: true + choices: + - present + - absent + version_added: 2.9 system_sdn_connector: description: - Configure connection to SDN Connector. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent - access-key: + access_key: description: - AWS access key ID. - azure-region: + type: str + azure_region: description: - Azure server region. + type: str choices: - global - china - germany - usgov - client-id: + - local + client_id: description: - Azure client ID (application ID). - client-secret: + type: str + client_secret: description: - Azure client secret (application key). - compartment-id: + type: str + compartment_id: description: - Compartment ID. - external-ip: + type: str + external_ip: description: - Configure GCP external IP. + type: list suboptions: name: description: - External IP name. required: true - gcp-project: + type: str + gcp_project: description: - GCP project name. - key-passwd: + type: str + key_passwd: description: - Private key password. + type: str + login_endpoint: + description: + - Azure Stack login enpoint. + type: str name: description: - SDN connector name. required: true + type: str nic: description: - Configure Azure network interface. + type: list suboptions: ip: description: - Configure IP configuration. + type: list suboptions: name: description: - IP configuration name. required: true - public-ip: + type: str + public_ip: description: - Public IP name. + type: str name: description: - Network interface name. required: true - oci-cert: + type: str + oci_cert: description: - OCI certificate. Source certificate.local.name. - oci-fingerprint: + type: str + oci_fingerprint: description: - OCI pubkey fingerprint. - oci-region: + type: str + oci_region: description: - OCI server region. + type: str choices: - phoenix - ashburn @@ -152,95 +185,124 @@ options: password: description: - Password of the remote SDN connector as login credentials. - private-key: + type: str + private_key: description: - Private key of GCP service account. + type: str region: description: - AWS region name. - resource-group: + type: str + resource_group: description: - Azure resource group. + type: str + resource_url: + description: + - Azure Stack resource URL. + type: str route: description: - Configure GCP route. + type: list suboptions: name: description: - Route name. required: true - route-table: + type: str + route_table: description: - Configure Azure route table. + type: list suboptions: name: description: - Route table name. required: true + type: str route: description: - Configure Azure route. + type: list suboptions: name: description: - Route name. required: true - next-hop: + type: str + next_hop: description: - Next hop address. - secret-key: + type: str + secret_key: description: - AWS secret access key. + type: str server: description: - Server address of the remote SDN connector. - server-port: + type: str + server_port: description: - Port number of the remote SDN connector. - service-account: + type: int + service_account: description: - GCP service account email. + type: str status: description: - Enable/disable connection to the remote SDN connector. + type: str choices: - disable - enable - subscription-id: + subscription_id: description: - Azure subscription ID. - tenant-id: + type: str + tenant_id: description: - Tenant ID (directory ID). + type: str type: description: - Type of SDN connector. + type: str choices: - aci - aws - azure + - gcp - nsx - nuage - oci - - gcp - update-interval: + - openstack + update_interval: description: - - Dynamic object update interval (0 - 3600 sec, 0 means disabled, default = 60). - use-metadata-iam: + - Dynamic object update interval (0 - 3600 sec, 0 means disabled). + type: int + use_metadata_iam: description: - Enable/disable using IAM role from metadata to call API. + type: str choices: - disable - enable - user-id: + user_id: description: - User ID. + type: str username: description: - Username of the remote SDN connector as login credentials. - vpc-id: + type: str + vpc_id: description: - AWS VPC ID. + type: str ''' EXAMPLES = ''' @@ -250,63 +312,67 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure connection to SDN Connector. fortios_system_sdn_connector: - host: "{{ host }}" + host: "{{ host }}" username: "{{ username }}" password: "{{ password }}" - vdom: "{{ vdom }}" + vdom: "{{ vdom }}" + https: "False" + state: "present" system_sdn_connector: - state: "present" - access-key: "" - azure-region: "global" - client-id: "" - client-secret: "" - compartment-id: "" - external-ip: + access_key: "" + azure_region: "global" + client_id: "" + client_secret: "" + compartment_id: "" + external_ip: - name: "default_name_9" - gcp-project: "" - key-passwd: "" - name: "default_name_12" + gcp_project: "" + key_passwd: "" + login_endpoint: "" + name: "default_name_13" nic: - ip: - - name: "default_name_15" - public-ip: "" - name: "default_name_17" - oci-cert: " (source certificate.local.name)" - oci-fingerprint: "" - oci-region: "phoenix" + name: "default_name_16" + public_ip: "" + name: "default_name_18" + oci_cert: " (source certificate.local.name)" + oci_fingerprint: "" + oci_region: "phoenix" password: "" - private-key: "" + private_key: "" region: "" - resource-group: "" + resource_group: "" + resource_url: "" route: - - - name: "default_name_26" - route-table: - name: "default_name_28" + route_table: + - + name: "default_name_30" route: - - name: "default_name_30" - next-hop: "" - secret-key: "" + name: "default_name_32" + next_hop: "" + secret_key: "" server: "192.168.100.40" - server-port: "34" - service-account: "" + server_port: "36" + service_account: "" status: "disable" - subscription-id: "" - tenant-id: "" + subscription_id: "" + tenant_id: "" type: "aci" - update-interval: "40" - use-metadata-iam: "disable" - user-id: "" + update_interval: "42" + use_metadata_iam: "disable" + user_id: "" username: "" - vpc-id: "" + vpc_id: "" ''' RETURN = ''' @@ -329,7 +395,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 @@ -369,14 +435,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']: @@ -384,135 +452,156 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_sdn_connector_data(json): - option_list = ['access-key', 'azure-region', 'client-id', - 'client-secret', 'compartment-id', 'external-ip', - 'gcp-project', 'key-passwd', 'name', - 'nic', 'oci-cert', 'oci-fingerprint', - 'oci-region', 'password', 'private-key', - 'region', 'resource-group', 'route', - 'route-table', 'secret-key', 'server', - 'server-port', 'service-account', 'status', - 'subscription-id', 'tenant-id', 'type', - 'update-interval', 'use-metadata-iam', 'user-id', - 'username', 'vpc-id'] + option_list = ['access_key', 'azure_region', 'client_id', + 'client_secret', 'compartment_id', 'external_ip', + 'gcp_project', 'key_passwd', 'login_endpoint', + 'name', 'nic', 'oci_cert', + 'oci_fingerprint', 'oci_region', 'password', + 'private_key', 'region', 'resource_group', + 'resource_url', 'route', 'route_table', + 'secret_key', 'server', 'server_port', + 'service_account', 'status', 'subscription_id', + 'tenant_id', 'type', 'update_interval', + 'use_metadata_iam', 'user_id', 'username', + 'vpc_id'] 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 system_sdn_connector(data, fos): vdom = data['vdom'] + state = data['state'] system_sdn_connector_data = data['system_sdn_connector'] - filtered_data = filter_system_sdn_connector_data(system_sdn_connector_data) - if system_sdn_connector_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_sdn_connector_data(system_sdn_connector_data)) + + if state == "present": return fos.set('system', 'sdn-connector', data=filtered_data, vdom=vdom) - elif system_sdn_connector_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'sdn-connector', 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_system(data, fos): - login(data) - methodlist = ['system_sdn_connector'] - for method in methodlist: - if data[method]: - resp = eval(method)(data, fos) - break + if data['system_sdn_connector']: + resp = system_sdn_connector(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, - "https": {"required": False, "type": "bool", "default": "False"}, + "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_sdn_connector": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, - "access-key": {"required": False, "type": "str"}, - "azure-region": {"required": False, "type": "str", + "access_key": {"required": False, "type": "str"}, + "azure_region": {"required": False, "type": "str", "choices": ["global", "china", "germany", - "usgov"]}, - "client-id": {"required": False, "type": "str"}, - "client-secret": {"required": False, "type": "str"}, - "compartment-id": {"required": False, "type": "str"}, - "external-ip": {"required": False, "type": "list", + "usgov", "local"]}, + "client_id": {"required": False, "type": "str"}, + "client_secret": {"required": False, "type": "str"}, + "compartment_id": {"required": False, "type": "str"}, + "external_ip": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "gcp-project": {"required": False, "type": "str"}, - "key-passwd": {"required": False, "type": "str"}, + "gcp_project": {"required": False, "type": "str"}, + "key_passwd": {"required": False, "type": "str"}, + "login_endpoint": {"required": False, "type": "str"}, "name": {"required": True, "type": "str"}, "nic": {"required": False, "type": "list", "options": { "ip": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"}, - "public-ip": {"required": False, "type": "str"} + "public_ip": {"required": False, "type": "str"} }}, "name": {"required": True, "type": "str"} }}, - "oci-cert": {"required": False, "type": "str"}, - "oci-fingerprint": {"required": False, "type": "str"}, - "oci-region": {"required": False, "type": "str", + "oci_cert": {"required": False, "type": "str"}, + "oci_fingerprint": {"required": False, "type": "str"}, + "oci_region": {"required": False, "type": "str", "choices": ["phoenix", "ashburn", "frankfurt", "london"]}, "password": {"required": False, "type": "str"}, - "private-key": {"required": False, "type": "str"}, + "private_key": {"required": False, "type": "str"}, "region": {"required": False, "type": "str"}, - "resource-group": {"required": False, "type": "str"}, + "resource_group": {"required": False, "type": "str"}, + "resource_url": {"required": False, "type": "str"}, "route": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "route-table": {"required": False, "type": "list", + "route_table": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"}, "route": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"}, - "next-hop": {"required": False, "type": "str"} + "next_hop": {"required": False, "type": "str"} }} }}, - "secret-key": {"required": False, "type": "str"}, + "secret_key": {"required": False, "type": "str"}, "server": {"required": False, "type": "str"}, - "server-port": {"required": False, "type": "int"}, - "service-account": {"required": False, "type": "str"}, + "server_port": {"required": False, "type": "int"}, + "service_account": {"required": False, "type": "str"}, "status": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "subscription-id": {"required": False, "type": "str"}, - "tenant-id": {"required": False, "type": "str"}, + "subscription_id": {"required": False, "type": "str"}, + "tenant_id": {"required": False, "type": "str"}, "type": {"required": False, "type": "str", "choices": ["aci", "aws", "azure", - "nsx", "nuage", "oci", - "gcp"]}, - "update-interval": {"required": False, "type": "int"}, - "use-metadata-iam": {"required": False, "type": "str", + "gcp", "nsx", "nuage", + "oci", "openstack"]}, + "update_interval": {"required": False, "type": "int"}, + "use_metadata_iam": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "user-id": {"required": False, "type": "str"}, + "user_id": {"required": False, "type": "str"}, "username": {"required": False, "type": "str"}, - "vpc-id": {"required": False, "type": "str"} + "vpc_id": {"required": False, "type": "str"} } } @@ -520,15 +609,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_settings.py b/lib/ansible/modules/network/fortios/fortios_system_settings.py index c79b8818516..4c26c149b87 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_settings.py +++ b/lib/ansible/modules/network/fortios/fortios_system_settings.py @@ -130,11 +130,11 @@ options: - disable bfd_desired_min_tx: description: - - BFD desired minimal transmit interval (1 - 100000 ms, default = 50). + - BFD desired minimal transmit interval (1 - 100000 ms). type: int bfd_detect_mult: description: - - BFD detection multiplier (1 - 50, default = 3). + - BFD detection multiplier (1 - 50). type: int bfd_dont_enforce_src_port: description: @@ -145,7 +145,7 @@ options: - disable bfd_required_min_rx: description: - - BFD required minimal receive interval (1 - 100000 ms, default = 50). + - BFD required minimal receive interval (1 - 100000 ms). type: int block_land_attack: description: @@ -207,11 +207,11 @@ options: type: str discovered_device_timeout: description: - - Timeout for discovered devices (1 - 365 days, default = 28). + - Timeout for discovered devices (1 - 365 days). type: int ecmp_max_paths: description: - - Maximum number of Equal Cost Multi-Path (ECMP) next-hops. Set to 1 to disable ECMP routing (1 - 100, default = 10). + - Maximum number of Equal Cost Multi-Path (ECMP) next-hops. Set to 1 to disable ECMP routing (1 - 100). type: int email_portal_check_dns: description: @@ -649,7 +649,7 @@ options: - global mac_ttl: description: - - Duration of MAC addresses in Transparent mode (300 - 8640000 sec, default = 300). + - Duration of MAC addresses in Transparent mode (300 - 8640000 sec). type: int manageip: description: @@ -703,7 +703,7 @@ options: - disable sccp_port: description: - - TCP port the SCCP proxy monitors for SCCP traffic (0 - 65535, default = 2000). + - TCP port the SCCP proxy monitors for SCCP traffic (0 - 65535). type: int ses_denied_traffic: description: @@ -729,15 +729,15 @@ options: - disable sip_ssl_port: description: - - TCP port the SIP proxy monitors for SIP SSL/TLS traffic (0 - 65535, default = 5061). + - TCP port the SIP proxy monitors for SIP SSL/TLS traffic (0 - 65535). type: int sip_tcp_port: description: - - TCP port the SIP proxy monitors for SIP traffic (0 - 65535, default = 5060). + - TCP port the SIP proxy monitors for SIP traffic (0 - 65535). type: int sip_udp_port: description: - - UDP port the SIP proxy monitors for SIP traffic (0 - 65535, default = 5060). + - UDP port the SIP proxy monitors for SIP traffic (0 - 65535). type: int snat_hairpin_traffic: description: diff --git a/lib/ansible/modules/network/fortios/fortios_system_vdom.py b/lib/ansible/modules/network/fortios/fortios_system_vdom.py index c4ccf53f201..8c411097bf7 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_vdom.py +++ b/lib/ansible/modules/network/fortios/fortios_system_vdom.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_system_vdom short_description: Configure virtual domain in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and vdom category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -44,53 +41,70 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 + state: + description: + - Indicates whether to create or remove the object. + type: str + required: true + choices: + - present + - absent + version_added: 2.9 system_vdom: description: - Configure virtual domain. default: null + type: dict suboptions: - state: - description: - - Indicates whether to create or remove the object - choices: - - present - - absent name: description: - VDOM name. required: true - short-name: + type: str + short_name: description: - VDOM short name. + type: str temporary: description: - Temporary. - vcluster-id: + type: int + vcluster_id: description: - Virtual cluster ID (0 - 4294967295). + type: int ''' EXAMPLES = ''' @@ -100,6 +114,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure virtual domain. fortios_system_vdom: @@ -108,12 +123,12 @@ EXAMPLES = ''' password: "{{ password }}" vdom: "{{ vdom }}" https: "False" + state: "present" system_vdom: - state: "present" name: "default_name_3" - short-name: "" + short_name: "" temporary: "5" - vcluster-id: "6" + vcluster_id: "6" ''' RETURN = ''' @@ -176,14 +191,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']: @@ -191,12 +208,12 @@ def login(data): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_vdom_data(json): - option_list = ['name', 'short-name', 'temporary', - 'vcluster-id'] + option_list = ['name', 'short_name', 'temporary', + 'vcluster_id'] dictionary = {} for attribute in option_list: @@ -206,65 +223,70 @@ def filter_system_vdom_data(json): return dictionary -def flatten_multilists_attributes(data): - multilist_attrs = [] - - for attr in multilist_attrs: - try: - path = "data['" + "']['".join(elem for elem in attr) + "']" - current_val = eval(path) - flattened_val = ' '.join(elem for elem in current_val) - exec(path + '= flattened_val') - except BaseException: - pass +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 system_vdom(data, fos): vdom = data['vdom'] + state = data['state'] system_vdom_data = data['system_vdom'] - flattened_data = flatten_multilists_attributes(system_vdom_data) - filtered_data = filter_system_vdom_data(flattened_data) - if system_vdom_data['state'] == "present": + filtered_data = underscore_to_hyphen(filter_system_vdom_data(system_vdom_data)) + + if state == "present": return fos.set('system', 'vdom', data=filtered_data, vdom=vdom) - elif system_vdom_data['state'] == "absent": + elif state == "absent": return fos.delete('system', 'vdom', 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_system(data, fos): - login(data) if data['system_vdom']: resp = system_vdom(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, + "state": {"required": True, "type": "str", + "choices": ["present", "absent"]}, "system_vdom": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "state": {"required": True, "type": "str", - "choices": ["present", "absent"]}, "name": {"required": True, "type": "str"}, - "short-name": {"required": False, "type": "str"}, + "short_name": {"required": False, "type": "str"}, "temporary": {"required": False, "type": "int"}, - "vcluster-id": {"required": False, "type": "int"} + "vcluster_id": {"required": False, "type": "int"} } } @@ -272,15 +294,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - global fos - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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_system_virtual_wan_link.py b/lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py index 7ececdaa36d..6a3b1a32621 100644 --- a/lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py +++ b/lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py @@ -26,10 +26,10 @@ DOCUMENTATION = ''' module: fortios_system_virtual_wan_link short_description: Configure redundant internet connections using SD-WAN (formerly virtual WAN link) in Fortinet's FortiOS and FortiGate. description: - - This module is able to configure a FortiGate or FortiOS by allowing the + - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the user to set and modify system feature and virtual_wan_link category. Examples include all parameters and values need to be adjusted to datasources before usage. - Tested with FOS v6.0.2 + Tested with FOS v6.0.5 version_added: "2.8" author: - Miguel Angel Munoz (@mamunozgonzalez) @@ -41,95 +41,124 @@ requirements: - fortiosapi>=0.9.8 options: host: - description: - - FortiOS or FortiGate ip address. - required: true + description: + - FortiOS or FortiGate IP address. + type: str + required: false username: description: - FortiOS or FortiGate username. - required: true + type: str + required: false password: description: - FortiOS or FortiGate password. + type: str default: "" vdom: description: - Virtual domain, among those defined previously. A vdom is a virtual instance of the FortiGate that can be configured and used as a different unit. + type: str default: root https: description: - - Indicates if the requests towards FortiGate must use HTTPS - protocol + - Indicates if the requests towards FortiGate must use HTTPS protocol. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. type: bool default: true + version_added: 2.9 system_virtual_wan_link: description: - Configure redundant internet connections using SD-WAN (formerly virtual WAN link). default: null + type: dict suboptions: - fail-alert-interfaces: + fail_alert_interfaces: description: - Physical interfaces that will be alerted. + type: list suboptions: name: description: - Physical interface name. Source system.interface.name. required: true - fail-detect: + type: str + fail_detect: description: - Enable/disable SD-WAN Internet connection status checking (failure detection). + type: str choices: - enable - disable - health-check: + health_check: description: - SD-WAN status checking or health checking. Identify a server on the Internet and determine how SD-WAN verifies that the FortiGate can communicate with it. + type: list suboptions: - addr-mode: + addr_mode: description: - Address mode (IPv4 or IPv6). + type: str choices: - ipv4 - ipv6 failtime: description: - - Number of failures before server is considered lost (1 - 10, default = 5). - http-get: + - Number of failures before server is considered lost (1 - 3600). + type: int + http_agent: + description: + - String in the http-agent field in the HTTP header. + type: str + http_get: description: - URL used to communicate with the server if the protocol if the protocol is HTTP. - http-match: + type: str + http_match: description: - Response string expected from the server if the protocol is HTTP. + type: str interval: description: - - Status check interval, or the time between attempting to connect to the server (1 - 3600 sec, default = 5). + - Status check interval, or the time between attempting to connect to the server (1 - 3600 sec). + type: int members: description: - Member sequence number list. + type: list suboptions: - seq-num: + seq_num: description: - Member sequence number. Source system.virtual-wan-link.members.seq-num. - required: true + type: int name: description: - Status check or health check name. required: true - packet-size: + type: str + packet_size: description: - Packet size of a twamp test session, + type: int password: description: - Twamp controller password in authentication mode + type: str port: description: - Port number used to communicate with the server over the selected protocol. + type: int protocol: description: - Protocol used to determine if the FortiGate can communicate with the server. + type: str choices: - ping - tcp-echo @@ -139,73 +168,91 @@ options: - ping6 recoverytime: description: - - Number of successful responses received before server is considered recovered (1 - 10, default = 5). - security-mode: + - Number of successful responses received before server is considered recovered (1 - 3600). + type: int + security_mode: description: - Twamp controller security mode. + type: str choices: - none - authentication server: description: - IP address or FQDN name of the server. + type: str sla: description: - Service level agreement (SLA). + type: list suboptions: id: description: - SLA ID. required: true - jitter-threshold: + type: int + jitter_threshold: description: - - Jitter for SLA to make decision in milliseconds. (0 - 10000000, default = 5). - latency-threshold: + - Jitter for SLA to make decision in milliseconds. (0 - 10000000). + type: int + latency_threshold: description: - - Latency for SLA to make decision in milliseconds. (0 - 10000000, default = 5). - link-cost-factor: + - Latency for SLA to make decision in milliseconds. (0 - 10000000). + type: int + link_cost_factor: description: - Criteria on which to base link selection. + type: str choices: - latency - jitter - packet-loss - packetloss-threshold: + packetloss_threshold: description: - - Packet loss for SLA to make decision in percentage. (0 - 100, default = 0). - threshold-alert-jitter: + - Packet loss for SLA to make decision in percentage. (0 - 100). + type: int + threshold_alert_jitter: description: - - Alert threshold for jitter (ms, default = 0). - threshold-alert-latency: + - Alert threshold for jitter (ms). + type: int + threshold_alert_latency: description: - - Alert threshold for latency (ms, default = 0). - threshold-alert-packetloss: + - Alert threshold for latency (ms). + type: int + threshold_alert_packetloss: description: - - Alert threshold for packet loss (percentage, default = 0). - threshold-warning-jitter: + - Alert threshold for packet loss (percentage). + type: int + threshold_warning_jitter: description: - - Warning threshold for jitter (ms, default = 0). - threshold-warning-latency: + - Warning threshold for jitter (ms). + type: int + threshold_warning_latency: description: - - Warning threshold for latency (ms, default = 0). - threshold-warning-packetloss: + - Warning threshold for latency (ms). + type: int + threshold_warning_packetloss: description: - - Warning threshold for packet loss (percentage, default = 0). - update-cascade-interface: + - Warning threshold for packet loss (percentage). + type: int + update_cascade_interface: description: - Enable/disable update cascade interface. + type: str choices: - enable - disable - update-static-route: + update_static_route: description: - Enable/disable updating the static route. + type: str choices: - enable - disable - load-balance-mode: + load_balance_mode: description: - Algorithm or mode to use for load balancing Internet traffic to SD-WAN members. + type: str choices: - source-ip-based - weight-based @@ -215,205 +262,262 @@ options: members: description: - Physical FortiGate interfaces added to the virtual-wan-link. + type: list suboptions: comment: description: - Comments. + type: str gateway: description: - The default gateway for this interface. Usually the default gateway of the Internet service provider that this interface is connected to. + type: str gateway6: description: - IPv6 gateway. - ingress-spillover-threshold: + type: str + ingress_spillover_threshold: description: - Ingress spillover threshold for this interface (0 - 16776000 kbit/s). When this traffic volume threshold is reached, new sessions spill over to other interfaces in the SD-WAN. + type: int interface: description: - Interface name. Source system.interface.name. + type: str priority: description: - Priority of the interface (0 - 4294967295). Used for SD-WAN rules or priority rules. - seq-num: + type: int + seq_num: description: - Sequence number(1-255). - required: true + type: int source: description: - Source IP address used in the health-check packet to the server. + type: str source6: description: - Source IPv6 address used in the health-check packet to the server. - spillover-threshold: + type: str + spillover_threshold: description: - Egress spillover threshold for this interface (0 - 16776000 kbit/s). When this traffic volume threshold is reached, new sessions spill over to other interfaces in the SD-WAN. + type: int status: description: - Enable/disable this interface in the SD-WAN. + type: str choices: - disable - enable - volume-ratio: + volume_ratio: description: - Measured volume ratio (this value / sum of all values = percentage of link volume, 0 - 255). + type: int weight: description: - Weight of this interface for weighted load balancing. (0 - 255) More traffic is directed to interfaces with higher weights. + type: int service: description: - Create SD-WAN rules or priority rules (also called services) to control how sessions are distributed to physical interfaces in the SD-WAN. + type: list suboptions: - addr-mode: + addr_mode: description: - Address mode (IPv4 or IPv6). + type: str choices: - ipv4 - ipv6 - bandwidth-weight: + bandwidth_weight: description: - Coefficient of reciprocal of available bidirectional bandwidth in the formula of custom-profile-1. - dscp-forward: + type: int + default: + description: + - Enable/disable use of SD-WAN as default service. + type: str + choices: + - enable + - disable + dscp_forward: description: - Enable/disable forward traffic DSCP tag. + type: str choices: - enable - disable - dscp-forward-tag: + dscp_forward_tag: description: - Forward traffic DSCP tag. - dscp-reverse: + type: str + dscp_reverse: description: - Enable/disable reverse traffic DSCP tag. + type: str choices: - enable - disable - dscp-reverse-tag: + dscp_reverse_tag: description: - Reverse traffic DSCP tag. + type: str dst: description: - Destination address name. + type: list suboptions: name: description: - Address or address group name. Source firewall.address.name firewall.addrgrp.name. required: true - dst-negate: + type: str + dst_negate: description: - Enable/disable negation of destination address match. + type: str choices: - enable - disable dst6: description: - Destination address6 name. + type: list suboptions: name: description: - Address6 or address6 group name. Source firewall.address6.name firewall.addrgrp6.name. required: true - end-port: + type: str + end_port: description: - End destination port number. + type: int gateway: description: - Enable/disable SD-WAN service gateway. + type: str choices: - enable - disable groups: description: - User groups. + type: list suboptions: name: description: - Group name. Source user.group.name. required: true - health-check: + type: str + health_check: description: - Health check. Source system.virtual-wan-link.health-check.name. - hold-down-time: + type: str + hold_down_time: description: - - Waiting period in seconds when switching from the back-up member to the primary member (0 - 10000000, default = 0). + - Waiting period in seconds when switching from the back-up member to the primary member (0 - 10000000). + type: int id: description: - Priority rule ID (1 - 4000). required: true - input-device: + type: int + input_device: description: - Source interface name. + type: list suboptions: name: description: - Interface name. Source system.interface.name. required: true - internet-service: + type: str + internet_service: description: - Enable/disable use of Internet service for application-based load balancing. + type: str choices: - enable - disable - internet-service-ctrl: + internet_service_ctrl: description: - Control-based Internet Service ID list. + type: list suboptions: id: description: - Control-based Internet Service ID. required: true - internet-service-ctrl-group: + type: int + internet_service_ctrl_group: description: - Control-based Internet Service group list. + type: list suboptions: name: description: - Control-based Internet Service group name. Source application.group.name. required: true - internet-service-custom: + type: str + internet_service_custom: description: - Custom Internet service name list. + type: list suboptions: name: description: - Custom Internet service name. Source firewall.internet-service-custom.name. required: true - internet-service-custom-group: + type: str + internet_service_custom_group: description: - Custom Internet Service group list. + type: list suboptions: name: description: - Custom Internet Service group name. Source firewall.internet-service-custom-group.name. required: true - internet-service-group: + type: str + internet_service_group: description: - Internet Service group list. + type: list suboptions: name: description: - Internet Service group name. Source firewall.internet-service-group.name. required: true - internet-service-id: + type: str + internet_service_id: description: - Internet service ID list. + type: list suboptions: id: description: - Internet service ID. Source firewall.internet-service.id. required: true - jitter-weight: + type: int + jitter_weight: description: - Coefficient of jitter in the formula of custom-profile-1. - latency-weight: + type: int + latency_weight: description: - Coefficient of latency in the formula of custom-profile-1. - link-cost-factor: + type: int + link_cost_factor: description: - Link cost factor. + type: str choices: - latency - jitter @@ -422,15 +526,18 @@ options: - outbandwidth - bibandwidth - custom-profile-1 - link-cost-threshold: + link_cost_threshold: description: - - Percentage threshold change of link cost values that will result in policy route regeneration (0 - 10000000, default = 10). + - Percentage threshold change of link cost values that will result in policy route regeneration (0 - 10000000). + type: int member: description: - Member sequence number. + type: int mode: description: - Control how the priority rule sets the priority of interfaces in the SD-WAN. + type: str choices: - auto - manual @@ -439,85 +546,105 @@ options: name: description: - Priority rule name. - packet-loss-weight: + type: str + packet_loss_weight: description: - Coefficient of packet-loss in the formula of custom-profile-1. - priority-members: + type: int + priority_members: description: - Member sequence number list. + type: list suboptions: - seq-num: + seq_num: description: - Member sequence number. Source system.virtual-wan-link.members.seq-num. - required: true + type: int protocol: description: - Protocol number. - quality-link: + type: int + quality_link: description: - Quality grade. - route-tag: + type: int + route_tag: description: - IPv4 route map route-tag. + type: int sla: description: - Service level agreement (SLA). + type: list suboptions: - health-check: + health_check: description: - Virtual WAN Link health-check. Source system.virtual-wan-link.health-check.name. - required: true + type: str id: description: - SLA ID. + type: int src: description: - Source address name. + type: list suboptions: name: description: - Address or address group name. Source firewall.address.name firewall.addrgrp.name. required: true - src-negate: + type: str + src_negate: description: - Enable/disable negation of source address match. + type: str choices: - enable - disable src6: description: - Source address6 name. + type: list suboptions: name: description: - Address6 or address6 group name. Source firewall.address6.name firewall.addrgrp6.name. required: true - start-port: + type: str + start_port: description: - Start destination port number. + type: int status: description: - Enable/disable SD-WAN service. + type: str choices: - enable - disable tos: description: - Type of service bit pattern. - tos-mask: + type: str + tos_mask: description: - Type of service evaluated bits. + type: str users: description: - User name. + type: list suboptions: name: description: - User name. Source user.local.name. required: true + type: str status: description: - Enable/disable SD-WAN. + type: str choices: - disable - enable @@ -530,6 +657,7 @@ EXAMPLES = ''' username: "admin" password: "" vdom: "root" + ssl_verify: "False" tasks: - name: Configure redundant internet connections using SD-WAN (formerly virtual WAN link). fortios_system_virtual_wan_link: @@ -539,136 +667,138 @@ EXAMPLES = ''' vdom: "{{ vdom }}" https: "False" system_virtual_wan_link: - fail-alert-interfaces: + fail_alert_interfaces: - name: "default_name_4 (source system.interface.name)" - fail-detect: "enable" - health-check: + fail_detect: "enable" + health_check: - - addr-mode: "ipv4" + addr_mode: "ipv4" failtime: "8" - http-get: "" - http-match: "" - interval: "11" + http_agent: "" + http_get: "" + http_match: "" + interval: "12" members: - - seq-num: "13 (source system.virtual-wan-link.members.seq-num)" - name: "default_name_14" - packet-size: "15" + seq_num: "14 (source system.virtual-wan-link.members.seq-num)" + name: "default_name_15" + packet_size: "16" password: "" - port: "17" + port: "18" protocol: "ping" - recoverytime: "19" - security-mode: "none" + recoverytime: "20" + security_mode: "none" server: "192.168.100.40" sla: - - id: "23" - jitter-threshold: "24" - latency-threshold: "25" - link-cost-factor: "latency" - packetloss-threshold: "27" - threshold-alert-jitter: "28" - threshold-alert-latency: "29" - threshold-alert-packetloss: "30" - threshold-warning-jitter: "31" - threshold-warning-latency: "32" - threshold-warning-packetloss: "33" - update-cascade-interface: "enable" - update-static-route: "enable" - load-balance-mode: "source-ip-based" + id: "24" + jitter_threshold: "25" + latency_threshold: "26" + link_cost_factor: "latency" + packetloss_threshold: "28" + threshold_alert_jitter: "29" + threshold_alert_latency: "30" + threshold_alert_packetloss: "31" + threshold_warning_jitter: "32" + threshold_warning_latency: "33" + threshold_warning_packetloss: "34" + update_cascade_interface: "enable" + update_static_route: "enable" + load_balance_mode: "source-ip-based" members: - comment: "Comments." gateway: "" gateway6: "" - ingress-spillover-threshold: "41" + ingress_spillover_threshold: "42" interface: " (source system.interface.name)" - priority: "43" - seq-num: "44" + priority: "44" + seq_num: "45" source: "" source6: "" - spillover-threshold: "47" + spillover_threshold: "48" status: "disable" - volume-ratio: "49" - weight: "50" + volume_ratio: "50" + weight: "51" service: - - addr-mode: "ipv4" - bandwidth-weight: "53" - dscp-forward: "enable" - dscp-forward-tag: "" - dscp-reverse: "enable" - dscp-reverse-tag: "" + addr_mode: "ipv4" + bandwidth_weight: "54" + default: "enable" + dscp_forward: "enable" + dscp_forward_tag: "" + dscp_reverse: "enable" + dscp_reverse_tag: "" dst: - - name: "default_name_59 (source firewall.address.name firewall.addrgrp.name)" - dst-negate: "enable" + name: "default_name_61 (source firewall.address.name firewall.addrgrp.name)" + dst_negate: "enable" dst6: - - name: "default_name_62 (source firewall.address6.name firewall.addrgrp6.name)" - end-port: "63" + name: "default_name_64 (source firewall.address6.name firewall.addrgrp6.name)" + end_port: "65" gateway: "enable" groups: - - name: "default_name_66 (source user.group.name)" - health-check: " (source system.virtual-wan-link.health-check.name)" - hold-down-time: "68" - id: "69" - input-device: + name: "default_name_68 (source user.group.name)" + health_check: " (source system.virtual-wan-link.health-check.name)" + hold_down_time: "70" + id: "71" + input_device: - - name: "default_name_71 (source system.interface.name)" - internet-service: "enable" - internet-service-ctrl: + name: "default_name_73 (source system.interface.name)" + internet_service: "enable" + internet_service_ctrl: - - id: "74" - internet-service-ctrl-group: + id: "76" + internet_service_ctrl_group: - - name: "default_name_76 (source application.group.name)" - internet-service-custom: + name: "default_name_78 (source application.group.name)" + internet_service_custom: - - name: "default_name_78 (source firewall.internet-service-custom.name)" - internet-service-custom-group: + name: "default_name_80 (source firewall.internet-service-custom.name)" + internet_service_custom_group: - - name: "default_name_80 (source firewall.internet-service-custom-group.name)" - internet-service-group: + name: "default_name_82 (source firewall.internet-service-custom-group.name)" + internet_service_group: - - name: "default_name_82 (source firewall.internet-service-group.name)" - internet-service-id: + name: "default_name_84 (source firewall.internet-service-group.name)" + internet_service_id: - - id: "84 (source firewall.internet-service.id)" - jitter-weight: "85" - latency-weight: "86" - link-cost-factor: "latency" - link-cost-threshold: "88" - member: "89" + id: "86 (source firewall.internet-service.id)" + jitter_weight: "87" + latency_weight: "88" + link_cost_factor: "latency" + link_cost_threshold: "90" + member: "91" mode: "auto" - name: "default_name_91" - packet-loss-weight: "92" - priority-members: + name: "default_name_93" + packet_loss_weight: "94" + priority_members: - - seq-num: "94 (source system.virtual-wan-link.members.seq-num)" - protocol: "95" - quality-link: "96" - route-tag: "97" + seq_num: "96 (source system.virtual-wan-link.members.seq-num)" + protocol: "97" + quality_link: "98" + route_tag: "99" sla: - - health-check: " (source system.virtual-wan-link.health-check.name)" - id: "100" + health_check: " (source system.virtual-wan-link.health-check.name)" + id: "102" src: - - name: "default_name_102 (source firewall.address.name firewall.addrgrp.name)" - src-negate: "enable" + name: "default_name_104 (source firewall.address.name firewall.addrgrp.name)" + src_negate: "enable" src6: - - name: "default_name_105 (source firewall.address6.name firewall.addrgrp6.name)" - start-port: "106" + name: "default_name_107 (source firewall.address6.name firewall.addrgrp6.name)" + start_port: "108" status: "enable" tos: "" - tos-mask: "" + tos_mask: "" users: - - name: "default_name_111 (source user.local.name)" + name: "default_name_113 (source user.local.name)" status: "disable" ''' @@ -732,12 +862,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 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']: @@ -745,12 +879,12 @@ def login(data, fos): else: fos.https('on') - fos.login(host, username, password) + fos.login(host, username, password, verify=ssl_verify) def filter_system_virtual_wan_link_data(json): - option_list = ['fail-alert-interfaces', 'fail-detect', 'health-check', - 'load-balance-mode', 'members', 'service', + option_list = ['fail_alert_interfaces', 'fail_detect', 'health_check', + 'load_balance_mode', 'members', 'service', 'status'] dictionary = {} @@ -761,10 +895,23 @@ def filter_system_virtual_wan_link_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 system_virtual_wan_link(data, fos): vdom = data['vdom'] system_virtual_wan_link_data = data['system_virtual_wan_link'] - filtered_data = filter_system_virtual_wan_link_data(system_virtual_wan_link_data) + filtered_data = underscore_to_hyphen(filter_system_virtual_wan_link_data(system_virtual_wan_link_data)) return fos.set('system', 'virtual-wan-link', @@ -772,76 +919,83 @@ def system_virtual_wan_link(data, fos): vdom=vdom) +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + def fortios_system(data, fos): - login(data, fos) if data['system_virtual_wan_link']: resp = system_virtual_wan_link(data, fos) - fos.logout() - return not resp['status'] == "success", resp['status'] == "success", resp + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp def main(): fields = { - "host": {"required": True, "type": "str"}, - "username": {"required": True, "type": "str"}, - "password": {"required": False, "type": "str", "no_log": True}, + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "default": "", "no_log": True}, "vdom": {"required": False, "type": "str", "default": "root"}, "https": {"required": False, "type": "bool", "default": True}, + "ssl_verify": {"required": False, "type": "bool", "default": True}, "system_virtual_wan_link": { - "required": False, "type": "dict", + "required": False, "type": "dict", "default": None, "options": { - "fail-alert-interfaces": {"required": False, "type": "list", + "fail_alert_interfaces": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "fail-detect": {"required": False, "type": "str", + "fail_detect": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "health-check": {"required": False, "type": "list", + "health_check": {"required": False, "type": "list", "options": { - "addr-mode": {"required": False, "type": "str", + "addr_mode": {"required": False, "type": "str", "choices": ["ipv4", "ipv6"]}, "failtime": {"required": False, "type": "int"}, - "http-get": {"required": False, "type": "str"}, - "http-match": {"required": False, "type": "str"}, + "http_agent": {"required": False, "type": "str"}, + "http_get": {"required": False, "type": "str"}, + "http_match": {"required": False, "type": "str"}, "interval": {"required": False, "type": "int"}, "members": {"required": False, "type": "list", "options": { - "seq-num": {"required": True, "type": "int"} + "seq_num": {"required": False, "type": "int"} }}, "name": {"required": True, "type": "str"}, - "packet-size": {"required": False, "type": "int"}, + "packet_size": {"required": False, "type": "int"}, "password": {"required": False, "type": "str"}, "port": {"required": False, "type": "int"}, "protocol": {"required": False, "type": "str", "choices": ["ping", "tcp-echo", "udp-echo", "http", "twamp", "ping6"]}, "recoverytime": {"required": False, "type": "int"}, - "security-mode": {"required": False, "type": "str", + "security_mode": {"required": False, "type": "str", "choices": ["none", "authentication"]}, "server": {"required": False, "type": "str"}, "sla": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"}, - "jitter-threshold": {"required": False, "type": "int"}, - "latency-threshold": {"required": False, "type": "int"}, - "link-cost-factor": {"required": False, "type": "str", + "jitter_threshold": {"required": False, "type": "int"}, + "latency_threshold": {"required": False, "type": "int"}, + "link_cost_factor": {"required": False, "type": "str", "choices": ["latency", "jitter", "packet-loss"]}, - "packetloss-threshold": {"required": False, "type": "int"} + "packetloss_threshold": {"required": False, "type": "int"} }}, - "threshold-alert-jitter": {"required": False, "type": "int"}, - "threshold-alert-latency": {"required": False, "type": "int"}, - "threshold-alert-packetloss": {"required": False, "type": "int"}, - "threshold-warning-jitter": {"required": False, "type": "int"}, - "threshold-warning-latency": {"required": False, "type": "int"}, - "threshold-warning-packetloss": {"required": False, "type": "int"}, - "update-cascade-interface": {"required": False, "type": "str", + "threshold_alert_jitter": {"required": False, "type": "int"}, + "threshold_alert_latency": {"required": False, "type": "int"}, + "threshold_alert_packetloss": {"required": False, "type": "int"}, + "threshold_warning_jitter": {"required": False, "type": "int"}, + "threshold_warning_latency": {"required": False, "type": "int"}, + "threshold_warning_packetloss": {"required": False, "type": "int"}, + "update_cascade_interface": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "update-static-route": {"required": False, "type": "str", + "update_static_route": {"required": False, "type": "str", "choices": ["enable", "disable"]} }}, - "load-balance-mode": {"required": False, "type": "str", + "load_balance_mode": {"required": False, "type": "str", "choices": ["source-ip-based", "weight-based", "usage-based", "source-dest-ip-based", "measured-volume-based"]}, "members": {"required": False, "type": "list", @@ -849,119 +1003,121 @@ def main(): "comment": {"required": False, "type": "str"}, "gateway": {"required": False, "type": "str"}, "gateway6": {"required": False, "type": "str"}, - "ingress-spillover-threshold": {"required": False, "type": "int"}, + "ingress_spillover_threshold": {"required": False, "type": "int"}, "interface": {"required": False, "type": "str"}, "priority": {"required": False, "type": "int"}, - "seq-num": {"required": True, "type": "int"}, + "seq_num": {"required": False, "type": "int"}, "source": {"required": False, "type": "str"}, "source6": {"required": False, "type": "str"}, - "spillover-threshold": {"required": False, "type": "int"}, + "spillover_threshold": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["disable", "enable"]}, - "volume-ratio": {"required": False, "type": "int"}, + "volume_ratio": {"required": False, "type": "int"}, "weight": {"required": False, "type": "int"} }}, "service": {"required": False, "type": "list", "options": { - "addr-mode": {"required": False, "type": "str", + "addr_mode": {"required": False, "type": "str", "choices": ["ipv4", "ipv6"]}, - "bandwidth-weight": {"required": False, "type": "int"}, - "dscp-forward": {"required": False, "type": "str", + "bandwidth_weight": {"required": False, "type": "int"}, + "default": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "dscp_forward": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dscp-forward-tag": {"required": False, "type": "str"}, - "dscp-reverse": {"required": False, "type": "str", + "dscp_forward_tag": {"required": False, "type": "str"}, + "dscp_reverse": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "dscp-reverse-tag": {"required": False, "type": "str"}, + "dscp_reverse_tag": {"required": False, "type": "str"}, "dst": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "dst-negate": {"required": False, "type": "str", + "dst_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "dst6": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "end-port": {"required": False, "type": "int"}, + "end_port": {"required": False, "type": "int"}, "gateway": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "groups": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "health-check": {"required": False, "type": "str"}, - "hold-down-time": {"required": False, "type": "int"}, + "health_check": {"required": False, "type": "str"}, + "hold_down_time": {"required": False, "type": "int"}, "id": {"required": True, "type": "int"}, - "input-device": {"required": False, "type": "list", + "input_device": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service": {"required": False, "type": "str", + "internet_service": {"required": False, "type": "str", "choices": ["enable", "disable"]}, - "internet-service-ctrl": {"required": False, "type": "list", + "internet_service_ctrl": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "internet-service-ctrl-group": {"required": False, "type": "list", + "internet_service_ctrl_group": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-custom": {"required": False, "type": "list", + "internet_service_custom": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-custom-group": {"required": False, "type": "list", + "internet_service_custom_group": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-group": {"required": False, "type": "list", + "internet_service_group": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "internet-service-id": {"required": False, "type": "list", + "internet_service_id": {"required": False, "type": "list", "options": { "id": {"required": True, "type": "int"} }}, - "jitter-weight": {"required": False, "type": "int"}, - "latency-weight": {"required": False, "type": "int"}, - "link-cost-factor": {"required": False, "type": "str", + "jitter_weight": {"required": False, "type": "int"}, + "latency_weight": {"required": False, "type": "int"}, + "link_cost_factor": {"required": False, "type": "str", "choices": ["latency", "jitter", "packet-loss", "inbandwidth", "outbandwidth", "bibandwidth", "custom-profile-1"]}, - "link-cost-threshold": {"required": False, "type": "int"}, + "link_cost_threshold": {"required": False, "type": "int"}, "member": {"required": False, "type": "int"}, "mode": {"required": False, "type": "str", "choices": ["auto", "manual", "priority", "sla"]}, "name": {"required": False, "type": "str"}, - "packet-loss-weight": {"required": False, "type": "int"}, - "priority-members": {"required": False, "type": "list", + "packet_loss_weight": {"required": False, "type": "int"}, + "priority_members": {"required": False, "type": "list", "options": { - "seq-num": {"required": True, "type": "int"} + "seq_num": {"required": False, "type": "int"} }}, "protocol": {"required": False, "type": "int"}, - "quality-link": {"required": False, "type": "int"}, - "route-tag": {"required": False, "type": "int"}, + "quality_link": {"required": False, "type": "int"}, + "route_tag": {"required": False, "type": "int"}, "sla": {"required": False, "type": "list", "options": { - "health-check": {"required": True, "type": "str"}, + "health_check": {"required": False, "type": "str"}, "id": {"required": False, "type": "int"} }}, "src": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "src-negate": {"required": False, "type": "str", + "src_negate": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "src6": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} }}, - "start-port": {"required": False, "type": "int"}, + "start_port": {"required": False, "type": "int"}, "status": {"required": False, "type": "str", "choices": ["enable", "disable"]}, "tos": {"required": False, "type": "str"}, - "tos-mask": {"required": False, "type": "str"}, + "tos_mask": {"required": False, "type": "str"}, "users": {"required": False, "type": "list", "options": { "name": {"required": True, "type": "str"} @@ -976,14 +1132,31 @@ def main(): module = AnsibleModule(argument_spec=fields, supports_check_mode=False) - try: - from fortiosapi import FortiOSAPI - except ImportError: - module.fail_json(msg="fortiosapi module is required") - fos = FortiOSAPI() + # legacy_mode refers to using fortiosapi instead of HTTPAPI + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(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_system(module.params, fos) + login(module.params, fos) + is_error, has_changed, result = fortios_system(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 140e5b36443..cecbf9cbbf8 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -3693,46 +3693,10 @@ lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E338 lib/ansible/modules/network/fortios/fortios_report_chart.py validate-modules:E326 -lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_switch_controller_global.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_global.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_accprofile.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_accprofile.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_admin.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_admin.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_api_user.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_api_user.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_central_management.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_central_management.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E326 -lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_dns.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_dns.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E326 -lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_interface.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_interface.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_vdom.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_vdom.py validate-modules:E337 -lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py validate-modules:E336 -lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_user_device.py validate-modules:E337 diff --git a/test/units/modules/network/fortios/test_fortios_spamfilter_profile.py b/test/units/modules/network/fortios/test_fortios_spamfilter_profile.py new file mode 100644 index 00000000000..8f5dc599142 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_spamfilter_profile.py @@ -0,0 +1,339 @@ +# 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_spamfilter_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_spamfilter_profile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_spamfilter_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', + 'spamfilter_profile': { + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'external': 'enable', + 'flow-based': 'enable', + 'name': 'default_name_6', + 'replacemsg-group': 'test_value_7', + 'spam-bwl-table': '8', + 'spam-bword-table': '9', + 'spam-bword-threshold': '10', + 'spam-filtering': 'enable', + 'spam-iptrust-table': '12', + 'spam-log': 'disable', + 'spam-log-fortiguard-response': 'disable', + 'spam-mheader-table': '15', + 'spam-rbl-table': '16', + + } + + set_method_mock.assert_called_with('spamfilter', '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_spamfilter_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', + 'spamfilter_profile': { + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'external': 'enable', + 'flow-based': 'enable', + 'name': 'default_name_6', + 'replacemsg-group': 'test_value_7', + 'spam-bwl-table': '8', + 'spam-bword-table': '9', + 'spam-bword-threshold': '10', + 'spam-filtering': 'enable', + 'spam-iptrust-table': '12', + 'spam-log': 'disable', + 'spam-log-fortiguard-response': 'disable', + 'spam-mheader-table': '15', + 'spam-rbl-table': '16', + + } + + set_method_mock.assert_called_with('spamfilter', '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_spamfilter_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', + 'spamfilter_profile': { + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + delete_method_mock.assert_called_with('spamfilter', '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_spamfilter_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', + 'spamfilter_profile': { + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + delete_method_mock.assert_called_with('spamfilter', '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_spamfilter_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', + 'spamfilter_profile': { + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'external': 'enable', + 'flow-based': 'enable', + 'name': 'default_name_6', + 'replacemsg-group': 'test_value_7', + 'spam-bwl-table': '8', + 'spam-bword-table': '9', + 'spam-bword-threshold': '10', + 'spam-filtering': 'enable', + 'spam-iptrust-table': '12', + 'spam-log': 'disable', + 'spam-log-fortiguard-response': 'disable', + 'spam-mheader-table': '15', + 'spam-rbl-table': '16', + + } + + set_method_mock.assert_called_with('spamfilter', '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_spamfilter_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', + 'spamfilter_profile': { + 'random_attribute_not_valid': 'tag', + 'comment': 'Comment.', + 'external': 'enable', + 'flow_based': 'enable', + 'name': 'default_name_6', + 'replacemsg_group': 'test_value_7', + 'spam_bwl_table': '8', + 'spam_bword_table': '9', + 'spam_bword_threshold': '10', + 'spam_filtering': 'enable', + 'spam_iptrust_table': '12', + 'spam_log': 'disable', + 'spam_log_fortiguard_response': 'disable', + 'spam_mheader_table': '15', + 'spam_rbl_table': '16', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance) + + expected_data = { + 'comment': 'Comment.', + 'external': 'enable', + 'flow-based': 'enable', + 'name': 'default_name_6', + 'replacemsg-group': 'test_value_7', + 'spam-bwl-table': '8', + 'spam-bword-table': '9', + 'spam-bword-threshold': '10', + 'spam-filtering': 'enable', + 'spam-iptrust-table': '12', + 'spam-log': 'disable', + 'spam-log-fortiguard-response': 'disable', + 'spam-mheader-table': '15', + 'spam-rbl-table': '16', + + } + + set_method_mock.assert_called_with('spamfilter', '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_ssh_filter_profile.py b/test/units/modules/network/fortios/test_fortios_ssh_filter_profile.py new file mode 100644 index 00000000000..80286c1e8cb --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_ssh_filter_profile.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_ssh_filter_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_ssh_filter_profile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_ssh_filter_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', + 'ssh_filter_profile': { + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + expected_data = { + 'block': 'x11', + 'default-command-log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + } + + set_method_mock.assert_called_with('ssh-filter', '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_ssh_filter_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', + 'ssh_filter_profile': { + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + expected_data = { + 'block': 'x11', + 'default-command-log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + } + + set_method_mock.assert_called_with('ssh-filter', '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_ssh_filter_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', + 'ssh_filter_profile': { + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + delete_method_mock.assert_called_with('ssh-filter', '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_ssh_filter_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', + 'ssh_filter_profile': { + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + delete_method_mock.assert_called_with('ssh-filter', '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_ssh_filter_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', + 'ssh_filter_profile': { + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + expected_data = { + 'block': 'x11', + 'default-command-log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + } + + set_method_mock.assert_called_with('ssh-filter', '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_ssh_filter_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', + 'ssh_filter_profile': { + 'random_attribute_not_valid': 'tag', + 'block': 'x11', + 'default_command_log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance) + + expected_data = { + 'block': 'x11', + 'default-command-log': 'enable', + 'log': 'x11', + 'name': 'default_name_6', + + } + + set_method_mock.assert_called_with('ssh-filter', '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_switch_controller_global.py b/test/units/modules/network/fortios/test_fortios_switch_controller_global.py new file mode 100644 index 00000000000..50021093e6b --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_global.py @@ -0,0 +1,199 @@ +# 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_switch_controller_global +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_switch_controller_global.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_global_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', + 'switch_controller_global': { + 'allow_multiple_interfaces': 'enable', + 'default_virtual_switch_vlan': 'test_value_4', + 'https_image_push': 'enable', + 'log_mac_limit_violations': 'enable', + 'mac_aging_interval': '7', + 'mac_retention_period': '8', + 'mac_violation_timer': '9' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'allow-multiple-interfaces': 'enable', + 'default-virtual-switch-vlan': 'test_value_4', + 'https-image-push': 'enable', + 'log-mac-limit-violations': 'enable', + 'mac-aging-interval': '7', + 'mac-retention-period': '8', + 'mac-violation-timer': '9' + } + + set_method_mock.assert_called_with('switch-controller', 'global', 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_switch_controller_global_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', + 'switch_controller_global': { + 'allow_multiple_interfaces': 'enable', + 'default_virtual_switch_vlan': 'test_value_4', + 'https_image_push': 'enable', + 'log_mac_limit_violations': 'enable', + 'mac_aging_interval': '7', + 'mac_retention_period': '8', + 'mac_violation_timer': '9' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'allow-multiple-interfaces': 'enable', + 'default-virtual-switch-vlan': 'test_value_4', + 'https-image-push': 'enable', + 'log-mac-limit-violations': 'enable', + 'mac-aging-interval': '7', + 'mac-retention-period': '8', + 'mac-violation-timer': '9' + } + + set_method_mock.assert_called_with('switch-controller', 'global', 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_switch_controller_global_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', + 'switch_controller_global': { + 'allow_multiple_interfaces': 'enable', + 'default_virtual_switch_vlan': 'test_value_4', + 'https_image_push': 'enable', + 'log_mac_limit_violations': 'enable', + 'mac_aging_interval': '7', + 'mac_retention_period': '8', + 'mac_violation_timer': '9' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'allow-multiple-interfaces': 'enable', + 'default-virtual-switch-vlan': 'test_value_4', + 'https-image-push': 'enable', + 'log-mac-limit-violations': 'enable', + 'mac-aging-interval': '7', + 'mac-retention-period': '8', + 'mac-violation-timer': '9' + } + + set_method_mock.assert_called_with('switch-controller', 'global', 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_switch_controller_global_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', + 'switch_controller_global': { + 'random_attribute_not_valid': 'tag', + 'allow_multiple_interfaces': 'enable', + 'default_virtual_switch_vlan': 'test_value_4', + 'https_image_push': 'enable', + 'log_mac_limit_violations': 'enable', + 'mac_aging_interval': '7', + 'mac_retention_period': '8', + 'mac_violation_timer': '9' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'allow-multiple-interfaces': 'enable', + 'default-virtual-switch-vlan': 'test_value_4', + 'https-image-push': 'enable', + 'log-mac-limit-violations': 'enable', + 'mac-aging-interval': '7', + 'mac-retention-period': '8', + 'mac-violation-timer': '9' + } + + set_method_mock.assert_called_with('switch-controller', 'global', 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_switch_controller_lldp_profile.py b/test/units/modules/network/fortios/test_fortios_switch_controller_lldp_profile.py new file mode 100644 index 00000000000..783418d6f42 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_lldp_profile.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_switch_controller_lldp_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_switch_controller_lldp_profile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + '802.1-tlvs': 'port-vlan-id', + '802.3-tlvs': 'max-frame-size', + 'auto-isl': 'disable', + 'auto-isl-hello-timer': '6', + 'auto-isl-port-group': '7', + 'auto-isl-receive-timeout': '8', + 'med-tlvs': 'inventory-management', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + '802.1-tlvs': 'port-vlan-id', + '802.3-tlvs': 'max-frame-size', + 'auto-isl': 'disable', + 'auto-isl-hello-timer': '6', + 'auto-isl-port-group': '7', + 'auto-isl-receive-timeout': '8', + 'med-tlvs': 'inventory-management', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + '802.1-tlvs': 'port-vlan-id', + '802.3-tlvs': 'max-frame-size', + 'auto-isl': 'disable', + 'auto-isl-hello-timer': '6', + 'auto-isl-port-group': '7', + 'auto-isl-receive-timeout': '8', + 'med-tlvs': 'inventory-management', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_profile': { + 'random_attribute_not_valid': 'tag', + '802.1_tlvs': 'port-vlan-id', + '802.3_tlvs': 'max-frame-size', + 'auto_isl': 'disable', + 'auto_isl_hello_timer': '6', + 'auto_isl_port_group': '7', + 'auto_isl_receive_timeout': '8', + 'med_tlvs': 'inventory-management', + 'name': 'default_name_10' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + '802.1-tlvs': 'port-vlan-id', + '802.3-tlvs': 'max-frame-size', + 'auto-isl': 'disable', + 'auto-isl-hello-timer': '6', + 'auto-isl-port-group': '7', + 'auto-isl-receive-timeout': '8', + 'med-tlvs': 'inventory-management', + 'name': 'default_name_10' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_settings.py b/test/units/modules/network/fortios/test_fortios_switch_controller_lldp_settings.py new file mode 100644 index 00000000000..c8e9e8c94c0 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_lldp_settings.py @@ -0,0 +1,183 @@ +# 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_switch_controller_lldp_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_switch_controller_lldp_settings.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_lldp_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', + 'switch_controller_lldp_settings': { + 'fast_start_interval': '3', + 'management_interface': 'internal', + 'status': 'enable', + 'tx_hold': '6', + 'tx_interval': '7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'fast-start-interval': '3', + 'management-interface': 'internal', + 'status': 'enable', + 'tx-hold': '6', + 'tx-interval': '7' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_settings': { + 'fast_start_interval': '3', + 'management_interface': 'internal', + 'status': 'enable', + 'tx_hold': '6', + 'tx_interval': '7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'fast-start-interval': '3', + 'management-interface': 'internal', + 'status': 'enable', + 'tx-hold': '6', + 'tx-interval': '7' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_settings': { + 'fast_start_interval': '3', + 'management_interface': 'internal', + 'status': 'enable', + 'tx_hold': '6', + 'tx_interval': '7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'fast-start-interval': '3', + 'management-interface': 'internal', + 'status': 'enable', + 'tx-hold': '6', + 'tx-interval': '7' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_lldp_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', + 'switch_controller_lldp_settings': { + 'random_attribute_not_valid': 'tag', + 'fast_start_interval': '3', + 'management_interface': 'internal', + 'status': 'enable', + 'tx_hold': '6', + 'tx_interval': '7' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'fast-start-interval': '3', + 'management-interface': 'internal', + 'status': 'enable', + 'tx-hold': '6', + 'tx-interval': '7' + } + + set_method_mock.assert_called_with('switch-controller', 'lldp-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_switch_controller_mac_sync_settings.py b/test/units/modules/network/fortios/test_fortios_switch_controller_mac_sync_settings.py new file mode 100644 index 00000000000..8a41be2c86c --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_mac_sync_settings.py @@ -0,0 +1,151 @@ +# 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_switch_controller_mac_sync_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_switch_controller_mac_sync_settings.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_mac_sync_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', + 'switch_controller_mac_sync_settings': { + 'mac_sync_interval': '3' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'mac-sync-interval': '3' + } + + set_method_mock.assert_called_with('switch-controller', 'mac-sync-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_switch_controller_mac_sync_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', + 'switch_controller_mac_sync_settings': { + 'mac_sync_interval': '3' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'mac-sync-interval': '3' + } + + set_method_mock.assert_called_with('switch-controller', 'mac-sync-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_switch_controller_mac_sync_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', + 'switch_controller_mac_sync_settings': { + 'mac_sync_interval': '3' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'mac-sync-interval': '3' + } + + set_method_mock.assert_called_with('switch-controller', 'mac-sync-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_switch_controller_mac_sync_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', + 'switch_controller_mac_sync_settings': { + 'random_attribute_not_valid': 'tag', + 'mac_sync_interval': '3' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'mac-sync-interval': '3' + } + + set_method_mock.assert_called_with('switch-controller', 'mac-sync-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_switch_controller_managed_switch.py b/test/units/modules/network/fortios/test_fortios_switch_controller_managed_switch.py new file mode 100644 index 00000000000..16703470645 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_managed_switch.py @@ -0,0 +1,389 @@ +# 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_switch_controller_managed_switch +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_switch_controller_managed_switch.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': {'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + expected_data = {'delayed-restart-trigger': '3', + 'description': 'test_value_4', + 'directly-connected': '5', + 'dynamic-capability': '6', + 'dynamically-discovered': '7', + 'fsw-wan1-admin': 'discovered', + 'fsw-wan1-peer': 'test_value_9', + 'fsw-wan2-admin': 'discovered', + 'fsw-wan2-peer': 'test_value_11', + 'max-allowed-trunk-members': '12', + 'name': 'default_name_13', + 'owner-vdom': 'test_value_14', + 'poe-detection-type': '15', + 'poe-pre-standard-detection': 'enable', + 'pre-provisioned': '17', + 'staged-image-version': 'test_value_18', + 'switch-device-tag': 'test_value_19', + 'switch-id': 'test_value_20', + 'switch-profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + } + + set_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': {'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + expected_data = {'delayed-restart-trigger': '3', + 'description': 'test_value_4', + 'directly-connected': '5', + 'dynamic-capability': '6', + 'dynamically-discovered': '7', + 'fsw-wan1-admin': 'discovered', + 'fsw-wan1-peer': 'test_value_9', + 'fsw-wan2-admin': 'discovered', + 'fsw-wan2-peer': 'test_value_11', + 'max-allowed-trunk-members': '12', + 'name': 'default_name_13', + 'owner-vdom': 'test_value_14', + 'poe-detection-type': '15', + 'poe-pre-standard-detection': 'enable', + 'pre-provisioned': '17', + 'staged-image-version': 'test_value_18', + 'switch-device-tag': 'test_value_19', + 'switch-id': 'test_value_20', + 'switch-profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + } + + set_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': {'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': {'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + delete_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': {'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + expected_data = {'delayed-restart-trigger': '3', + 'description': 'test_value_4', + 'directly-connected': '5', + 'dynamic-capability': '6', + 'dynamically-discovered': '7', + 'fsw-wan1-admin': 'discovered', + 'fsw-wan1-peer': 'test_value_9', + 'fsw-wan2-admin': 'discovered', + 'fsw-wan2-peer': 'test_value_11', + 'max-allowed-trunk-members': '12', + 'name': 'default_name_13', + 'owner-vdom': 'test_value_14', + 'poe-detection-type': '15', + 'poe-pre-standard-detection': 'enable', + 'pre-provisioned': '17', + 'staged-image-version': 'test_value_18', + 'switch-device-tag': 'test_value_19', + 'switch-id': 'test_value_20', + 'switch-profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + } + + set_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_managed_switch_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', + 'switch_controller_managed_switch': { + 'random_attribute_not_valid': 'tag', 'delayed_restart_trigger': '3', + 'description': 'test_value_4', + 'directly_connected': '5', + 'dynamic_capability': '6', + 'dynamically_discovered': '7', + 'fsw_wan1_admin': 'discovered', + 'fsw_wan1_peer': 'test_value_9', + 'fsw_wan2_admin': 'discovered', + 'fsw_wan2_peer': 'test_value_11', + 'max_allowed_trunk_members': '12', + 'name': 'default_name_13', + 'owner_vdom': 'test_value_14', + 'poe_detection_type': '15', + 'poe_pre_standard_detection': 'enable', + 'pre_provisioned': '17', + 'staged_image_version': 'test_value_18', + 'switch_device_tag': 'test_value_19', + 'switch_id': 'test_value_20', + 'switch_profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance) + + expected_data = {'delayed-restart-trigger': '3', + 'description': 'test_value_4', + 'directly-connected': '5', + 'dynamic-capability': '6', + 'dynamically-discovered': '7', + 'fsw-wan1-admin': 'discovered', + 'fsw-wan1-peer': 'test_value_9', + 'fsw-wan2-admin': 'discovered', + 'fsw-wan2-peer': 'test_value_11', + 'max-allowed-trunk-members': '12', + 'name': 'default_name_13', + 'owner-vdom': 'test_value_14', + 'poe-detection-type': '15', + 'poe-pre-standard-detection': 'enable', + 'pre-provisioned': '17', + 'staged-image-version': 'test_value_18', + 'switch-device-tag': 'test_value_19', + 'switch-id': 'test_value_20', + 'switch-profile': 'test_value_21', + 'type': 'virtual', + 'version': '23' + } + + set_method_mock.assert_called_with('switch-controller', 'managed-switch', 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_switch_controller_network_monitor_settings.py b/test/units/modules/network/fortios/test_fortios_switch_controller_network_monitor_settings.py new file mode 100644 index 00000000000..50255f41c60 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_switch_controller_network_monitor_settings.py @@ -0,0 +1,151 @@ +# 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_switch_controller_network_monitor_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_switch_controller_network_monitor_settings.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_switch_controller_network_monitor_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', + 'switch_controller_network_monitor_settings': { + 'network_monitoring': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'network-monitoring': 'enable' + } + + set_method_mock.assert_called_with('switch-controller', 'network-monitor-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_switch_controller_network_monitor_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', + 'switch_controller_network_monitor_settings': { + 'network_monitoring': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'network-monitoring': 'enable' + } + + set_method_mock.assert_called_with('switch-controller', 'network-monitor-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_switch_controller_network_monitor_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', + 'switch_controller_network_monitor_settings': { + 'network_monitoring': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'network-monitoring': 'enable' + } + + set_method_mock.assert_called_with('switch-controller', 'network-monitor-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_switch_controller_network_monitor_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', + 'switch_controller_network_monitor_settings': { + 'random_attribute_not_valid': 'tag', + 'network_monitoring': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance) + + expected_data = { + 'network-monitoring': 'enable' + } + + set_method_mock.assert_called_with('switch-controller', 'network-monitor-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_system_accprofile.py b/test/units/modules/network/fortios/test_fortios_system_accprofile.py new file mode 100644 index 00000000000..c0479fc6146 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_accprofile.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_system_accprofile +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_system_accprofile.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_accprofile_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', + 'system_accprofile': { + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + expected_data = { + 'admintimeout': '3', + 'admintimeout-override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + } + + set_method_mock.assert_called_with('system', 'accprofile', 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_system_accprofile_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', + 'system_accprofile': { + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + expected_data = { + 'admintimeout': '3', + 'admintimeout-override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + } + + set_method_mock.assert_called_with('system', 'accprofile', 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_system_accprofile_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', + 'system_accprofile': { + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'accprofile', 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_system_accprofile_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', + 'system_accprofile': { + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'accprofile', 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_system_accprofile_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', + 'system_accprofile': { + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + expected_data = { + 'admintimeout': '3', + 'admintimeout-override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + } + + set_method_mock.assert_called_with('system', 'accprofile', 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_system_accprofile_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', + 'system_accprofile': { + 'random_attribute_not_valid': 'tag', + 'admintimeout': '3', + 'admintimeout_override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance) + + expected_data = { + 'admintimeout': '3', + 'admintimeout-override': 'enable', + 'authgrp': 'none', + 'comments': 'test_value_6', + 'ftviewgrp': 'none', + 'fwgrp': 'none', + 'loggrp': 'none', + 'name': 'default_name_10', + 'netgrp': 'none', + 'scope': 'vdom', + 'secfabgrp': 'none', + 'sysgrp': 'none', + 'utmgrp': 'none', + 'vpngrp': 'none', + 'wanoptgrp': 'none', + 'wifi': 'none' + } + + set_method_mock.assert_called_with('system', 'accprofile', 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_system_admin.py b/test/units/modules/network/fortios/test_fortios_system_admin.py new file mode 100644 index 00000000000..bf5445dcf54 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_admin.py @@ -0,0 +1,689 @@ +# 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_system_admin +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_system_admin.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_admin_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', + 'system_admin': { + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'accprofile-override': 'enable', + 'allow-remove-admin-session': 'enable', + 'comments': 'test_value_6', + 'email-to': 'test_value_7', + 'force-password-change': 'enable', + 'fortitoken': 'test_value_9', + 'guest-auth': 'disable', + 'guest-lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6-trusthost1': 'test_value_15', + 'ip6-trusthost10': 'test_value_16', + 'ip6-trusthost2': 'test_value_17', + 'ip6-trusthost3': 'test_value_18', + 'ip6-trusthost4': 'test_value_19', + 'ip6-trusthost5': 'test_value_20', + 'ip6-trusthost6': 'test_value_21', + 'ip6-trusthost7': 'test_value_22', + 'ip6-trusthost8': 'test_value_23', + 'ip6-trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password-expire': 'test_value_27', + 'peer-auth': 'enable', + 'peer-group': 'test_value_29', + 'radius-vdom-override': 'enable', + 'remote-auth': 'enable', + 'remote-group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms-custom-server': 'test_value_34', + 'sms-phone': 'test_value_35', + 'sms-server': 'fortiguard', + 'ssh-certificate': 'test_value_37', + 'ssh-public-key1': 'test_value_38', + 'ssh-public-key2': 'test_value_39', + 'ssh-public-key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two-factor': 'disable', + 'wildcard': 'enable' + } + + set_method_mock.assert_called_with('system', 'admin', 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_system_admin_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', + 'system_admin': { + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'accprofile-override': 'enable', + 'allow-remove-admin-session': 'enable', + 'comments': 'test_value_6', + 'email-to': 'test_value_7', + 'force-password-change': 'enable', + 'fortitoken': 'test_value_9', + 'guest-auth': 'disable', + 'guest-lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6-trusthost1': 'test_value_15', + 'ip6-trusthost10': 'test_value_16', + 'ip6-trusthost2': 'test_value_17', + 'ip6-trusthost3': 'test_value_18', + 'ip6-trusthost4': 'test_value_19', + 'ip6-trusthost5': 'test_value_20', + 'ip6-trusthost6': 'test_value_21', + 'ip6-trusthost7': 'test_value_22', + 'ip6-trusthost8': 'test_value_23', + 'ip6-trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password-expire': 'test_value_27', + 'peer-auth': 'enable', + 'peer-group': 'test_value_29', + 'radius-vdom-override': 'enable', + 'remote-auth': 'enable', + 'remote-group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms-custom-server': 'test_value_34', + 'sms-phone': 'test_value_35', + 'sms-server': 'fortiguard', + 'ssh-certificate': 'test_value_37', + 'ssh-public-key1': 'test_value_38', + 'ssh-public-key2': 'test_value_39', + 'ssh-public-key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two-factor': 'disable', + 'wildcard': 'enable' + } + + set_method_mock.assert_called_with('system', 'admin', 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_system_admin_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', + 'system_admin': { + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'admin', 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_system_admin_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', + 'system_admin': { + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'admin', 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_system_admin_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', + 'system_admin': { + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'accprofile-override': 'enable', + 'allow-remove-admin-session': 'enable', + 'comments': 'test_value_6', + 'email-to': 'test_value_7', + 'force-password-change': 'enable', + 'fortitoken': 'test_value_9', + 'guest-auth': 'disable', + 'guest-lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6-trusthost1': 'test_value_15', + 'ip6-trusthost10': 'test_value_16', + 'ip6-trusthost2': 'test_value_17', + 'ip6-trusthost3': 'test_value_18', + 'ip6-trusthost4': 'test_value_19', + 'ip6-trusthost5': 'test_value_20', + 'ip6-trusthost6': 'test_value_21', + 'ip6-trusthost7': 'test_value_22', + 'ip6-trusthost8': 'test_value_23', + 'ip6-trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password-expire': 'test_value_27', + 'peer-auth': 'enable', + 'peer-group': 'test_value_29', + 'radius-vdom-override': 'enable', + 'remote-auth': 'enable', + 'remote-group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms-custom-server': 'test_value_34', + 'sms-phone': 'test_value_35', + 'sms-server': 'fortiguard', + 'ssh-certificate': 'test_value_37', + 'ssh-public-key1': 'test_value_38', + 'ssh-public-key2': 'test_value_39', + 'ssh-public-key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two-factor': 'disable', + 'wildcard': 'enable' + } + + set_method_mock.assert_called_with('system', 'admin', 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_system_admin_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', + 'system_admin': { + 'random_attribute_not_valid': 'tag', + 'accprofile': 'test_value_3', + 'accprofile_override': 'enable', + 'allow_remove_admin_session': 'enable', + 'comments': 'test_value_6', + 'email_to': 'test_value_7', + 'force_password_change': 'enable', + 'fortitoken': 'test_value_9', + 'guest_auth': 'disable', + 'guest_lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6_trusthost1': 'test_value_15', + 'ip6_trusthost10': 'test_value_16', + 'ip6_trusthost2': 'test_value_17', + 'ip6_trusthost3': 'test_value_18', + 'ip6_trusthost4': 'test_value_19', + 'ip6_trusthost5': 'test_value_20', + 'ip6_trusthost6': 'test_value_21', + 'ip6_trusthost7': 'test_value_22', + 'ip6_trusthost8': 'test_value_23', + 'ip6_trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password_expire': 'test_value_27', + 'peer_auth': 'enable', + 'peer_group': 'test_value_29', + 'radius_vdom_override': 'enable', + 'remote_auth': 'enable', + 'remote_group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms_custom_server': 'test_value_34', + 'sms_phone': 'test_value_35', + 'sms_server': 'fortiguard', + 'ssh_certificate': 'test_value_37', + 'ssh_public_key1': 'test_value_38', + 'ssh_public_key2': 'test_value_39', + 'ssh_public_key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two_factor': 'disable', + 'wildcard': 'enable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'accprofile-override': 'enable', + 'allow-remove-admin-session': 'enable', + 'comments': 'test_value_6', + 'email-to': 'test_value_7', + 'force-password-change': 'enable', + 'fortitoken': 'test_value_9', + 'guest-auth': 'disable', + 'guest-lang': 'test_value_11', + 'hidden': '12', + 'history0': 'test_value_13', + 'history1': 'test_value_14', + 'ip6-trusthost1': 'test_value_15', + 'ip6-trusthost10': 'test_value_16', + 'ip6-trusthost2': 'test_value_17', + 'ip6-trusthost3': 'test_value_18', + 'ip6-trusthost4': 'test_value_19', + 'ip6-trusthost5': 'test_value_20', + 'ip6-trusthost6': 'test_value_21', + 'ip6-trusthost7': 'test_value_22', + 'ip6-trusthost8': 'test_value_23', + 'ip6-trusthost9': 'test_value_24', + 'name': 'default_name_25', + 'password': 'test_value_26', + 'password-expire': 'test_value_27', + 'peer-auth': 'enable', + 'peer-group': 'test_value_29', + 'radius-vdom-override': 'enable', + 'remote-auth': 'enable', + 'remote-group': 'test_value_32', + 'schedule': 'test_value_33', + 'sms-custom-server': 'test_value_34', + 'sms-phone': 'test_value_35', + 'sms-server': 'fortiguard', + 'ssh-certificate': 'test_value_37', + 'ssh-public-key1': 'test_value_38', + 'ssh-public-key2': 'test_value_39', + 'ssh-public-key3': 'test_value_40', + 'trusthost1': 'test_value_41', + 'trusthost10': 'test_value_42', + 'trusthost2': 'test_value_43', + 'trusthost3': 'test_value_44', + 'trusthost4': 'test_value_45', + 'trusthost5': 'test_value_46', + 'trusthost6': 'test_value_47', + 'trusthost7': 'test_value_48', + 'trusthost8': 'test_value_49', + 'trusthost9': 'test_value_50', + 'two-factor': 'disable', + 'wildcard': 'enable' + } + + set_method_mock.assert_called_with('system', 'admin', 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_system_api_user.py b/test/units/modules/network/fortios/test_fortios_system_api_user.py new file mode 100644 index 00000000000..c127c9c465f --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_api_user.py @@ -0,0 +1,279 @@ +# 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_system_api_user +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_system_api_user.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_api_user_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', + 'system_api_user': { + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'api-key': 'test_value_4', + 'comments': 'test_value_5', + 'cors-allow-origin': 'test_value_6', + 'name': 'default_name_7', + 'peer-auth': 'enable', + 'peer-group': 'test_value_9', + 'schedule': 'test_value_10', + + } + + set_method_mock.assert_called_with('system', 'api-user', 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_system_api_user_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', + 'system_api_user': { + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'api-key': 'test_value_4', + 'comments': 'test_value_5', + 'cors-allow-origin': 'test_value_6', + 'name': 'default_name_7', + 'peer-auth': 'enable', + 'peer-group': 'test_value_9', + 'schedule': 'test_value_10', + + } + + set_method_mock.assert_called_with('system', 'api-user', 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_system_api_user_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', + 'system_api_user': { + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'api-user', 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_system_api_user_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', + 'system_api_user': { + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'api-user', 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_system_api_user_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', + 'system_api_user': { + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'api-key': 'test_value_4', + 'comments': 'test_value_5', + 'cors-allow-origin': 'test_value_6', + 'name': 'default_name_7', + 'peer-auth': 'enable', + 'peer-group': 'test_value_9', + 'schedule': 'test_value_10', + + } + + set_method_mock.assert_called_with('system', 'api-user', 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_system_api_user_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', + 'system_api_user': { + 'random_attribute_not_valid': 'tag', + 'accprofile': 'test_value_3', + 'api_key': 'test_value_4', + 'comments': 'test_value_5', + 'cors_allow_origin': 'test_value_6', + 'name': 'default_name_7', + 'peer_auth': 'enable', + 'peer_group': 'test_value_9', + 'schedule': 'test_value_10', + + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance) + + expected_data = { + 'accprofile': 'test_value_3', + 'api-key': 'test_value_4', + 'comments': 'test_value_5', + 'cors-allow-origin': 'test_value_6', + 'name': 'default_name_7', + 'peer-auth': 'enable', + 'peer-group': 'test_value_9', + 'schedule': 'test_value_10', + + } + + set_method_mock.assert_called_with('system', 'api-user', 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_system_central_management.py b/test/units/modules/network/fortios/test_fortios_system_central_management.py new file mode 100644 index 00000000000..149effdc6d9 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_central_management.py @@ -0,0 +1,263 @@ +# 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_system_central_management +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_system_central_management.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_central_management_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', + 'system_central_management': { + 'allow_monitor': 'enable', + 'allow_push_configuration': 'enable', + 'allow_push_firmware': 'enable', + 'allow_remote_firmware_upgrade': 'enable', + 'enc_algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg_source_ip': 'test_value_9', + 'fmg_source_ip6': 'test_value_10', + 'include_default_servers': 'enable', + 'mode': 'normal', + 'schedule_config_restore': 'enable', + 'schedule_script_restore': 'enable', + 'serial_number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance) + + expected_data = { + 'allow-monitor': 'enable', + 'allow-push-configuration': 'enable', + 'allow-push-firmware': 'enable', + 'allow-remote-firmware-upgrade': 'enable', + 'enc-algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg-source-ip': 'test_value_9', + 'fmg-source-ip6': 'test_value_10', + 'include-default-servers': 'enable', + 'mode': 'normal', + 'schedule-config-restore': 'enable', + 'schedule-script-restore': 'enable', + 'serial-number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + } + + set_method_mock.assert_called_with('system', 'central-management', 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_system_central_management_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', + 'system_central_management': { + 'allow_monitor': 'enable', + 'allow_push_configuration': 'enable', + 'allow_push_firmware': 'enable', + 'allow_remote_firmware_upgrade': 'enable', + 'enc_algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg_source_ip': 'test_value_9', + 'fmg_source_ip6': 'test_value_10', + 'include_default_servers': 'enable', + 'mode': 'normal', + 'schedule_config_restore': 'enable', + 'schedule_script_restore': 'enable', + 'serial_number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance) + + expected_data = { + 'allow-monitor': 'enable', + 'allow-push-configuration': 'enable', + 'allow-push-firmware': 'enable', + 'allow-remote-firmware-upgrade': 'enable', + 'enc-algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg-source-ip': 'test_value_9', + 'fmg-source-ip6': 'test_value_10', + 'include-default-servers': 'enable', + 'mode': 'normal', + 'schedule-config-restore': 'enable', + 'schedule-script-restore': 'enable', + 'serial-number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + } + + set_method_mock.assert_called_with('system', 'central-management', 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_system_central_management_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', + 'system_central_management': { + 'allow_monitor': 'enable', + 'allow_push_configuration': 'enable', + 'allow_push_firmware': 'enable', + 'allow_remote_firmware_upgrade': 'enable', + 'enc_algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg_source_ip': 'test_value_9', + 'fmg_source_ip6': 'test_value_10', + 'include_default_servers': 'enable', + 'mode': 'normal', + 'schedule_config_restore': 'enable', + 'schedule_script_restore': 'enable', + 'serial_number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance) + + expected_data = { + 'allow-monitor': 'enable', + 'allow-push-configuration': 'enable', + 'allow-push-firmware': 'enable', + 'allow-remote-firmware-upgrade': 'enable', + 'enc-algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg-source-ip': 'test_value_9', + 'fmg-source-ip6': 'test_value_10', + 'include-default-servers': 'enable', + 'mode': 'normal', + 'schedule-config-restore': 'enable', + 'schedule-script-restore': 'enable', + 'serial-number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + } + + set_method_mock.assert_called_with('system', 'central-management', 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_system_central_management_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', + 'system_central_management': { + 'random_attribute_not_valid': 'tag', + 'allow_monitor': 'enable', + 'allow_push_configuration': 'enable', + 'allow_push_firmware': 'enable', + 'allow_remote_firmware_upgrade': 'enable', + 'enc_algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg_source_ip': 'test_value_9', + 'fmg_source_ip6': 'test_value_10', + 'include_default_servers': 'enable', + 'mode': 'normal', + 'schedule_config_restore': 'enable', + 'schedule_script_restore': 'enable', + 'serial_number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance) + + expected_data = { + 'allow-monitor': 'enable', + 'allow-push-configuration': 'enable', + 'allow-push-firmware': 'enable', + 'allow-remote-firmware-upgrade': 'enable', + 'enc-algorithm': 'default', + 'fmg': 'test_value_8', + 'fmg-source-ip': 'test_value_9', + 'fmg-source-ip6': 'test_value_10', + 'include-default-servers': 'enable', + 'mode': 'normal', + 'schedule-config-restore': 'enable', + 'schedule-script-restore': 'enable', + 'serial-number': 'test_value_15', + 'type': 'fortimanager', + 'vdom': 'test_value_17' + } + + set_method_mock.assert_called_with('system', 'central-management', 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_system_dhcp_server.py b/test/units/modules/network/fortios/test_fortios_system_dhcp_server.py new file mode 100644 index 00000000000..8c97fcdfe79 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_dhcp_server.py @@ -0,0 +1,589 @@ +# 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_system_dhcp_server +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_dhcp_server.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_dhcp_server_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_dhcp_server': { + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + expected_data = { + 'auto-configuration': 'disable', + 'conflicted-ip-timeout': '4', + 'ddns-auth': 'disable', + 'ddns-key': 'test_value_6', + 'ddns-keyname': 'test_value_7', + 'ddns-server-ip': 'test_value_8', + 'ddns-ttl': '9', + 'ddns-update': 'disable', + 'ddns-update-override': 'disable', + 'ddns-zone': 'test_value_12', + 'default-gateway': 'test_value_13', + 'dns-server1': 'test_value_14', + 'dns-server2': 'test_value_15', + 'dns-server3': 'test_value_16', + 'dns-service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient-on-net-status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip-mode': 'range', + 'ipsec-lease-hold': '24', + 'lease-time': '25', + 'mac-acl-default-action': 'assign', + 'netmask': 'test_value_27', + 'next-server': 'test_value_28', + 'ntp-server1': 'test_value_29', + 'ntp-server2': 'test_value_30', + 'ntp-server3': 'test_value_31', + 'ntp-service': 'local', + 'server-type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone-option': 'disable', + 'vci-match': 'disable', + 'wifi-ac1': 'test_value_38', + 'wifi-ac2': 'test_value_39', + 'wifi-ac3': 'test_value_40', + 'wins-server1': 'test_value_41', + 'wins-server2': 'test_value_42' + } + + set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_system_dhcp_server_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_dhcp_server': { + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + expected_data = { + 'auto-configuration': 'disable', + 'conflicted-ip-timeout': '4', + 'ddns-auth': 'disable', + 'ddns-key': 'test_value_6', + 'ddns-keyname': 'test_value_7', + 'ddns-server-ip': 'test_value_8', + 'ddns-ttl': '9', + 'ddns-update': 'disable', + 'ddns-update-override': 'disable', + 'ddns-zone': 'test_value_12', + 'default-gateway': 'test_value_13', + 'dns-server1': 'test_value_14', + 'dns-server2': 'test_value_15', + 'dns-server3': 'test_value_16', + 'dns-service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient-on-net-status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip-mode': 'range', + 'ipsec-lease-hold': '24', + 'lease-time': '25', + 'mac-acl-default-action': 'assign', + 'netmask': 'test_value_27', + 'next-server': 'test_value_28', + 'ntp-server1': 'test_value_29', + 'ntp-server2': 'test_value_30', + 'ntp-server3': 'test_value_31', + 'ntp-service': 'local', + 'server-type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone-option': 'disable', + 'vci-match': 'disable', + 'wifi-ac1': 'test_value_38', + 'wifi-ac2': 'test_value_39', + 'wifi-ac3': 'test_value_40', + 'wins-server1': 'test_value_41', + 'wins-server2': 'test_value_42' + } + + set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_system_dhcp_server_removal(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'system_dhcp_server': { + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + delete_method_mock.assert_called_with('system.dhcp', 'server', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_system_dhcp_server_deletion_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result) + + input_data = { + 'username': 'admin', + 'state': 'absent', + 'system_dhcp_server': { + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + delete_method_mock.assert_called_with('system.dhcp', 'server', mkey=ANY, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_system_dhcp_server_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_dhcp_server': { + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + expected_data = { + 'auto-configuration': 'disable', + 'conflicted-ip-timeout': '4', + 'ddns-auth': 'disable', + 'ddns-key': 'test_value_6', + 'ddns-keyname': 'test_value_7', + 'ddns-server-ip': 'test_value_8', + 'ddns-ttl': '9', + 'ddns-update': 'disable', + 'ddns-update-override': 'disable', + 'ddns-zone': 'test_value_12', + 'default-gateway': 'test_value_13', + 'dns-server1': 'test_value_14', + 'dns-server2': 'test_value_15', + 'dns-server3': 'test_value_16', + 'dns-service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient-on-net-status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip-mode': 'range', + 'ipsec-lease-hold': '24', + 'lease-time': '25', + 'mac-acl-default-action': 'assign', + 'netmask': 'test_value_27', + 'next-server': 'test_value_28', + 'ntp-server1': 'test_value_29', + 'ntp-server2': 'test_value_30', + 'ntp-server3': 'test_value_31', + 'ntp-service': 'local', + 'server-type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone-option': 'disable', + 'vci-match': 'disable', + 'wifi-ac1': 'test_value_38', + 'wifi-ac2': 'test_value_39', + 'wifi-ac3': 'test_value_40', + 'wins-server1': 'test_value_41', + 'wins-server2': 'test_value_42' + } + + set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_system_dhcp_server_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_dhcp_server': { + 'random_attribute_not_valid': 'tag', + 'auto_configuration': 'disable', + 'conflicted_ip_timeout': '4', + 'ddns_auth': 'disable', + 'ddns_key': 'test_value_6', + 'ddns_keyname': 'test_value_7', + 'ddns_server_ip': 'test_value_8', + 'ddns_ttl': '9', + 'ddns_update': 'disable', + 'ddns_update_override': 'disable', + 'ddns_zone': 'test_value_12', + 'default_gateway': 'test_value_13', + 'dns_server1': 'test_value_14', + 'dns_server2': 'test_value_15', + 'dns_server3': 'test_value_16', + 'dns_service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient_on_net_status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip_mode': 'range', + 'ipsec_lease_hold': '24', + 'lease_time': '25', + 'mac_acl_default_action': 'assign', + 'netmask': 'test_value_27', + 'next_server': 'test_value_28', + 'ntp_server1': 'test_value_29', + 'ntp_server2': 'test_value_30', + 'ntp_server3': 'test_value_31', + 'ntp_service': 'local', + 'server_type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone_option': 'disable', + 'vci_match': 'disable', + 'wifi_ac1': 'test_value_38', + 'wifi_ac2': 'test_value_39', + 'wifi_ac3': 'test_value_40', + 'wins_server1': 'test_value_41', + 'wins_server2': 'test_value_42' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance) + + expected_data = { + 'auto-configuration': 'disable', + 'conflicted-ip-timeout': '4', + 'ddns-auth': 'disable', + 'ddns-key': 'test_value_6', + 'ddns-keyname': 'test_value_7', + 'ddns-server-ip': 'test_value_8', + 'ddns-ttl': '9', + 'ddns-update': 'disable', + 'ddns-update-override': 'disable', + 'ddns-zone': 'test_value_12', + 'default-gateway': 'test_value_13', + 'dns-server1': 'test_value_14', + 'dns-server2': 'test_value_15', + 'dns-server3': 'test_value_16', + 'dns-service': 'local', + 'domain': 'test_value_18', + 'filename': 'test_value_19', + 'forticlient-on-net-status': 'disable', + 'id': '21', + 'interface': 'test_value_22', + 'ip-mode': 'range', + 'ipsec-lease-hold': '24', + 'lease-time': '25', + 'mac-acl-default-action': 'assign', + 'netmask': 'test_value_27', + 'next-server': 'test_value_28', + 'ntp-server1': 'test_value_29', + 'ntp-server2': 'test_value_30', + 'ntp-server3': 'test_value_31', + 'ntp-service': 'local', + 'server-type': 'regular', + 'status': 'disable', + 'timezone': '01', + 'timezone-option': 'disable', + 'vci-match': 'disable', + 'wifi-ac1': 'test_value_38', + 'wifi-ac2': 'test_value_39', + 'wifi-ac3': 'test_value_40', + 'wins-server1': 'test_value_41', + 'wins-server2': 'test_value_42' + } + + set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 diff --git a/test/units/modules/network/fortios/test_fortios_system_dns.py b/test/units/modules/network/fortios/test_fortios_system_dns.py new file mode 100644 index 00000000000..0cede4e2837 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_dns.py @@ -0,0 +1,223 @@ +# 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_system_dns +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_system_dns.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_dns_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', + 'system_dns': { + 'cache_notfound_responses': 'disable', + 'dns_cache_limit': '4', + 'dns_cache_ttl': '5', + 'ip6_primary': 'test_value_6', + 'ip6_secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source_ip': '84.230.14.11', + 'timeout': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance) + + expected_data = { + 'cache-notfound-responses': 'disable', + 'dns-cache-limit': '4', + 'dns-cache-ttl': '5', + 'ip6-primary': 'test_value_6', + 'ip6-secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source-ip': '84.230.14.11', + 'timeout': '12' + } + + set_method_mock.assert_called_with('system', 'dns', 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_system_dns_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', + 'system_dns': { + 'cache_notfound_responses': 'disable', + 'dns_cache_limit': '4', + 'dns_cache_ttl': '5', + 'ip6_primary': 'test_value_6', + 'ip6_secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source_ip': '84.230.14.11', + 'timeout': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance) + + expected_data = { + 'cache-notfound-responses': 'disable', + 'dns-cache-limit': '4', + 'dns-cache-ttl': '5', + 'ip6-primary': 'test_value_6', + 'ip6-secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source-ip': '84.230.14.11', + 'timeout': '12' + } + + set_method_mock.assert_called_with('system', 'dns', 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_system_dns_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', + 'system_dns': { + 'cache_notfound_responses': 'disable', + 'dns_cache_limit': '4', + 'dns_cache_ttl': '5', + 'ip6_primary': 'test_value_6', + 'ip6_secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source_ip': '84.230.14.11', + 'timeout': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance) + + expected_data = { + 'cache-notfound-responses': 'disable', + 'dns-cache-limit': '4', + 'dns-cache-ttl': '5', + 'ip6-primary': 'test_value_6', + 'ip6-secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source-ip': '84.230.14.11', + 'timeout': '12' + } + + set_method_mock.assert_called_with('system', 'dns', 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_system_dns_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', + 'system_dns': { + 'random_attribute_not_valid': 'tag', + 'cache_notfound_responses': 'disable', + 'dns_cache_limit': '4', + 'dns_cache_ttl': '5', + 'ip6_primary': 'test_value_6', + 'ip6_secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source_ip': '84.230.14.11', + 'timeout': '12' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance) + + expected_data = { + 'cache-notfound-responses': 'disable', + 'dns-cache-limit': '4', + 'dns-cache-ttl': '5', + 'ip6-primary': 'test_value_6', + 'ip6-secondary': 'test_value_7', + 'primary': 'test_value_8', + 'retry': '9', + 'secondary': 'test_value_10', + 'source-ip': '84.230.14.11', + 'timeout': '12' + } + + set_method_mock.assert_called_with('system', 'dns', 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_system_global.py b/test/units/modules/network/fortios/test_fortios_system_global.py new file mode 100644 index 00000000000..7f3742e08ef --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_global.py @@ -0,0 +1,1559 @@ +# 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_system_global +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_system_global.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_global_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', + 'system_global': { + 'admin_concurrent': 'enable', + 'admin_console_timeout': '4', + 'admin_https_pki_required': 'enable', + 'admin_lockout_duration': '6', + 'admin_lockout_threshold': '7', + 'admin_login_max': '8', + 'admin_maintainer': 'enable', + 'admin_port': '10', + 'admin_restrict_local': 'enable', + 'admin_scp': 'enable', + 'admin_server_cert': 'test_value_13', + 'admin_sport': '14', + 'admin_ssh_grace_time': '15', + 'admin_ssh_password': 'enable', + 'admin_ssh_port': '17', + 'admin_ssh_v1': 'enable', + 'admin_telnet_port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow_traffic_redirect': 'enable', + 'anti_replay': 'disable', + 'arp_max_entry': '24', + 'asymroute': 'enable', + 'auth_cert': 'test_value_26', + 'auth_http_port': '27', + 'auth_https_port': '28', + 'auth_keepalive': 'enable', + 'auth_session_limit': 'block-new', + 'auto_auth_extension_device': 'enable', + 'av_affinity': 'test_value_32', + 'av_failopen': 'pass', + 'av_failopen_session': 'enable', + 'batch_cmdb': 'enable', + 'block_session_timer': '36', + 'br_fdb_max_entry': '37', + 'cert_chain_max': '38', + 'cfg_revert_timeout': '39', + 'cfg_save': 'automatic', + 'check_protocol_header': 'loose', + 'check_reset_range': 'strict', + 'cli_audit_log': 'enable', + 'clt_cert_req': 'enable', + 'compliance_check': 'enable', + 'compliance_check_time': 'test_value_46', + 'cpu_use_threshold': '47', + 'csr_ca_attribute': 'enable', + 'daily_restart': 'enable', + 'device_identification_active_scan_delay': '50', + 'device_idle_timeout': '51', + 'dh_params': '1024', + 'dnsproxy_worker_count': '53', + 'dst': 'enable', + 'endpoint_control_fds_access': 'enable', + 'endpoint_control_portal_port': '56', + 'failtime': '57', + 'fds_statistics': 'enable', + 'fds_statistics_period': '59', + 'fgd_alert_subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender_data_port': '62', + 'fortiextender_vlan_mode': 'enable', + 'fortiservice_port': '64', + 'gui_certificates': 'enable', + 'gui_custom_language': 'enable', + 'gui_date_format': 'yyyy/MM/dd', + 'gui_device_latitude': 'test_value_68', + 'gui_device_longitude': 'test_value_69', + 'gui_display_hostname': 'enable', + 'gui_ipv6': 'enable', + 'gui_lines_per_page': '72', + 'gui_theme': 'green', + 'gui_wireless_opensecurity': 'enable', + 'honor_df': 'enable', + 'hostname': 'myhostname76', + 'igmp_state_limit': '77', + 'interval': '78', + 'ip_src_port_range': 'test_value_79', + 'ips_affinity': 'test_value_80', + 'ipsec_asic_offload': 'enable', + 'ipsec_hmac_offload': 'enable', + 'ipsec_soft_dec_async': 'enable', + 'ipv6_accept_dad': '84', + 'ipv6_allow_anycast_probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp_transmission': 'enable', + 'log_ssl_connection': 'enable', + 'log_uuid': 'disable', + 'login_timestamp': 'enable', + 'long_vdom_name': 'enable', + 'management_vdom': 'test_value_93', + 'max_dlpstat_memory': '94', + 'max_route_cache_size': '95', + 'mc_ttl_notchange': 'enable', + 'memory_use_threshold_extreme': '97', + 'memory_use_threshold_green': '98', + 'memory_use_threshold_red': '99', + 'miglog_affinity': 'test_value_100', + 'miglogd_children': '101', + 'multi_factor_authentication': 'optional', + 'multicast_forward': 'enable', + 'ndp_max_entry': '104', + 'per_user_bwl': 'enable', + 'policy_auth_concurrent': '106', + 'post_login_banner': 'disable', + 'pre_login_banner': 'enable', + 'private_data_encryption': 'disable', + 'proxy_auth_lifetime': 'enable', + 'proxy_auth_lifetime_timeout': '111', + 'proxy_auth_timeout': '112', + 'proxy_cipher_hardware_acceleration': 'disable', + 'proxy_kxp_hardware_acceleration': 'disable', + 'proxy_re_authentication_mode': 'session', + 'proxy_worker_count': '116', + 'radius_port': '117', + 'reboot_upon_config_restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset_sessionless_tcp': 'enable', + 'restart_time': 'test_value_122', + 'revision_backup_on_logout': 'enable', + 'revision_image_auto_backup': 'enable', + 'scanunit_count': '125', + 'security_rating_result_submission': 'enable', + 'security_rating_run_on_schedule': 'enable', + 'send_pmtu_icmp': 'enable', + 'snat_route_change': 'enable', + 'special_file_23_support': 'disable', + 'ssd_trim_date': '131', + 'ssd_trim_freq': 'never', + 'ssd_trim_hour': '133', + 'ssd_trim_min': '134', + 'ssd_trim_weekday': 'sunday', + 'ssh_cbc_cipher': 'enable', + 'ssh_hmac_md5': 'enable', + 'ssh_kex_sha1': 'enable', + 'ssl_min_proto_version': 'SSLv3', + 'ssl_static_key_ciphers': 'enable', + 'sslvpn_cipher_hardware_acceleration': 'enable', + 'sslvpn_kxp_hardware_acceleration': 'enable', + 'sslvpn_max_worker_count': '143', + 'sslvpn_plugin_version_check': 'enable', + 'strict_dirty_session_check': 'enable', + 'strong_crypto': 'enable', + 'switch_controller': 'disable', + 'switch_controller_reserved_network': 'test_value_148', + 'sys_perf_log_interval': '149', + 'tcp_halfclose_timer': '150', + 'tcp_halfopen_timer': '151', + 'tcp_option': 'enable', + 'tcp_timewait_timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp_mc_skip_policy': 'enable', + 'traffic_priority': 'tos', + 'traffic_priority_level': 'low', + 'two_factor_email_expiry': '159', + 'two_factor_fac_expiry': '160', + 'two_factor_ftk_expiry': '161', + 'two_factor_ftm_expiry': '162', + 'two_factor_sms_expiry': '163', + 'udp_idle_timer': '164', + 'user_server_cert': 'test_value_165', + 'vdom_admin': 'enable', + 'vip_arp_range': 'unlimited', + 'virtual_server_count': '168', + 'virtual_server_hardware_acceleration': 'disable', + 'wad_affinity': 'test_value_170', + 'wad_csvc_cs_count': '171', + 'wad_csvc_db_count': '172', + 'wad_source_affinity': 'disable', + 'wad_worker_count': '174', + 'wifi_ca_certificate': 'test_value_175', + 'wifi_certificate': 'test_value_176', + 'wimax_4g_usb': 'enable', + 'wireless_controller': 'enable', + 'wireless_controller_port': '179' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_global.fortios_system(input_data, fos_instance) + + expected_data = { + 'admin-concurrent': 'enable', + 'admin-console-timeout': '4', + 'admin-https-pki-required': 'enable', + 'admin-lockout-duration': '6', + 'admin-lockout-threshold': '7', + 'admin-login-max': '8', + 'admin-maintainer': 'enable', + 'admin-port': '10', + 'admin-restrict-local': 'enable', + 'admin-scp': 'enable', + 'admin-server-cert': 'test_value_13', + 'admin-sport': '14', + 'admin-ssh-grace-time': '15', + 'admin-ssh-password': 'enable', + 'admin-ssh-port': '17', + 'admin-ssh-v1': 'enable', + 'admin-telnet-port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow-traffic-redirect': 'enable', + 'anti-replay': 'disable', + 'arp-max-entry': '24', + 'asymroute': 'enable', + 'auth-cert': 'test_value_26', + 'auth-http-port': '27', + 'auth-https-port': '28', + 'auth-keepalive': 'enable', + 'auth-session-limit': 'block-new', + 'auto-auth-extension-device': 'enable', + 'av-affinity': 'test_value_32', + 'av-failopen': 'pass', + 'av-failopen-session': 'enable', + 'batch-cmdb': 'enable', + 'block-session-timer': '36', + 'br-fdb-max-entry': '37', + 'cert-chain-max': '38', + 'cfg-revert-timeout': '39', + 'cfg-save': 'automatic', + 'check-protocol-header': 'loose', + 'check-reset-range': 'strict', + 'cli-audit-log': 'enable', + 'clt-cert-req': 'enable', + 'compliance-check': 'enable', + 'compliance-check-time': 'test_value_46', + 'cpu-use-threshold': '47', + 'csr-ca-attribute': 'enable', + 'daily-restart': 'enable', + 'device-identification-active-scan-delay': '50', + 'device-idle-timeout': '51', + 'dh-params': '1024', + 'dnsproxy-worker-count': '53', + 'dst': 'enable', + 'endpoint-control-fds-access': 'enable', + 'endpoint-control-portal-port': '56', + 'failtime': '57', + 'fds-statistics': 'enable', + 'fds-statistics-period': '59', + 'fgd-alert-subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender-data-port': '62', + 'fortiextender-vlan-mode': 'enable', + 'fortiservice-port': '64', + 'gui-certificates': 'enable', + 'gui-custom-language': 'enable', + 'gui-date-format': 'yyyy/MM/dd', + 'gui-device-latitude': 'test_value_68', + 'gui-device-longitude': 'test_value_69', + 'gui-display-hostname': 'enable', + 'gui-ipv6': 'enable', + 'gui-lines-per-page': '72', + 'gui-theme': 'green', + 'gui-wireless-opensecurity': 'enable', + 'honor-df': 'enable', + 'hostname': 'myhostname76', + 'igmp-state-limit': '77', + 'interval': '78', + 'ip-src-port-range': 'test_value_79', + 'ips-affinity': 'test_value_80', + 'ipsec-asic-offload': 'enable', + 'ipsec-hmac-offload': 'enable', + 'ipsec-soft-dec-async': 'enable', + 'ipv6-accept-dad': '84', + 'ipv6-allow-anycast-probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp-transmission': 'enable', + 'log-ssl-connection': 'enable', + 'log-uuid': 'disable', + 'login-timestamp': 'enable', + 'long-vdom-name': 'enable', + 'management-vdom': 'test_value_93', + 'max-dlpstat-memory': '94', + 'max-route-cache-size': '95', + 'mc-ttl-notchange': 'enable', + 'memory-use-threshold-extreme': '97', + 'memory-use-threshold-green': '98', + 'memory-use-threshold-red': '99', + 'miglog-affinity': 'test_value_100', + 'miglogd-children': '101', + 'multi-factor-authentication': 'optional', + 'multicast-forward': 'enable', + 'ndp-max-entry': '104', + 'per-user-bwl': 'enable', + 'policy-auth-concurrent': '106', + 'post-login-banner': 'disable', + 'pre-login-banner': 'enable', + 'private-data-encryption': 'disable', + 'proxy-auth-lifetime': 'enable', + 'proxy-auth-lifetime-timeout': '111', + 'proxy-auth-timeout': '112', + 'proxy-cipher-hardware-acceleration': 'disable', + 'proxy-kxp-hardware-acceleration': 'disable', + 'proxy-re-authentication-mode': 'session', + 'proxy-worker-count': '116', + 'radius-port': '117', + 'reboot-upon-config-restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset-sessionless-tcp': 'enable', + 'restart-time': 'test_value_122', + 'revision-backup-on-logout': 'enable', + 'revision-image-auto-backup': 'enable', + 'scanunit-count': '125', + 'security-rating-result-submission': 'enable', + 'security-rating-run-on-schedule': 'enable', + 'send-pmtu-icmp': 'enable', + 'snat-route-change': 'enable', + 'special-file-23-support': 'disable', + 'ssd-trim-date': '131', + 'ssd-trim-freq': 'never', + 'ssd-trim-hour': '133', + 'ssd-trim-min': '134', + 'ssd-trim-weekday': 'sunday', + 'ssh-cbc-cipher': 'enable', + 'ssh-hmac-md5': 'enable', + 'ssh-kex-sha1': 'enable', + 'ssl-min-proto-version': 'SSLv3', + 'ssl-static-key-ciphers': 'enable', + 'sslvpn-cipher-hardware-acceleration': 'enable', + 'sslvpn-kxp-hardware-acceleration': 'enable', + 'sslvpn-max-worker-count': '143', + 'sslvpn-plugin-version-check': 'enable', + 'strict-dirty-session-check': 'enable', + 'strong-crypto': 'enable', + 'switch-controller': 'disable', + 'switch-controller-reserved-network': 'test_value_148', + 'sys-perf-log-interval': '149', + 'tcp-halfclose-timer': '150', + 'tcp-halfopen-timer': '151', + 'tcp-option': 'enable', + 'tcp-timewait-timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp-mc-skip-policy': 'enable', + 'traffic-priority': 'tos', + 'traffic-priority-level': 'low', + 'two-factor-email-expiry': '159', + 'two-factor-fac-expiry': '160', + 'two-factor-ftk-expiry': '161', + 'two-factor-ftm-expiry': '162', + 'two-factor-sms-expiry': '163', + 'udp-idle-timer': '164', + 'user-server-cert': 'test_value_165', + 'vdom-admin': 'enable', + 'vip-arp-range': 'unlimited', + 'virtual-server-count': '168', + 'virtual-server-hardware-acceleration': 'disable', + 'wad-affinity': 'test_value_170', + 'wad-csvc-cs-count': '171', + 'wad-csvc-db-count': '172', + 'wad-source-affinity': 'disable', + 'wad-worker-count': '174', + 'wifi-ca-certificate': 'test_value_175', + 'wifi-certificate': 'test_value_176', + 'wimax-4g-usb': 'enable', + 'wireless-controller': 'enable', + 'wireless-controller-port': '179' + } + + set_method_mock.assert_called_with('system', 'global', 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_system_global_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', + 'system_global': { + 'admin_concurrent': 'enable', + 'admin_console_timeout': '4', + 'admin_https_pki_required': 'enable', + 'admin_lockout_duration': '6', + 'admin_lockout_threshold': '7', + 'admin_login_max': '8', + 'admin_maintainer': 'enable', + 'admin_port': '10', + 'admin_restrict_local': 'enable', + 'admin_scp': 'enable', + 'admin_server_cert': 'test_value_13', + 'admin_sport': '14', + 'admin_ssh_grace_time': '15', + 'admin_ssh_password': 'enable', + 'admin_ssh_port': '17', + 'admin_ssh_v1': 'enable', + 'admin_telnet_port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow_traffic_redirect': 'enable', + 'anti_replay': 'disable', + 'arp_max_entry': '24', + 'asymroute': 'enable', + 'auth_cert': 'test_value_26', + 'auth_http_port': '27', + 'auth_https_port': '28', + 'auth_keepalive': 'enable', + 'auth_session_limit': 'block-new', + 'auto_auth_extension_device': 'enable', + 'av_affinity': 'test_value_32', + 'av_failopen': 'pass', + 'av_failopen_session': 'enable', + 'batch_cmdb': 'enable', + 'block_session_timer': '36', + 'br_fdb_max_entry': '37', + 'cert_chain_max': '38', + 'cfg_revert_timeout': '39', + 'cfg_save': 'automatic', + 'check_protocol_header': 'loose', + 'check_reset_range': 'strict', + 'cli_audit_log': 'enable', + 'clt_cert_req': 'enable', + 'compliance_check': 'enable', + 'compliance_check_time': 'test_value_46', + 'cpu_use_threshold': '47', + 'csr_ca_attribute': 'enable', + 'daily_restart': 'enable', + 'device_identification_active_scan_delay': '50', + 'device_idle_timeout': '51', + 'dh_params': '1024', + 'dnsproxy_worker_count': '53', + 'dst': 'enable', + 'endpoint_control_fds_access': 'enable', + 'endpoint_control_portal_port': '56', + 'failtime': '57', + 'fds_statistics': 'enable', + 'fds_statistics_period': '59', + 'fgd_alert_subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender_data_port': '62', + 'fortiextender_vlan_mode': 'enable', + 'fortiservice_port': '64', + 'gui_certificates': 'enable', + 'gui_custom_language': 'enable', + 'gui_date_format': 'yyyy/MM/dd', + 'gui_device_latitude': 'test_value_68', + 'gui_device_longitude': 'test_value_69', + 'gui_display_hostname': 'enable', + 'gui_ipv6': 'enable', + 'gui_lines_per_page': '72', + 'gui_theme': 'green', + 'gui_wireless_opensecurity': 'enable', + 'honor_df': 'enable', + 'hostname': 'myhostname76', + 'igmp_state_limit': '77', + 'interval': '78', + 'ip_src_port_range': 'test_value_79', + 'ips_affinity': 'test_value_80', + 'ipsec_asic_offload': 'enable', + 'ipsec_hmac_offload': 'enable', + 'ipsec_soft_dec_async': 'enable', + 'ipv6_accept_dad': '84', + 'ipv6_allow_anycast_probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp_transmission': 'enable', + 'log_ssl_connection': 'enable', + 'log_uuid': 'disable', + 'login_timestamp': 'enable', + 'long_vdom_name': 'enable', + 'management_vdom': 'test_value_93', + 'max_dlpstat_memory': '94', + 'max_route_cache_size': '95', + 'mc_ttl_notchange': 'enable', + 'memory_use_threshold_extreme': '97', + 'memory_use_threshold_green': '98', + 'memory_use_threshold_red': '99', + 'miglog_affinity': 'test_value_100', + 'miglogd_children': '101', + 'multi_factor_authentication': 'optional', + 'multicast_forward': 'enable', + 'ndp_max_entry': '104', + 'per_user_bwl': 'enable', + 'policy_auth_concurrent': '106', + 'post_login_banner': 'disable', + 'pre_login_banner': 'enable', + 'private_data_encryption': 'disable', + 'proxy_auth_lifetime': 'enable', + 'proxy_auth_lifetime_timeout': '111', + 'proxy_auth_timeout': '112', + 'proxy_cipher_hardware_acceleration': 'disable', + 'proxy_kxp_hardware_acceleration': 'disable', + 'proxy_re_authentication_mode': 'session', + 'proxy_worker_count': '116', + 'radius_port': '117', + 'reboot_upon_config_restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset_sessionless_tcp': 'enable', + 'restart_time': 'test_value_122', + 'revision_backup_on_logout': 'enable', + 'revision_image_auto_backup': 'enable', + 'scanunit_count': '125', + 'security_rating_result_submission': 'enable', + 'security_rating_run_on_schedule': 'enable', + 'send_pmtu_icmp': 'enable', + 'snat_route_change': 'enable', + 'special_file_23_support': 'disable', + 'ssd_trim_date': '131', + 'ssd_trim_freq': 'never', + 'ssd_trim_hour': '133', + 'ssd_trim_min': '134', + 'ssd_trim_weekday': 'sunday', + 'ssh_cbc_cipher': 'enable', + 'ssh_hmac_md5': 'enable', + 'ssh_kex_sha1': 'enable', + 'ssl_min_proto_version': 'SSLv3', + 'ssl_static_key_ciphers': 'enable', + 'sslvpn_cipher_hardware_acceleration': 'enable', + 'sslvpn_kxp_hardware_acceleration': 'enable', + 'sslvpn_max_worker_count': '143', + 'sslvpn_plugin_version_check': 'enable', + 'strict_dirty_session_check': 'enable', + 'strong_crypto': 'enable', + 'switch_controller': 'disable', + 'switch_controller_reserved_network': 'test_value_148', + 'sys_perf_log_interval': '149', + 'tcp_halfclose_timer': '150', + 'tcp_halfopen_timer': '151', + 'tcp_option': 'enable', + 'tcp_timewait_timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp_mc_skip_policy': 'enable', + 'traffic_priority': 'tos', + 'traffic_priority_level': 'low', + 'two_factor_email_expiry': '159', + 'two_factor_fac_expiry': '160', + 'two_factor_ftk_expiry': '161', + 'two_factor_ftm_expiry': '162', + 'two_factor_sms_expiry': '163', + 'udp_idle_timer': '164', + 'user_server_cert': 'test_value_165', + 'vdom_admin': 'enable', + 'vip_arp_range': 'unlimited', + 'virtual_server_count': '168', + 'virtual_server_hardware_acceleration': 'disable', + 'wad_affinity': 'test_value_170', + 'wad_csvc_cs_count': '171', + 'wad_csvc_db_count': '172', + 'wad_source_affinity': 'disable', + 'wad_worker_count': '174', + 'wifi_ca_certificate': 'test_value_175', + 'wifi_certificate': 'test_value_176', + 'wimax_4g_usb': 'enable', + 'wireless_controller': 'enable', + 'wireless_controller_port': '179' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_global.fortios_system(input_data, fos_instance) + + expected_data = { + 'admin-concurrent': 'enable', + 'admin-console-timeout': '4', + 'admin-https-pki-required': 'enable', + 'admin-lockout-duration': '6', + 'admin-lockout-threshold': '7', + 'admin-login-max': '8', + 'admin-maintainer': 'enable', + 'admin-port': '10', + 'admin-restrict-local': 'enable', + 'admin-scp': 'enable', + 'admin-server-cert': 'test_value_13', + 'admin-sport': '14', + 'admin-ssh-grace-time': '15', + 'admin-ssh-password': 'enable', + 'admin-ssh-port': '17', + 'admin-ssh-v1': 'enable', + 'admin-telnet-port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow-traffic-redirect': 'enable', + 'anti-replay': 'disable', + 'arp-max-entry': '24', + 'asymroute': 'enable', + 'auth-cert': 'test_value_26', + 'auth-http-port': '27', + 'auth-https-port': '28', + 'auth-keepalive': 'enable', + 'auth-session-limit': 'block-new', + 'auto-auth-extension-device': 'enable', + 'av-affinity': 'test_value_32', + 'av-failopen': 'pass', + 'av-failopen-session': 'enable', + 'batch-cmdb': 'enable', + 'block-session-timer': '36', + 'br-fdb-max-entry': '37', + 'cert-chain-max': '38', + 'cfg-revert-timeout': '39', + 'cfg-save': 'automatic', + 'check-protocol-header': 'loose', + 'check-reset-range': 'strict', + 'cli-audit-log': 'enable', + 'clt-cert-req': 'enable', + 'compliance-check': 'enable', + 'compliance-check-time': 'test_value_46', + 'cpu-use-threshold': '47', + 'csr-ca-attribute': 'enable', + 'daily-restart': 'enable', + 'device-identification-active-scan-delay': '50', + 'device-idle-timeout': '51', + 'dh-params': '1024', + 'dnsproxy-worker-count': '53', + 'dst': 'enable', + 'endpoint-control-fds-access': 'enable', + 'endpoint-control-portal-port': '56', + 'failtime': '57', + 'fds-statistics': 'enable', + 'fds-statistics-period': '59', + 'fgd-alert-subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender-data-port': '62', + 'fortiextender-vlan-mode': 'enable', + 'fortiservice-port': '64', + 'gui-certificates': 'enable', + 'gui-custom-language': 'enable', + 'gui-date-format': 'yyyy/MM/dd', + 'gui-device-latitude': 'test_value_68', + 'gui-device-longitude': 'test_value_69', + 'gui-display-hostname': 'enable', + 'gui-ipv6': 'enable', + 'gui-lines-per-page': '72', + 'gui-theme': 'green', + 'gui-wireless-opensecurity': 'enable', + 'honor-df': 'enable', + 'hostname': 'myhostname76', + 'igmp-state-limit': '77', + 'interval': '78', + 'ip-src-port-range': 'test_value_79', + 'ips-affinity': 'test_value_80', + 'ipsec-asic-offload': 'enable', + 'ipsec-hmac-offload': 'enable', + 'ipsec-soft-dec-async': 'enable', + 'ipv6-accept-dad': '84', + 'ipv6-allow-anycast-probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp-transmission': 'enable', + 'log-ssl-connection': 'enable', + 'log-uuid': 'disable', + 'login-timestamp': 'enable', + 'long-vdom-name': 'enable', + 'management-vdom': 'test_value_93', + 'max-dlpstat-memory': '94', + 'max-route-cache-size': '95', + 'mc-ttl-notchange': 'enable', + 'memory-use-threshold-extreme': '97', + 'memory-use-threshold-green': '98', + 'memory-use-threshold-red': '99', + 'miglog-affinity': 'test_value_100', + 'miglogd-children': '101', + 'multi-factor-authentication': 'optional', + 'multicast-forward': 'enable', + 'ndp-max-entry': '104', + 'per-user-bwl': 'enable', + 'policy-auth-concurrent': '106', + 'post-login-banner': 'disable', + 'pre-login-banner': 'enable', + 'private-data-encryption': 'disable', + 'proxy-auth-lifetime': 'enable', + 'proxy-auth-lifetime-timeout': '111', + 'proxy-auth-timeout': '112', + 'proxy-cipher-hardware-acceleration': 'disable', + 'proxy-kxp-hardware-acceleration': 'disable', + 'proxy-re-authentication-mode': 'session', + 'proxy-worker-count': '116', + 'radius-port': '117', + 'reboot-upon-config-restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset-sessionless-tcp': 'enable', + 'restart-time': 'test_value_122', + 'revision-backup-on-logout': 'enable', + 'revision-image-auto-backup': 'enable', + 'scanunit-count': '125', + 'security-rating-result-submission': 'enable', + 'security-rating-run-on-schedule': 'enable', + 'send-pmtu-icmp': 'enable', + 'snat-route-change': 'enable', + 'special-file-23-support': 'disable', + 'ssd-trim-date': '131', + 'ssd-trim-freq': 'never', + 'ssd-trim-hour': '133', + 'ssd-trim-min': '134', + 'ssd-trim-weekday': 'sunday', + 'ssh-cbc-cipher': 'enable', + 'ssh-hmac-md5': 'enable', + 'ssh-kex-sha1': 'enable', + 'ssl-min-proto-version': 'SSLv3', + 'ssl-static-key-ciphers': 'enable', + 'sslvpn-cipher-hardware-acceleration': 'enable', + 'sslvpn-kxp-hardware-acceleration': 'enable', + 'sslvpn-max-worker-count': '143', + 'sslvpn-plugin-version-check': 'enable', + 'strict-dirty-session-check': 'enable', + 'strong-crypto': 'enable', + 'switch-controller': 'disable', + 'switch-controller-reserved-network': 'test_value_148', + 'sys-perf-log-interval': '149', + 'tcp-halfclose-timer': '150', + 'tcp-halfopen-timer': '151', + 'tcp-option': 'enable', + 'tcp-timewait-timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp-mc-skip-policy': 'enable', + 'traffic-priority': 'tos', + 'traffic-priority-level': 'low', + 'two-factor-email-expiry': '159', + 'two-factor-fac-expiry': '160', + 'two-factor-ftk-expiry': '161', + 'two-factor-ftm-expiry': '162', + 'two-factor-sms-expiry': '163', + 'udp-idle-timer': '164', + 'user-server-cert': 'test_value_165', + 'vdom-admin': 'enable', + 'vip-arp-range': 'unlimited', + 'virtual-server-count': '168', + 'virtual-server-hardware-acceleration': 'disable', + 'wad-affinity': 'test_value_170', + 'wad-csvc-cs-count': '171', + 'wad-csvc-db-count': '172', + 'wad-source-affinity': 'disable', + 'wad-worker-count': '174', + 'wifi-ca-certificate': 'test_value_175', + 'wifi-certificate': 'test_value_176', + 'wimax-4g-usb': 'enable', + 'wireless-controller': 'enable', + 'wireless-controller-port': '179' + } + + set_method_mock.assert_called_with('system', 'global', 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_system_global_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', + 'system_global': { + 'admin_concurrent': 'enable', + 'admin_console_timeout': '4', + 'admin_https_pki_required': 'enable', + 'admin_lockout_duration': '6', + 'admin_lockout_threshold': '7', + 'admin_login_max': '8', + 'admin_maintainer': 'enable', + 'admin_port': '10', + 'admin_restrict_local': 'enable', + 'admin_scp': 'enable', + 'admin_server_cert': 'test_value_13', + 'admin_sport': '14', + 'admin_ssh_grace_time': '15', + 'admin_ssh_password': 'enable', + 'admin_ssh_port': '17', + 'admin_ssh_v1': 'enable', + 'admin_telnet_port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow_traffic_redirect': 'enable', + 'anti_replay': 'disable', + 'arp_max_entry': '24', + 'asymroute': 'enable', + 'auth_cert': 'test_value_26', + 'auth_http_port': '27', + 'auth_https_port': '28', + 'auth_keepalive': 'enable', + 'auth_session_limit': 'block-new', + 'auto_auth_extension_device': 'enable', + 'av_affinity': 'test_value_32', + 'av_failopen': 'pass', + 'av_failopen_session': 'enable', + 'batch_cmdb': 'enable', + 'block_session_timer': '36', + 'br_fdb_max_entry': '37', + 'cert_chain_max': '38', + 'cfg_revert_timeout': '39', + 'cfg_save': 'automatic', + 'check_protocol_header': 'loose', + 'check_reset_range': 'strict', + 'cli_audit_log': 'enable', + 'clt_cert_req': 'enable', + 'compliance_check': 'enable', + 'compliance_check_time': 'test_value_46', + 'cpu_use_threshold': '47', + 'csr_ca_attribute': 'enable', + 'daily_restart': 'enable', + 'device_identification_active_scan_delay': '50', + 'device_idle_timeout': '51', + 'dh_params': '1024', + 'dnsproxy_worker_count': '53', + 'dst': 'enable', + 'endpoint_control_fds_access': 'enable', + 'endpoint_control_portal_port': '56', + 'failtime': '57', + 'fds_statistics': 'enable', + 'fds_statistics_period': '59', + 'fgd_alert_subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender_data_port': '62', + 'fortiextender_vlan_mode': 'enable', + 'fortiservice_port': '64', + 'gui_certificates': 'enable', + 'gui_custom_language': 'enable', + 'gui_date_format': 'yyyy/MM/dd', + 'gui_device_latitude': 'test_value_68', + 'gui_device_longitude': 'test_value_69', + 'gui_display_hostname': 'enable', + 'gui_ipv6': 'enable', + 'gui_lines_per_page': '72', + 'gui_theme': 'green', + 'gui_wireless_opensecurity': 'enable', + 'honor_df': 'enable', + 'hostname': 'myhostname76', + 'igmp_state_limit': '77', + 'interval': '78', + 'ip_src_port_range': 'test_value_79', + 'ips_affinity': 'test_value_80', + 'ipsec_asic_offload': 'enable', + 'ipsec_hmac_offload': 'enable', + 'ipsec_soft_dec_async': 'enable', + 'ipv6_accept_dad': '84', + 'ipv6_allow_anycast_probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp_transmission': 'enable', + 'log_ssl_connection': 'enable', + 'log_uuid': 'disable', + 'login_timestamp': 'enable', + 'long_vdom_name': 'enable', + 'management_vdom': 'test_value_93', + 'max_dlpstat_memory': '94', + 'max_route_cache_size': '95', + 'mc_ttl_notchange': 'enable', + 'memory_use_threshold_extreme': '97', + 'memory_use_threshold_green': '98', + 'memory_use_threshold_red': '99', + 'miglog_affinity': 'test_value_100', + 'miglogd_children': '101', + 'multi_factor_authentication': 'optional', + 'multicast_forward': 'enable', + 'ndp_max_entry': '104', + 'per_user_bwl': 'enable', + 'policy_auth_concurrent': '106', + 'post_login_banner': 'disable', + 'pre_login_banner': 'enable', + 'private_data_encryption': 'disable', + 'proxy_auth_lifetime': 'enable', + 'proxy_auth_lifetime_timeout': '111', + 'proxy_auth_timeout': '112', + 'proxy_cipher_hardware_acceleration': 'disable', + 'proxy_kxp_hardware_acceleration': 'disable', + 'proxy_re_authentication_mode': 'session', + 'proxy_worker_count': '116', + 'radius_port': '117', + 'reboot_upon_config_restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset_sessionless_tcp': 'enable', + 'restart_time': 'test_value_122', + 'revision_backup_on_logout': 'enable', + 'revision_image_auto_backup': 'enable', + 'scanunit_count': '125', + 'security_rating_result_submission': 'enable', + 'security_rating_run_on_schedule': 'enable', + 'send_pmtu_icmp': 'enable', + 'snat_route_change': 'enable', + 'special_file_23_support': 'disable', + 'ssd_trim_date': '131', + 'ssd_trim_freq': 'never', + 'ssd_trim_hour': '133', + 'ssd_trim_min': '134', + 'ssd_trim_weekday': 'sunday', + 'ssh_cbc_cipher': 'enable', + 'ssh_hmac_md5': 'enable', + 'ssh_kex_sha1': 'enable', + 'ssl_min_proto_version': 'SSLv3', + 'ssl_static_key_ciphers': 'enable', + 'sslvpn_cipher_hardware_acceleration': 'enable', + 'sslvpn_kxp_hardware_acceleration': 'enable', + 'sslvpn_max_worker_count': '143', + 'sslvpn_plugin_version_check': 'enable', + 'strict_dirty_session_check': 'enable', + 'strong_crypto': 'enable', + 'switch_controller': 'disable', + 'switch_controller_reserved_network': 'test_value_148', + 'sys_perf_log_interval': '149', + 'tcp_halfclose_timer': '150', + 'tcp_halfopen_timer': '151', + 'tcp_option': 'enable', + 'tcp_timewait_timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp_mc_skip_policy': 'enable', + 'traffic_priority': 'tos', + 'traffic_priority_level': 'low', + 'two_factor_email_expiry': '159', + 'two_factor_fac_expiry': '160', + 'two_factor_ftk_expiry': '161', + 'two_factor_ftm_expiry': '162', + 'two_factor_sms_expiry': '163', + 'udp_idle_timer': '164', + 'user_server_cert': 'test_value_165', + 'vdom_admin': 'enable', + 'vip_arp_range': 'unlimited', + 'virtual_server_count': '168', + 'virtual_server_hardware_acceleration': 'disable', + 'wad_affinity': 'test_value_170', + 'wad_csvc_cs_count': '171', + 'wad_csvc_db_count': '172', + 'wad_source_affinity': 'disable', + 'wad_worker_count': '174', + 'wifi_ca_certificate': 'test_value_175', + 'wifi_certificate': 'test_value_176', + 'wimax_4g_usb': 'enable', + 'wireless_controller': 'enable', + 'wireless_controller_port': '179' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_global.fortios_system(input_data, fos_instance) + + expected_data = { + 'admin-concurrent': 'enable', + 'admin-console-timeout': '4', + 'admin-https-pki-required': 'enable', + 'admin-lockout-duration': '6', + 'admin-lockout-threshold': '7', + 'admin-login-max': '8', + 'admin-maintainer': 'enable', + 'admin-port': '10', + 'admin-restrict-local': 'enable', + 'admin-scp': 'enable', + 'admin-server-cert': 'test_value_13', + 'admin-sport': '14', + 'admin-ssh-grace-time': '15', + 'admin-ssh-password': 'enable', + 'admin-ssh-port': '17', + 'admin-ssh-v1': 'enable', + 'admin-telnet-port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow-traffic-redirect': 'enable', + 'anti-replay': 'disable', + 'arp-max-entry': '24', + 'asymroute': 'enable', + 'auth-cert': 'test_value_26', + 'auth-http-port': '27', + 'auth-https-port': '28', + 'auth-keepalive': 'enable', + 'auth-session-limit': 'block-new', + 'auto-auth-extension-device': 'enable', + 'av-affinity': 'test_value_32', + 'av-failopen': 'pass', + 'av-failopen-session': 'enable', + 'batch-cmdb': 'enable', + 'block-session-timer': '36', + 'br-fdb-max-entry': '37', + 'cert-chain-max': '38', + 'cfg-revert-timeout': '39', + 'cfg-save': 'automatic', + 'check-protocol-header': 'loose', + 'check-reset-range': 'strict', + 'cli-audit-log': 'enable', + 'clt-cert-req': 'enable', + 'compliance-check': 'enable', + 'compliance-check-time': 'test_value_46', + 'cpu-use-threshold': '47', + 'csr-ca-attribute': 'enable', + 'daily-restart': 'enable', + 'device-identification-active-scan-delay': '50', + 'device-idle-timeout': '51', + 'dh-params': '1024', + 'dnsproxy-worker-count': '53', + 'dst': 'enable', + 'endpoint-control-fds-access': 'enable', + 'endpoint-control-portal-port': '56', + 'failtime': '57', + 'fds-statistics': 'enable', + 'fds-statistics-period': '59', + 'fgd-alert-subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender-data-port': '62', + 'fortiextender-vlan-mode': 'enable', + 'fortiservice-port': '64', + 'gui-certificates': 'enable', + 'gui-custom-language': 'enable', + 'gui-date-format': 'yyyy/MM/dd', + 'gui-device-latitude': 'test_value_68', + 'gui-device-longitude': 'test_value_69', + 'gui-display-hostname': 'enable', + 'gui-ipv6': 'enable', + 'gui-lines-per-page': '72', + 'gui-theme': 'green', + 'gui-wireless-opensecurity': 'enable', + 'honor-df': 'enable', + 'hostname': 'myhostname76', + 'igmp-state-limit': '77', + 'interval': '78', + 'ip-src-port-range': 'test_value_79', + 'ips-affinity': 'test_value_80', + 'ipsec-asic-offload': 'enable', + 'ipsec-hmac-offload': 'enable', + 'ipsec-soft-dec-async': 'enable', + 'ipv6-accept-dad': '84', + 'ipv6-allow-anycast-probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp-transmission': 'enable', + 'log-ssl-connection': 'enable', + 'log-uuid': 'disable', + 'login-timestamp': 'enable', + 'long-vdom-name': 'enable', + 'management-vdom': 'test_value_93', + 'max-dlpstat-memory': '94', + 'max-route-cache-size': '95', + 'mc-ttl-notchange': 'enable', + 'memory-use-threshold-extreme': '97', + 'memory-use-threshold-green': '98', + 'memory-use-threshold-red': '99', + 'miglog-affinity': 'test_value_100', + 'miglogd-children': '101', + 'multi-factor-authentication': 'optional', + 'multicast-forward': 'enable', + 'ndp-max-entry': '104', + 'per-user-bwl': 'enable', + 'policy-auth-concurrent': '106', + 'post-login-banner': 'disable', + 'pre-login-banner': 'enable', + 'private-data-encryption': 'disable', + 'proxy-auth-lifetime': 'enable', + 'proxy-auth-lifetime-timeout': '111', + 'proxy-auth-timeout': '112', + 'proxy-cipher-hardware-acceleration': 'disable', + 'proxy-kxp-hardware-acceleration': 'disable', + 'proxy-re-authentication-mode': 'session', + 'proxy-worker-count': '116', + 'radius-port': '117', + 'reboot-upon-config-restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset-sessionless-tcp': 'enable', + 'restart-time': 'test_value_122', + 'revision-backup-on-logout': 'enable', + 'revision-image-auto-backup': 'enable', + 'scanunit-count': '125', + 'security-rating-result-submission': 'enable', + 'security-rating-run-on-schedule': 'enable', + 'send-pmtu-icmp': 'enable', + 'snat-route-change': 'enable', + 'special-file-23-support': 'disable', + 'ssd-trim-date': '131', + 'ssd-trim-freq': 'never', + 'ssd-trim-hour': '133', + 'ssd-trim-min': '134', + 'ssd-trim-weekday': 'sunday', + 'ssh-cbc-cipher': 'enable', + 'ssh-hmac-md5': 'enable', + 'ssh-kex-sha1': 'enable', + 'ssl-min-proto-version': 'SSLv3', + 'ssl-static-key-ciphers': 'enable', + 'sslvpn-cipher-hardware-acceleration': 'enable', + 'sslvpn-kxp-hardware-acceleration': 'enable', + 'sslvpn-max-worker-count': '143', + 'sslvpn-plugin-version-check': 'enable', + 'strict-dirty-session-check': 'enable', + 'strong-crypto': 'enable', + 'switch-controller': 'disable', + 'switch-controller-reserved-network': 'test_value_148', + 'sys-perf-log-interval': '149', + 'tcp-halfclose-timer': '150', + 'tcp-halfopen-timer': '151', + 'tcp-option': 'enable', + 'tcp-timewait-timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp-mc-skip-policy': 'enable', + 'traffic-priority': 'tos', + 'traffic-priority-level': 'low', + 'two-factor-email-expiry': '159', + 'two-factor-fac-expiry': '160', + 'two-factor-ftk-expiry': '161', + 'two-factor-ftm-expiry': '162', + 'two-factor-sms-expiry': '163', + 'udp-idle-timer': '164', + 'user-server-cert': 'test_value_165', + 'vdom-admin': 'enable', + 'vip-arp-range': 'unlimited', + 'virtual-server-count': '168', + 'virtual-server-hardware-acceleration': 'disable', + 'wad-affinity': 'test_value_170', + 'wad-csvc-cs-count': '171', + 'wad-csvc-db-count': '172', + 'wad-source-affinity': 'disable', + 'wad-worker-count': '174', + 'wifi-ca-certificate': 'test_value_175', + 'wifi-certificate': 'test_value_176', + 'wimax-4g-usb': 'enable', + 'wireless-controller': 'enable', + 'wireless-controller-port': '179' + } + + set_method_mock.assert_called_with('system', 'global', 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_system_global_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', + 'system_global': { + 'random_attribute_not_valid': 'tag', + 'admin_concurrent': 'enable', + 'admin_console_timeout': '4', + 'admin_https_pki_required': 'enable', + 'admin_lockout_duration': '6', + 'admin_lockout_threshold': '7', + 'admin_login_max': '8', + 'admin_maintainer': 'enable', + 'admin_port': '10', + 'admin_restrict_local': 'enable', + 'admin_scp': 'enable', + 'admin_server_cert': 'test_value_13', + 'admin_sport': '14', + 'admin_ssh_grace_time': '15', + 'admin_ssh_password': 'enable', + 'admin_ssh_port': '17', + 'admin_ssh_v1': 'enable', + 'admin_telnet_port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow_traffic_redirect': 'enable', + 'anti_replay': 'disable', + 'arp_max_entry': '24', + 'asymroute': 'enable', + 'auth_cert': 'test_value_26', + 'auth_http_port': '27', + 'auth_https_port': '28', + 'auth_keepalive': 'enable', + 'auth_session_limit': 'block-new', + 'auto_auth_extension_device': 'enable', + 'av_affinity': 'test_value_32', + 'av_failopen': 'pass', + 'av_failopen_session': 'enable', + 'batch_cmdb': 'enable', + 'block_session_timer': '36', + 'br_fdb_max_entry': '37', + 'cert_chain_max': '38', + 'cfg_revert_timeout': '39', + 'cfg_save': 'automatic', + 'check_protocol_header': 'loose', + 'check_reset_range': 'strict', + 'cli_audit_log': 'enable', + 'clt_cert_req': 'enable', + 'compliance_check': 'enable', + 'compliance_check_time': 'test_value_46', + 'cpu_use_threshold': '47', + 'csr_ca_attribute': 'enable', + 'daily_restart': 'enable', + 'device_identification_active_scan_delay': '50', + 'device_idle_timeout': '51', + 'dh_params': '1024', + 'dnsproxy_worker_count': '53', + 'dst': 'enable', + 'endpoint_control_fds_access': 'enable', + 'endpoint_control_portal_port': '56', + 'failtime': '57', + 'fds_statistics': 'enable', + 'fds_statistics_period': '59', + 'fgd_alert_subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender_data_port': '62', + 'fortiextender_vlan_mode': 'enable', + 'fortiservice_port': '64', + 'gui_certificates': 'enable', + 'gui_custom_language': 'enable', + 'gui_date_format': 'yyyy/MM/dd', + 'gui_device_latitude': 'test_value_68', + 'gui_device_longitude': 'test_value_69', + 'gui_display_hostname': 'enable', + 'gui_ipv6': 'enable', + 'gui_lines_per_page': '72', + 'gui_theme': 'green', + 'gui_wireless_opensecurity': 'enable', + 'honor_df': 'enable', + 'hostname': 'myhostname76', + 'igmp_state_limit': '77', + 'interval': '78', + 'ip_src_port_range': 'test_value_79', + 'ips_affinity': 'test_value_80', + 'ipsec_asic_offload': 'enable', + 'ipsec_hmac_offload': 'enable', + 'ipsec_soft_dec_async': 'enable', + 'ipv6_accept_dad': '84', + 'ipv6_allow_anycast_probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp_transmission': 'enable', + 'log_ssl_connection': 'enable', + 'log_uuid': 'disable', + 'login_timestamp': 'enable', + 'long_vdom_name': 'enable', + 'management_vdom': 'test_value_93', + 'max_dlpstat_memory': '94', + 'max_route_cache_size': '95', + 'mc_ttl_notchange': 'enable', + 'memory_use_threshold_extreme': '97', + 'memory_use_threshold_green': '98', + 'memory_use_threshold_red': '99', + 'miglog_affinity': 'test_value_100', + 'miglogd_children': '101', + 'multi_factor_authentication': 'optional', + 'multicast_forward': 'enable', + 'ndp_max_entry': '104', + 'per_user_bwl': 'enable', + 'policy_auth_concurrent': '106', + 'post_login_banner': 'disable', + 'pre_login_banner': 'enable', + 'private_data_encryption': 'disable', + 'proxy_auth_lifetime': 'enable', + 'proxy_auth_lifetime_timeout': '111', + 'proxy_auth_timeout': '112', + 'proxy_cipher_hardware_acceleration': 'disable', + 'proxy_kxp_hardware_acceleration': 'disable', + 'proxy_re_authentication_mode': 'session', + 'proxy_worker_count': '116', + 'radius_port': '117', + 'reboot_upon_config_restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset_sessionless_tcp': 'enable', + 'restart_time': 'test_value_122', + 'revision_backup_on_logout': 'enable', + 'revision_image_auto_backup': 'enable', + 'scanunit_count': '125', + 'security_rating_result_submission': 'enable', + 'security_rating_run_on_schedule': 'enable', + 'send_pmtu_icmp': 'enable', + 'snat_route_change': 'enable', + 'special_file_23_support': 'disable', + 'ssd_trim_date': '131', + 'ssd_trim_freq': 'never', + 'ssd_trim_hour': '133', + 'ssd_trim_min': '134', + 'ssd_trim_weekday': 'sunday', + 'ssh_cbc_cipher': 'enable', + 'ssh_hmac_md5': 'enable', + 'ssh_kex_sha1': 'enable', + 'ssl_min_proto_version': 'SSLv3', + 'ssl_static_key_ciphers': 'enable', + 'sslvpn_cipher_hardware_acceleration': 'enable', + 'sslvpn_kxp_hardware_acceleration': 'enable', + 'sslvpn_max_worker_count': '143', + 'sslvpn_plugin_version_check': 'enable', + 'strict_dirty_session_check': 'enable', + 'strong_crypto': 'enable', + 'switch_controller': 'disable', + 'switch_controller_reserved_network': 'test_value_148', + 'sys_perf_log_interval': '149', + 'tcp_halfclose_timer': '150', + 'tcp_halfopen_timer': '151', + 'tcp_option': 'enable', + 'tcp_timewait_timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp_mc_skip_policy': 'enable', + 'traffic_priority': 'tos', + 'traffic_priority_level': 'low', + 'two_factor_email_expiry': '159', + 'two_factor_fac_expiry': '160', + 'two_factor_ftk_expiry': '161', + 'two_factor_ftm_expiry': '162', + 'two_factor_sms_expiry': '163', + 'udp_idle_timer': '164', + 'user_server_cert': 'test_value_165', + 'vdom_admin': 'enable', + 'vip_arp_range': 'unlimited', + 'virtual_server_count': '168', + 'virtual_server_hardware_acceleration': 'disable', + 'wad_affinity': 'test_value_170', + 'wad_csvc_cs_count': '171', + 'wad_csvc_db_count': '172', + 'wad_source_affinity': 'disable', + 'wad_worker_count': '174', + 'wifi_ca_certificate': 'test_value_175', + 'wifi_certificate': 'test_value_176', + 'wimax_4g_usb': 'enable', + 'wireless_controller': 'enable', + 'wireless_controller_port': '179' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_global.fortios_system(input_data, fos_instance) + + expected_data = { + 'admin-concurrent': 'enable', + 'admin-console-timeout': '4', + 'admin-https-pki-required': 'enable', + 'admin-lockout-duration': '6', + 'admin-lockout-threshold': '7', + 'admin-login-max': '8', + 'admin-maintainer': 'enable', + 'admin-port': '10', + 'admin-restrict-local': 'enable', + 'admin-scp': 'enable', + 'admin-server-cert': 'test_value_13', + 'admin-sport': '14', + 'admin-ssh-grace-time': '15', + 'admin-ssh-password': 'enable', + 'admin-ssh-port': '17', + 'admin-ssh-v1': 'enable', + 'admin-telnet-port': '19', + 'admintimeout': '20', + 'alias': 'test_value_21', + 'allow-traffic-redirect': 'enable', + 'anti-replay': 'disable', + 'arp-max-entry': '24', + 'asymroute': 'enable', + 'auth-cert': 'test_value_26', + 'auth-http-port': '27', + 'auth-https-port': '28', + 'auth-keepalive': 'enable', + 'auth-session-limit': 'block-new', + 'auto-auth-extension-device': 'enable', + 'av-affinity': 'test_value_32', + 'av-failopen': 'pass', + 'av-failopen-session': 'enable', + 'batch-cmdb': 'enable', + 'block-session-timer': '36', + 'br-fdb-max-entry': '37', + 'cert-chain-max': '38', + 'cfg-revert-timeout': '39', + 'cfg-save': 'automatic', + 'check-protocol-header': 'loose', + 'check-reset-range': 'strict', + 'cli-audit-log': 'enable', + 'clt-cert-req': 'enable', + 'compliance-check': 'enable', + 'compliance-check-time': 'test_value_46', + 'cpu-use-threshold': '47', + 'csr-ca-attribute': 'enable', + 'daily-restart': 'enable', + 'device-identification-active-scan-delay': '50', + 'device-idle-timeout': '51', + 'dh-params': '1024', + 'dnsproxy-worker-count': '53', + 'dst': 'enable', + 'endpoint-control-fds-access': 'enable', + 'endpoint-control-portal-port': '56', + 'failtime': '57', + 'fds-statistics': 'enable', + 'fds-statistics-period': '59', + 'fgd-alert-subscription': 'advisory', + 'fortiextender': 'enable', + 'fortiextender-data-port': '62', + 'fortiextender-vlan-mode': 'enable', + 'fortiservice-port': '64', + 'gui-certificates': 'enable', + 'gui-custom-language': 'enable', + 'gui-date-format': 'yyyy/MM/dd', + 'gui-device-latitude': 'test_value_68', + 'gui-device-longitude': 'test_value_69', + 'gui-display-hostname': 'enable', + 'gui-ipv6': 'enable', + 'gui-lines-per-page': '72', + 'gui-theme': 'green', + 'gui-wireless-opensecurity': 'enable', + 'honor-df': 'enable', + 'hostname': 'myhostname76', + 'igmp-state-limit': '77', + 'interval': '78', + 'ip-src-port-range': 'test_value_79', + 'ips-affinity': 'test_value_80', + 'ipsec-asic-offload': 'enable', + 'ipsec-hmac-offload': 'enable', + 'ipsec-soft-dec-async': 'enable', + 'ipv6-accept-dad': '84', + 'ipv6-allow-anycast-probe': 'enable', + 'language': 'english', + 'ldapconntimeout': '87', + 'lldp-transmission': 'enable', + 'log-ssl-connection': 'enable', + 'log-uuid': 'disable', + 'login-timestamp': 'enable', + 'long-vdom-name': 'enable', + 'management-vdom': 'test_value_93', + 'max-dlpstat-memory': '94', + 'max-route-cache-size': '95', + 'mc-ttl-notchange': 'enable', + 'memory-use-threshold-extreme': '97', + 'memory-use-threshold-green': '98', + 'memory-use-threshold-red': '99', + 'miglog-affinity': 'test_value_100', + 'miglogd-children': '101', + 'multi-factor-authentication': 'optional', + 'multicast-forward': 'enable', + 'ndp-max-entry': '104', + 'per-user-bwl': 'enable', + 'policy-auth-concurrent': '106', + 'post-login-banner': 'disable', + 'pre-login-banner': 'enable', + 'private-data-encryption': 'disable', + 'proxy-auth-lifetime': 'enable', + 'proxy-auth-lifetime-timeout': '111', + 'proxy-auth-timeout': '112', + 'proxy-cipher-hardware-acceleration': 'disable', + 'proxy-kxp-hardware-acceleration': 'disable', + 'proxy-re-authentication-mode': 'session', + 'proxy-worker-count': '116', + 'radius-port': '117', + 'reboot-upon-config-restore': 'enable', + 'refresh': '119', + 'remoteauthtimeout': '120', + 'reset-sessionless-tcp': 'enable', + 'restart-time': 'test_value_122', + 'revision-backup-on-logout': 'enable', + 'revision-image-auto-backup': 'enable', + 'scanunit-count': '125', + 'security-rating-result-submission': 'enable', + 'security-rating-run-on-schedule': 'enable', + 'send-pmtu-icmp': 'enable', + 'snat-route-change': 'enable', + 'special-file-23-support': 'disable', + 'ssd-trim-date': '131', + 'ssd-trim-freq': 'never', + 'ssd-trim-hour': '133', + 'ssd-trim-min': '134', + 'ssd-trim-weekday': 'sunday', + 'ssh-cbc-cipher': 'enable', + 'ssh-hmac-md5': 'enable', + 'ssh-kex-sha1': 'enable', + 'ssl-min-proto-version': 'SSLv3', + 'ssl-static-key-ciphers': 'enable', + 'sslvpn-cipher-hardware-acceleration': 'enable', + 'sslvpn-kxp-hardware-acceleration': 'enable', + 'sslvpn-max-worker-count': '143', + 'sslvpn-plugin-version-check': 'enable', + 'strict-dirty-session-check': 'enable', + 'strong-crypto': 'enable', + 'switch-controller': 'disable', + 'switch-controller-reserved-network': 'test_value_148', + 'sys-perf-log-interval': '149', + 'tcp-halfclose-timer': '150', + 'tcp-halfopen-timer': '151', + 'tcp-option': 'enable', + 'tcp-timewait-timer': '153', + 'tftp': 'enable', + 'timezone': '01', + 'tp-mc-skip-policy': 'enable', + 'traffic-priority': 'tos', + 'traffic-priority-level': 'low', + 'two-factor-email-expiry': '159', + 'two-factor-fac-expiry': '160', + 'two-factor-ftk-expiry': '161', + 'two-factor-ftm-expiry': '162', + 'two-factor-sms-expiry': '163', + 'udp-idle-timer': '164', + 'user-server-cert': 'test_value_165', + 'vdom-admin': 'enable', + 'vip-arp-range': 'unlimited', + 'virtual-server-count': '168', + 'virtual-server-hardware-acceleration': 'disable', + 'wad-affinity': 'test_value_170', + 'wad-csvc-cs-count': '171', + 'wad-csvc-db-count': '172', + 'wad-source-affinity': 'disable', + 'wad-worker-count': '174', + 'wifi-ca-certificate': 'test_value_175', + 'wifi-certificate': 'test_value_176', + 'wimax-4g-usb': 'enable', + 'wireless-controller': 'enable', + 'wireless-controller-port': '179' + } + + set_method_mock.assert_called_with('system', 'global', 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_system_interface.py b/test/units/modules/network/fortios/test_fortios_system_interface.py new file mode 100644 index 00000000000..41a5bfd27ec --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_interface.py @@ -0,0 +1,1769 @@ +# 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_system_interface +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_system_interface.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_interface_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', + 'system_interface': { + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + expected_data = { + 'ac-name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap-discover': 'enable', + 'arpforward': 'enable', + 'auth-type': 'auto', + 'auto-auth-extension-device': 'enable', + 'bfd': 'global', + 'bfd-desired-min-tx': '12', + 'bfd-detect-mult': '13', + 'bfd-required-min-rx': '14', + 'broadcast-forticlient-discovery': 'enable', + 'broadcast-forward': 'enable', + 'captive-portal': '17', + 'cli-conn-status': '18', + 'color': '19', + 'dedicated-to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected-peer-mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device-access-list': 'test_value_26', + 'device-identification': 'enable', + 'device-identification-active-scan': 'enable', + 'device-netscan': 'disable', + 'device-user-identification': 'enable', + 'devindex': '31', + 'dhcp-client-identifier': 'myId_32', + 'dhcp-relay-agent-option': 'enable', + 'dhcp-relay-ip': 'test_value_34', + 'dhcp-relay-service': 'disable', + 'dhcp-relay-type': 'regular', + 'dhcp-renew-time': '37', + 'disc-retry-timeout': '38', + 'disconnect-threshold': '39', + 'distance': '40', + 'dns-server-override': 'enable', + 'drop-fragment': 'enable', + 'drop-overlapped-fragment': 'enable', + 'egress-shaping-profile': 'test_value_44', + 'endpoint-compliance': 'enable', + 'estimated-downstream-bandwidth': '46', + 'estimated-upstream-bandwidth': '47', + 'explicit-ftp-proxy': 'enable', + 'explicit-web-proxy': 'enable', + 'external': 'enable', + 'fail-action-on-extender': 'soft-restart', + 'fail-alert-method': 'link-failed-signal', + 'fail-detect': 'enable', + 'fail-detect-option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink-backup-link': '57', + 'fortilink-split-interface': 'enable', + 'fortilink-stacking': 'enable', + 'forward-domain': '60', + 'gwdetect': 'enable', + 'ha-priority': '62', + 'icmp-accept-redirect': 'enable', + 'icmp-send-redirect': 'enable', + 'ident-accept': 'enable', + 'idle-timeout': '66', + 'inbandwidth': '67', + 'ingress-spillover-threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips-sniffer-mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp-ha-slave': 'enable', + 'lacp-mode': 'static', + 'lacp-speed': 'slow', + 'lcp-echo-interval': '79', + 'lcp-max-echo-fails': '80', + 'link-up-delay': '81', + 'lldp-transmission': 'enable', + 'macaddr': 'test_value_83', + 'management-ip': 'test_value_84', + 'min-links': '85', + 'min-links-down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu-override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios-forward': 'disable', + 'netflow-sampler': 'disable', + 'outbandwidth': '94', + 'padt-retry-timeout': '95', + 'password': 'test_value_96', + 'ping-serv-status': '97', + 'polling-interval': '98', + 'pppoe-unnumbered-negotiate': 'enable', + 'pptp-auth-type': 'auto', + 'pptp-client': 'enable', + 'pptp-password': 'test_value_102', + 'pptp-server-ip': 'test_value_103', + 'pptp-timeout': '104', + 'pptp-user': 'test_value_105', + 'preserve-session-route': 'enable', + 'priority': '107', + 'priority-override': 'enable', + 'proxy-captive-portal': 'enable', + 'redundant-interface': 'test_value_110', + 'remote-ip': 'test_value_111', + 'replacemsg-override-group': 'test_value_112', + 'role': 'lan', + 'sample-direction': 'tx', + 'sample-rate': '115', + 'scan-botnet-connections': 'disable', + 'secondary-IP': 'enable', + 'security-exempt-list': 'test_value_118', + 'security-external-logout': 'test_value_119', + 'security-external-web': 'test_value_120', + 'security-mac-auth-bypass': 'enable', + 'security-mode': 'none', + 'security-redirect-url': 'test_value_123', + 'service-name': 'test_value_124', + 'sflow-sampler': 'enable', + 'snmp-index': '126', + 'speed': 'auto', + 'spillover-threshold': '128', + 'src-check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward-mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute-dst-mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch-controller-access-vlan': 'enable', + 'switch-controller-arp-inspection': 'enable', + 'switch-controller-dhcp-snooping': 'enable', + 'switch-controller-dhcp-snooping-option82': 'enable', + 'switch-controller-dhcp-snooping-verify-mac': 'enable', + 'switch-controller-igmp-snooping': 'enable', + 'switch-controller-learning-limit': '142', + 'tcp-mss': '143', + 'trust-ip-1': 'test_value_144', + 'trust-ip-2': 'test_value_145', + 'trust-ip-3': 'test_value_146', + 'trust-ip6-1': 'test_value_147', + 'trust-ip6-2': 'test_value_148', + 'trust-ip6-3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp-virtual-mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins-ip': 'test_value_160' + } + + set_method_mock.assert_called_with('system', 'interface', 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_system_interface_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', + 'system_interface': { + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + expected_data = { + 'ac-name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap-discover': 'enable', + 'arpforward': 'enable', + 'auth-type': 'auto', + 'auto-auth-extension-device': 'enable', + 'bfd': 'global', + 'bfd-desired-min-tx': '12', + 'bfd-detect-mult': '13', + 'bfd-required-min-rx': '14', + 'broadcast-forticlient-discovery': 'enable', + 'broadcast-forward': 'enable', + 'captive-portal': '17', + 'cli-conn-status': '18', + 'color': '19', + 'dedicated-to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected-peer-mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device-access-list': 'test_value_26', + 'device-identification': 'enable', + 'device-identification-active-scan': 'enable', + 'device-netscan': 'disable', + 'device-user-identification': 'enable', + 'devindex': '31', + 'dhcp-client-identifier': 'myId_32', + 'dhcp-relay-agent-option': 'enable', + 'dhcp-relay-ip': 'test_value_34', + 'dhcp-relay-service': 'disable', + 'dhcp-relay-type': 'regular', + 'dhcp-renew-time': '37', + 'disc-retry-timeout': '38', + 'disconnect-threshold': '39', + 'distance': '40', + 'dns-server-override': 'enable', + 'drop-fragment': 'enable', + 'drop-overlapped-fragment': 'enable', + 'egress-shaping-profile': 'test_value_44', + 'endpoint-compliance': 'enable', + 'estimated-downstream-bandwidth': '46', + 'estimated-upstream-bandwidth': '47', + 'explicit-ftp-proxy': 'enable', + 'explicit-web-proxy': 'enable', + 'external': 'enable', + 'fail-action-on-extender': 'soft-restart', + 'fail-alert-method': 'link-failed-signal', + 'fail-detect': 'enable', + 'fail-detect-option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink-backup-link': '57', + 'fortilink-split-interface': 'enable', + 'fortilink-stacking': 'enable', + 'forward-domain': '60', + 'gwdetect': 'enable', + 'ha-priority': '62', + 'icmp-accept-redirect': 'enable', + 'icmp-send-redirect': 'enable', + 'ident-accept': 'enable', + 'idle-timeout': '66', + 'inbandwidth': '67', + 'ingress-spillover-threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips-sniffer-mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp-ha-slave': 'enable', + 'lacp-mode': 'static', + 'lacp-speed': 'slow', + 'lcp-echo-interval': '79', + 'lcp-max-echo-fails': '80', + 'link-up-delay': '81', + 'lldp-transmission': 'enable', + 'macaddr': 'test_value_83', + 'management-ip': 'test_value_84', + 'min-links': '85', + 'min-links-down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu-override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios-forward': 'disable', + 'netflow-sampler': 'disable', + 'outbandwidth': '94', + 'padt-retry-timeout': '95', + 'password': 'test_value_96', + 'ping-serv-status': '97', + 'polling-interval': '98', + 'pppoe-unnumbered-negotiate': 'enable', + 'pptp-auth-type': 'auto', + 'pptp-client': 'enable', + 'pptp-password': 'test_value_102', + 'pptp-server-ip': 'test_value_103', + 'pptp-timeout': '104', + 'pptp-user': 'test_value_105', + 'preserve-session-route': 'enable', + 'priority': '107', + 'priority-override': 'enable', + 'proxy-captive-portal': 'enable', + 'redundant-interface': 'test_value_110', + 'remote-ip': 'test_value_111', + 'replacemsg-override-group': 'test_value_112', + 'role': 'lan', + 'sample-direction': 'tx', + 'sample-rate': '115', + 'scan-botnet-connections': 'disable', + 'secondary-IP': 'enable', + 'security-exempt-list': 'test_value_118', + 'security-external-logout': 'test_value_119', + 'security-external-web': 'test_value_120', + 'security-mac-auth-bypass': 'enable', + 'security-mode': 'none', + 'security-redirect-url': 'test_value_123', + 'service-name': 'test_value_124', + 'sflow-sampler': 'enable', + 'snmp-index': '126', + 'speed': 'auto', + 'spillover-threshold': '128', + 'src-check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward-mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute-dst-mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch-controller-access-vlan': 'enable', + 'switch-controller-arp-inspection': 'enable', + 'switch-controller-dhcp-snooping': 'enable', + 'switch-controller-dhcp-snooping-option82': 'enable', + 'switch-controller-dhcp-snooping-verify-mac': 'enable', + 'switch-controller-igmp-snooping': 'enable', + 'switch-controller-learning-limit': '142', + 'tcp-mss': '143', + 'trust-ip-1': 'test_value_144', + 'trust-ip-2': 'test_value_145', + 'trust-ip-3': 'test_value_146', + 'trust-ip6-1': 'test_value_147', + 'trust-ip6-2': 'test_value_148', + 'trust-ip6-3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp-virtual-mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins-ip': 'test_value_160' + } + + set_method_mock.assert_called_with('system', 'interface', 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_system_interface_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', + 'system_interface': { + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'interface', 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_system_interface_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', + 'system_interface': { + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'interface', 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_system_interface_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', + 'system_interface': { + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + expected_data = { + 'ac-name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap-discover': 'enable', + 'arpforward': 'enable', + 'auth-type': 'auto', + 'auto-auth-extension-device': 'enable', + 'bfd': 'global', + 'bfd-desired-min-tx': '12', + 'bfd-detect-mult': '13', + 'bfd-required-min-rx': '14', + 'broadcast-forticlient-discovery': 'enable', + 'broadcast-forward': 'enable', + 'captive-portal': '17', + 'cli-conn-status': '18', + 'color': '19', + 'dedicated-to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected-peer-mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device-access-list': 'test_value_26', + 'device-identification': 'enable', + 'device-identification-active-scan': 'enable', + 'device-netscan': 'disable', + 'device-user-identification': 'enable', + 'devindex': '31', + 'dhcp-client-identifier': 'myId_32', + 'dhcp-relay-agent-option': 'enable', + 'dhcp-relay-ip': 'test_value_34', + 'dhcp-relay-service': 'disable', + 'dhcp-relay-type': 'regular', + 'dhcp-renew-time': '37', + 'disc-retry-timeout': '38', + 'disconnect-threshold': '39', + 'distance': '40', + 'dns-server-override': 'enable', + 'drop-fragment': 'enable', + 'drop-overlapped-fragment': 'enable', + 'egress-shaping-profile': 'test_value_44', + 'endpoint-compliance': 'enable', + 'estimated-downstream-bandwidth': '46', + 'estimated-upstream-bandwidth': '47', + 'explicit-ftp-proxy': 'enable', + 'explicit-web-proxy': 'enable', + 'external': 'enable', + 'fail-action-on-extender': 'soft-restart', + 'fail-alert-method': 'link-failed-signal', + 'fail-detect': 'enable', + 'fail-detect-option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink-backup-link': '57', + 'fortilink-split-interface': 'enable', + 'fortilink-stacking': 'enable', + 'forward-domain': '60', + 'gwdetect': 'enable', + 'ha-priority': '62', + 'icmp-accept-redirect': 'enable', + 'icmp-send-redirect': 'enable', + 'ident-accept': 'enable', + 'idle-timeout': '66', + 'inbandwidth': '67', + 'ingress-spillover-threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips-sniffer-mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp-ha-slave': 'enable', + 'lacp-mode': 'static', + 'lacp-speed': 'slow', + 'lcp-echo-interval': '79', + 'lcp-max-echo-fails': '80', + 'link-up-delay': '81', + 'lldp-transmission': 'enable', + 'macaddr': 'test_value_83', + 'management-ip': 'test_value_84', + 'min-links': '85', + 'min-links-down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu-override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios-forward': 'disable', + 'netflow-sampler': 'disable', + 'outbandwidth': '94', + 'padt-retry-timeout': '95', + 'password': 'test_value_96', + 'ping-serv-status': '97', + 'polling-interval': '98', + 'pppoe-unnumbered-negotiate': 'enable', + 'pptp-auth-type': 'auto', + 'pptp-client': 'enable', + 'pptp-password': 'test_value_102', + 'pptp-server-ip': 'test_value_103', + 'pptp-timeout': '104', + 'pptp-user': 'test_value_105', + 'preserve-session-route': 'enable', + 'priority': '107', + 'priority-override': 'enable', + 'proxy-captive-portal': 'enable', + 'redundant-interface': 'test_value_110', + 'remote-ip': 'test_value_111', + 'replacemsg-override-group': 'test_value_112', + 'role': 'lan', + 'sample-direction': 'tx', + 'sample-rate': '115', + 'scan-botnet-connections': 'disable', + 'secondary-IP': 'enable', + 'security-exempt-list': 'test_value_118', + 'security-external-logout': 'test_value_119', + 'security-external-web': 'test_value_120', + 'security-mac-auth-bypass': 'enable', + 'security-mode': 'none', + 'security-redirect-url': 'test_value_123', + 'service-name': 'test_value_124', + 'sflow-sampler': 'enable', + 'snmp-index': '126', + 'speed': 'auto', + 'spillover-threshold': '128', + 'src-check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward-mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute-dst-mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch-controller-access-vlan': 'enable', + 'switch-controller-arp-inspection': 'enable', + 'switch-controller-dhcp-snooping': 'enable', + 'switch-controller-dhcp-snooping-option82': 'enable', + 'switch-controller-dhcp-snooping-verify-mac': 'enable', + 'switch-controller-igmp-snooping': 'enable', + 'switch-controller-learning-limit': '142', + 'tcp-mss': '143', + 'trust-ip-1': 'test_value_144', + 'trust-ip-2': 'test_value_145', + 'trust-ip-3': 'test_value_146', + 'trust-ip6-1': 'test_value_147', + 'trust-ip6-2': 'test_value_148', + 'trust-ip6-3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp-virtual-mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins-ip': 'test_value_160' + } + + set_method_mock.assert_called_with('system', 'interface', 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_system_interface_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', + 'system_interface': { + 'random_attribute_not_valid': 'tag', + 'ac_name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap_discover': 'enable', + 'arpforward': 'enable', + 'auth_type': 'auto', + 'auto_auth_extension_device': 'enable', + 'bfd': 'global', + 'bfd_desired_min_tx': '12', + 'bfd_detect_mult': '13', + 'bfd_required_min_rx': '14', + 'broadcast_forticlient_discovery': 'enable', + 'broadcast_forward': 'enable', + 'captive_portal': '17', + 'cli_conn_status': '18', + 'color': '19', + 'dedicated_to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected_peer_mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device_access_list': 'test_value_26', + 'device_identification': 'enable', + 'device_identification_active_scan': 'enable', + 'device_netscan': 'disable', + 'device_user_identification': 'enable', + 'devindex': '31', + 'dhcp_client_identifier': 'myId_32', + 'dhcp_relay_agent_option': 'enable', + 'dhcp_relay_ip': 'test_value_34', + 'dhcp_relay_service': 'disable', + 'dhcp_relay_type': 'regular', + 'dhcp_renew_time': '37', + 'disc_retry_timeout': '38', + 'disconnect_threshold': '39', + 'distance': '40', + 'dns_server_override': 'enable', + 'drop_fragment': 'enable', + 'drop_overlapped_fragment': 'enable', + 'egress_shaping_profile': 'test_value_44', + 'endpoint_compliance': 'enable', + 'estimated_downstream_bandwidth': '46', + 'estimated_upstream_bandwidth': '47', + 'explicit_ftp_proxy': 'enable', + 'explicit_web_proxy': 'enable', + 'external': 'enable', + 'fail_action_on_extender': 'soft-restart', + 'fail_alert_method': 'link-failed-signal', + 'fail_detect': 'enable', + 'fail_detect_option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink_backup_link': '57', + 'fortilink_split_interface': 'enable', + 'fortilink_stacking': 'enable', + 'forward_domain': '60', + 'gwdetect': 'enable', + 'ha_priority': '62', + 'icmp_accept_redirect': 'enable', + 'icmp_send_redirect': 'enable', + 'ident_accept': 'enable', + 'idle_timeout': '66', + 'inbandwidth': '67', + 'ingress_spillover_threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips_sniffer_mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp_ha_slave': 'enable', + 'lacp_mode': 'static', + 'lacp_speed': 'slow', + 'lcp_echo_interval': '79', + 'lcp_max_echo_fails': '80', + 'link_up_delay': '81', + 'lldp_transmission': 'enable', + 'macaddr': 'test_value_83', + 'management_ip': 'test_value_84', + 'min_links': '85', + 'min_links_down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu_override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios_forward': 'disable', + 'netflow_sampler': 'disable', + 'outbandwidth': '94', + 'padt_retry_timeout': '95', + 'password': 'test_value_96', + 'ping_serv_status': '97', + 'polling_interval': '98', + 'pppoe_unnumbered_negotiate': 'enable', + 'pptp_auth_type': 'auto', + 'pptp_client': 'enable', + 'pptp_password': 'test_value_102', + 'pptp_server_ip': 'test_value_103', + 'pptp_timeout': '104', + 'pptp_user': 'test_value_105', + 'preserve_session_route': 'enable', + 'priority': '107', + 'priority_override': 'enable', + 'proxy_captive_portal': 'enable', + 'redundant_interface': 'test_value_110', + 'remote_ip': 'test_value_111', + 'replacemsg_override_group': 'test_value_112', + 'role': 'lan', + 'sample_direction': 'tx', + 'sample_rate': '115', + 'scan_botnet_connections': 'disable', + 'secondary_IP': 'enable', + 'security_exempt_list': 'test_value_118', + 'security_external_logout': 'test_value_119', + 'security_external_web': 'test_value_120', + 'security_mac_auth_bypass': 'enable', + 'security_mode': 'none', + 'security_redirect_url': 'test_value_123', + 'service_name': 'test_value_124', + 'sflow_sampler': 'enable', + 'snmp_index': '126', + 'speed': 'auto', + 'spillover_threshold': '128', + 'src_check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward_mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute_dst_mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch_controller_access_vlan': 'enable', + 'switch_controller_arp_inspection': 'enable', + 'switch_controller_dhcp_snooping': 'enable', + 'switch_controller_dhcp_snooping_option82': 'enable', + 'switch_controller_dhcp_snooping_verify_mac': 'enable', + 'switch_controller_igmp_snooping': 'enable', + 'switch_controller_learning_limit': '142', + 'tcp_mss': '143', + 'trust_ip_1': 'test_value_144', + 'trust_ip_2': 'test_value_145', + 'trust_ip_3': 'test_value_146', + 'trust_ip6_1': 'test_value_147', + 'trust_ip6_2': 'test_value_148', + 'trust_ip6_3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp_virtual_mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins_ip': 'test_value_160' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_interface.fortios_system(input_data, fos_instance) + + expected_data = { + 'ac-name': 'test_value_3', + 'aggregate': 'test_value_4', + 'algorithm': 'L2', + 'alias': 'test_value_6', + 'ap-discover': 'enable', + 'arpforward': 'enable', + 'auth-type': 'auto', + 'auto-auth-extension-device': 'enable', + 'bfd': 'global', + 'bfd-desired-min-tx': '12', + 'bfd-detect-mult': '13', + 'bfd-required-min-rx': '14', + 'broadcast-forticlient-discovery': 'enable', + 'broadcast-forward': 'enable', + 'captive-portal': '17', + 'cli-conn-status': '18', + 'color': '19', + 'dedicated-to': 'none', + 'defaultgw': 'enable', + 'description': 'test_value_22', + 'detected-peer-mtu': '23', + 'detectprotocol': 'ping', + 'detectserver': 'test_value_25', + 'device-access-list': 'test_value_26', + 'device-identification': 'enable', + 'device-identification-active-scan': 'enable', + 'device-netscan': 'disable', + 'device-user-identification': 'enable', + 'devindex': '31', + 'dhcp-client-identifier': 'myId_32', + 'dhcp-relay-agent-option': 'enable', + 'dhcp-relay-ip': 'test_value_34', + 'dhcp-relay-service': 'disable', + 'dhcp-relay-type': 'regular', + 'dhcp-renew-time': '37', + 'disc-retry-timeout': '38', + 'disconnect-threshold': '39', + 'distance': '40', + 'dns-server-override': 'enable', + 'drop-fragment': 'enable', + 'drop-overlapped-fragment': 'enable', + 'egress-shaping-profile': 'test_value_44', + 'endpoint-compliance': 'enable', + 'estimated-downstream-bandwidth': '46', + 'estimated-upstream-bandwidth': '47', + 'explicit-ftp-proxy': 'enable', + 'explicit-web-proxy': 'enable', + 'external': 'enable', + 'fail-action-on-extender': 'soft-restart', + 'fail-alert-method': 'link-failed-signal', + 'fail-detect': 'enable', + 'fail-detect-option': 'detectserver', + 'fortiheartbeat': 'enable', + 'fortilink': 'enable', + 'fortilink-backup-link': '57', + 'fortilink-split-interface': 'enable', + 'fortilink-stacking': 'enable', + 'forward-domain': '60', + 'gwdetect': 'enable', + 'ha-priority': '62', + 'icmp-accept-redirect': 'enable', + 'icmp-send-redirect': 'enable', + 'ident-accept': 'enable', + 'idle-timeout': '66', + 'inbandwidth': '67', + 'ingress-spillover-threshold': '68', + 'interface': 'test_value_69', + 'internal': '70', + 'ip': 'test_value_71', + 'ipmac': 'enable', + 'ips-sniffer-mode': 'enable', + 'ipunnumbered': 'test_value_74', + 'l2forward': 'enable', + 'lacp-ha-slave': 'enable', + 'lacp-mode': 'static', + 'lacp-speed': 'slow', + 'lcp-echo-interval': '79', + 'lcp-max-echo-fails': '80', + 'link-up-delay': '81', + 'lldp-transmission': 'enable', + 'macaddr': 'test_value_83', + 'management-ip': 'test_value_84', + 'min-links': '85', + 'min-links-down': 'operational', + 'mode': 'static', + 'mtu': '88', + 'mtu-override': 'enable', + 'name': 'default_name_90', + 'ndiscforward': 'enable', + 'netbios-forward': 'disable', + 'netflow-sampler': 'disable', + 'outbandwidth': '94', + 'padt-retry-timeout': '95', + 'password': 'test_value_96', + 'ping-serv-status': '97', + 'polling-interval': '98', + 'pppoe-unnumbered-negotiate': 'enable', + 'pptp-auth-type': 'auto', + 'pptp-client': 'enable', + 'pptp-password': 'test_value_102', + 'pptp-server-ip': 'test_value_103', + 'pptp-timeout': '104', + 'pptp-user': 'test_value_105', + 'preserve-session-route': 'enable', + 'priority': '107', + 'priority-override': 'enable', + 'proxy-captive-portal': 'enable', + 'redundant-interface': 'test_value_110', + 'remote-ip': 'test_value_111', + 'replacemsg-override-group': 'test_value_112', + 'role': 'lan', + 'sample-direction': 'tx', + 'sample-rate': '115', + 'scan-botnet-connections': 'disable', + 'secondary-IP': 'enable', + 'security-exempt-list': 'test_value_118', + 'security-external-logout': 'test_value_119', + 'security-external-web': 'test_value_120', + 'security-mac-auth-bypass': 'enable', + 'security-mode': 'none', + 'security-redirect-url': 'test_value_123', + 'service-name': 'test_value_124', + 'sflow-sampler': 'enable', + 'snmp-index': '126', + 'speed': 'auto', + 'spillover-threshold': '128', + 'src-check': 'enable', + 'status': 'up', + 'stpforward': 'enable', + 'stpforward-mode': 'rpl-all-ext-id', + 'subst': 'enable', + 'substitute-dst-mac': 'test_value_134', + 'switch': 'test_value_135', + 'switch-controller-access-vlan': 'enable', + 'switch-controller-arp-inspection': 'enable', + 'switch-controller-dhcp-snooping': 'enable', + 'switch-controller-dhcp-snooping-option82': 'enable', + 'switch-controller-dhcp-snooping-verify-mac': 'enable', + 'switch-controller-igmp-snooping': 'enable', + 'switch-controller-learning-limit': '142', + 'tcp-mss': '143', + 'trust-ip-1': 'test_value_144', + 'trust-ip-2': 'test_value_145', + 'trust-ip-3': 'test_value_146', + 'trust-ip6-1': 'test_value_147', + 'trust-ip6-2': 'test_value_148', + 'trust-ip6-3': 'test_value_149', + 'type': 'physical', + 'username': 'test_value_151', + 'vdom': 'test_value_152', + 'vindex': '153', + 'vlanforward': 'enable', + 'vlanid': '155', + 'vrf': '156', + 'vrrp-virtual-mac': 'enable', + 'wccp': 'enable', + 'weight': '159', + 'wins-ip': 'test_value_160' + } + + set_method_mock.assert_called_with('system', 'interface', 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_system_sdn_connector.py b/test/units/modules/network/fortios/test_fortios_system_sdn_connector.py new file mode 100644 index 00000000000..7d4ef82a438 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_sdn_connector.py @@ -0,0 +1,489 @@ +# 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_system_sdn_connector +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_system_sdn_connector.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_sdn_connector_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', + 'system_sdn_connector': { + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + expected_data = { + 'access-key': 'test_value_3', + 'azure-region': 'global', + 'client-id': 'test_value_5', + 'client-secret': 'test_value_6', + 'compartment-id': 'test_value_7', + 'gcp-project': 'test_value_8', + 'key-passwd': 'test_value_9', + 'login-endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci-cert': 'test_value_12', + 'oci-fingerprint': 'test_value_13', + 'oci-region': 'phoenix', + 'password': 'test_value_15', + 'private-key': 'test_value_16', + 'region': 'test_value_17', + 'resource-group': 'test_value_18', + 'resource-url': 'test_value_19', + 'secret-key': 'test_value_20', + 'server': '192.168.100.21', + 'server-port': '22', + 'service-account': 'test_value_23', + 'status': 'disable', + 'subscription-id': 'test_value_25', + 'tenant-id': 'test_value_26', + 'type': 'aci', + 'update-interval': '28', + 'use-metadata-iam': 'disable', + 'user-id': 'test_value_30', + 'username': 'test_value_31', + 'vpc-id': 'test_value_32' + } + + set_method_mock.assert_called_with('system', 'sdn-connector', 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_system_sdn_connector_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', + 'system_sdn_connector': { + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + expected_data = { + 'access-key': 'test_value_3', + 'azure-region': 'global', + 'client-id': 'test_value_5', + 'client-secret': 'test_value_6', + 'compartment-id': 'test_value_7', + 'gcp-project': 'test_value_8', + 'key-passwd': 'test_value_9', + 'login-endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci-cert': 'test_value_12', + 'oci-fingerprint': 'test_value_13', + 'oci-region': 'phoenix', + 'password': 'test_value_15', + 'private-key': 'test_value_16', + 'region': 'test_value_17', + 'resource-group': 'test_value_18', + 'resource-url': 'test_value_19', + 'secret-key': 'test_value_20', + 'server': '192.168.100.21', + 'server-port': '22', + 'service-account': 'test_value_23', + 'status': 'disable', + 'subscription-id': 'test_value_25', + 'tenant-id': 'test_value_26', + 'type': 'aci', + 'update-interval': '28', + 'use-metadata-iam': 'disable', + 'user-id': 'test_value_30', + 'username': 'test_value_31', + 'vpc-id': 'test_value_32' + } + + set_method_mock.assert_called_with('system', 'sdn-connector', 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_system_sdn_connector_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', + 'system_sdn_connector': { + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'sdn-connector', 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_system_sdn_connector_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', + 'system_sdn_connector': { + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'sdn-connector', 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_system_sdn_connector_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', + 'system_sdn_connector': { + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + expected_data = { + 'access-key': 'test_value_3', + 'azure-region': 'global', + 'client-id': 'test_value_5', + 'client-secret': 'test_value_6', + 'compartment-id': 'test_value_7', + 'gcp-project': 'test_value_8', + 'key-passwd': 'test_value_9', + 'login-endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci-cert': 'test_value_12', + 'oci-fingerprint': 'test_value_13', + 'oci-region': 'phoenix', + 'password': 'test_value_15', + 'private-key': 'test_value_16', + 'region': 'test_value_17', + 'resource-group': 'test_value_18', + 'resource-url': 'test_value_19', + 'secret-key': 'test_value_20', + 'server': '192.168.100.21', + 'server-port': '22', + 'service-account': 'test_value_23', + 'status': 'disable', + 'subscription-id': 'test_value_25', + 'tenant-id': 'test_value_26', + 'type': 'aci', + 'update-interval': '28', + 'use-metadata-iam': 'disable', + 'user-id': 'test_value_30', + 'username': 'test_value_31', + 'vpc-id': 'test_value_32' + } + + set_method_mock.assert_called_with('system', 'sdn-connector', 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_system_sdn_connector_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', + 'system_sdn_connector': { + 'random_attribute_not_valid': 'tag', + 'access_key': 'test_value_3', + 'azure_region': 'global', + 'client_id': 'test_value_5', + 'client_secret': 'test_value_6', + 'compartment_id': 'test_value_7', + 'gcp_project': 'test_value_8', + 'key_passwd': 'test_value_9', + 'login_endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci_cert': 'test_value_12', + 'oci_fingerprint': 'test_value_13', + 'oci_region': 'phoenix', + 'password': 'test_value_15', + 'private_key': 'test_value_16', + 'region': 'test_value_17', + 'resource_group': 'test_value_18', + 'resource_url': 'test_value_19', + 'secret_key': 'test_value_20', + 'server': '192.168.100.21', + 'server_port': '22', + 'service_account': 'test_value_23', + 'status': 'disable', + 'subscription_id': 'test_value_25', + 'tenant_id': 'test_value_26', + 'type': 'aci', + 'update_interval': '28', + 'use_metadata_iam': 'disable', + 'user_id': 'test_value_30', + 'username': 'test_value_31', + 'vpc_id': 'test_value_32' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance) + + expected_data = { + 'access-key': 'test_value_3', + 'azure-region': 'global', + 'client-id': 'test_value_5', + 'client-secret': 'test_value_6', + 'compartment-id': 'test_value_7', + 'gcp-project': 'test_value_8', + 'key-passwd': 'test_value_9', + 'login-endpoint': 'test_value_10', + 'name': 'default_name_11', + 'oci-cert': 'test_value_12', + 'oci-fingerprint': 'test_value_13', + 'oci-region': 'phoenix', + 'password': 'test_value_15', + 'private-key': 'test_value_16', + 'region': 'test_value_17', + 'resource-group': 'test_value_18', + 'resource-url': 'test_value_19', + 'secret-key': 'test_value_20', + 'server': '192.168.100.21', + 'server-port': '22', + 'service-account': 'test_value_23', + 'status': 'disable', + 'subscription-id': 'test_value_25', + 'tenant-id': 'test_value_26', + 'type': 'aci', + 'update-interval': '28', + 'use-metadata-iam': 'disable', + 'user-id': 'test_value_30', + 'username': 'test_value_31', + 'vpc-id': 'test_value_32' + } + + set_method_mock.assert_called_with('system', 'sdn-connector', 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_system_vdom.py b/test/units/modules/network/fortios/test_fortios_system_vdom.py new file mode 100644 index 00000000000..131f125ff06 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_vdom.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_system_vdom +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_system_vdom.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_vdom_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', + 'system_vdom': { + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'short-name': 'test_value_4', + 'temporary': '5', + 'vcluster-id': '6' + } + + set_method_mock.assert_called_with('system', 'vdom', 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_system_vdom_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', + 'system_vdom': { + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'short-name': 'test_value_4', + 'temporary': '5', + 'vcluster-id': '6' + } + + set_method_mock.assert_called_with('system', 'vdom', 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_system_vdom_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', + 'system_vdom': { + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'vdom', 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_system_vdom_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', + 'system_vdom': { + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + delete_method_mock.assert_called_with('system', 'vdom', 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_system_vdom_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', + 'system_vdom': { + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'short-name': 'test_value_4', + 'temporary': '5', + 'vcluster-id': '6' + } + + set_method_mock.assert_called_with('system', 'vdom', 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_system_vdom_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', + 'system_vdom': { + 'random_attribute_not_valid': 'tag', + 'name': 'default_name_3', + 'short_name': 'test_value_4', + 'temporary': '5', + 'vcluster_id': '6' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance) + + expected_data = { + 'name': 'default_name_3', + 'short-name': 'test_value_4', + 'temporary': '5', + 'vcluster-id': '6' + } + + set_method_mock.assert_called_with('system', 'vdom', 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_system_virtual_wan_link.py b/test/units/modules/network/fortios/test_fortios_system_virtual_wan_link.py new file mode 100644 index 00000000000..a9c329ef1e6 --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_virtual_wan_link.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_system_virtual_wan_link +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_system_virtual_wan_link.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_virtual_wan_link_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', + 'system_virtual_wan_link': {'fail_detect': 'enable', + 'load_balance_mode': 'source-ip-based', + 'status': 'disable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance) + + expected_data = {'fail-detect': 'enable', + 'load-balance-mode': 'source-ip-based', + 'status': 'disable' + } + + set_method_mock.assert_called_with('system', 'virtual-wan-link', 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_system_virtual_wan_link_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', + 'system_virtual_wan_link': {'fail_detect': 'enable', + 'load_balance_mode': 'source-ip-based', + 'status': 'disable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance) + + expected_data = {'fail-detect': 'enable', + 'load-balance-mode': 'source-ip-based', + 'status': 'disable' + } + + set_method_mock.assert_called_with('system', 'virtual-wan-link', 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_system_virtual_wan_link_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', + 'system_virtual_wan_link': {'fail_detect': 'enable', + 'load_balance_mode': 'source-ip-based', + 'status': 'disable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance) + + expected_data = {'fail-detect': 'enable', + 'load-balance-mode': 'source-ip-based', + 'status': 'disable' + } + + set_method_mock.assert_called_with('system', 'virtual-wan-link', 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_system_virtual_wan_link_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', + 'system_virtual_wan_link': { + 'random_attribute_not_valid': 'tag', 'fail_detect': 'enable', + 'load_balance_mode': 'source-ip-based', + 'status': 'disable' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance) + + expected_data = {'fail-detect': 'enable', + 'load-balance-mode': 'source-ip-based', + 'status': 'disable' + } + + set_method_mock.assert_called_with('system', 'virtual-wan-link', 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