diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py
index dfd6859dd5b..dfd34adee2b 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_ssl_ssh_profile
short_description: Configure SSL/SSH protocol options in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and ssl_ssh_profile category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and ssl_ssh_profile category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,82 +41,104 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_ssl_ssh_profile:
description:
- Configure SSL/SSH protocol options.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
caname:
description:
- CA certificate used by SSL Inspection. Source vpn.certificate.local.name.
+ type: str
comment:
description:
- Optional comments.
+ type: str
ftps:
description:
- Configure FTPS options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
+ - Ports to use for scanning (1 - 65535).
+ type: int
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
@@ -127,40 +146,47 @@ options:
https:
description:
- Configure HTTPS options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
+ - Ports to use for scanning (1 - 65535).
+ type: int
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- certificate-inspection
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
@@ -168,46 +194,54 @@ options:
imaps:
description:
- Configure IMAPS options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
+ - Ports to use for scanning (1 - 65535).
+ type: int
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
- ignore
- mapi-over-https:
+ mapi_over_https:
description:
- Enable/disable inspection of MAPI over HTTPS.
+ type: str
choices:
- enable
- disable
@@ -215,97 +249,115 @@ options:
description:
- Name.
required: true
+ type: str
pop3s:
description:
- Configure POP3S options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
+ - Ports to use for scanning (1 - 65535).
+ type: int
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
- ignore
- rpc-over-https:
+ rpc_over_https:
description:
- Enable/disable inspection of RPC over HTTPS.
+ type: str
choices:
- enable
- disable
- server-cert:
+ server_cert:
description:
- Certificate used by SSL Inspection to replace server certificate. Source vpn.certificate.local.name.
- server-cert-mode:
+ type: str
+ server_cert_mode:
description:
- Re-sign or replace the server's certificate.
+ type: str
choices:
- re-sign
- replace
smtps:
description:
- Configure SMTPS options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
+ - Ports to use for scanning (1 - 65535).
+ type: int
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
@@ -313,142 +365,169 @@ options:
ssh:
description:
- Configure SSH options.
+ type: dict
suboptions:
- inspect-all:
+ inspect_all:
description:
- Level of SSL inspection.
+ type: str
choices:
- disable
- deep-inspection
ports:
description:
- - Ports to use for scanning (1 - 65535, default = 443).
- ssh-algorithm:
+ - Ports to use for scanning (1 - 65535).
+ type: int
+ ssh_algorithm:
description:
- Relative strength of encryption algorithms accepted during negotiation.
+ type: str
choices:
- compatible
- high-encryption
- ssh-policy-check:
+ ssh_policy_check:
description:
- Enable/disable SSH policy check.
+ type: str
choices:
- disable
- enable
- ssh-tun-policy-check:
+ ssh_tun_policy_check:
description:
- Enable/disable SSH tunnel policy check.
+ type: str
choices:
- disable
- enable
status:
description:
- Configure protocol inspection status.
+ type: str
choices:
- disable
- deep-inspection
- unsupported-version:
+ unsupported_version:
description:
- Action based on SSH version being unsupported.
+ type: str
choices:
- bypass
- block
ssl:
description:
- Configure SSL options.
+ type: dict
suboptions:
- allow-invalid-server-cert:
+ allow_invalid_server_cert:
description:
- When enabled, allows SSL sessions whose server certificate validation failed.
+ type: str
choices:
- enable
- disable
- client-cert-request:
+ client_cert_request:
description:
- Action based on client certificate request.
+ type: str
choices:
- bypass
- inspect
- block
- inspect-all:
+ inspect_all:
description:
- Level of SSL inspection.
+ type: str
choices:
- disable
- certificate-inspection
- deep-inspection
- unsupported-ssl:
+ unsupported_ssl:
description:
- Action based on the SSL encryption used being unsupported.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-cert:
+ untrusted_cert:
description:
- Allow, ignore, or block the untrusted SSL session server certificate.
+ type: str
choices:
- allow
- block
- ignore
- ssl-anomalies-log:
+ ssl_anomalies_log:
description:
- Enable/disable logging SSL anomalies.
+ type: str
choices:
- disable
- enable
- ssl-exempt:
+ ssl_exempt:
description:
- Servers to exempt from SSL inspection.
+ type: list
suboptions:
address:
description:
- IPv4 address object. Source firewall.address.name firewall.addrgrp.name.
+ type: str
address6:
description:
- IPv6 address object. Source firewall.address6.name firewall.addrgrp6.name.
- fortiguard-category:
+ type: str
+ fortiguard_category:
description:
- FortiGuard category ID.
+ type: int
id:
description:
- ID number.
required: true
+ type: int
regex:
description:
- Exempt servers by regular expression.
+ type: str
type:
description:
- Type of address object (IPv4 or IPv6) or FortiGuard category.
+ type: str
choices:
- fortiguard-category
- address
- address6
- wildcard-fqdn
- regex
- wildcard-fqdn:
+ wildcard_fqdn:
description:
- Exempt servers by wildcard FQDN. Source firewall.wildcard-fqdn.custom.name firewall.wildcard-fqdn.group.name.
- ssl-exemptions-log:
+ type: str
+ ssl_exemptions_log:
description:
- Enable/disable logging SSL exemptions.
+ type: str
choices:
- disable
- enable
- ssl-server:
+ ssl_server:
description:
- SSL servers.
+ type: list
suboptions:
- ftps-client-cert-request:
+ ftps_client_cert_request:
description:
- Action based on client certificate request during the FTPS handshake.
+ type: str
choices:
- bypass
- inspect
- block
- https-client-cert-request:
+ https_client_cert_request:
description:
- Action based on client certificate request during the HTTPS handshake.
+ type: str
choices:
- bypass
- inspect
@@ -457,9 +536,11 @@ options:
description:
- SSL server ID.
required: true
- imaps-client-cert-request:
+ type: int
+ imaps_client_cert_request:
description:
- Action based on client certificate request during the IMAPS handshake.
+ type: str
choices:
- bypass
- inspect
@@ -467,39 +548,46 @@ options:
ip:
description:
- IPv4 address of the SSL server.
- pop3s-client-cert-request:
+ type: str
+ pop3s_client_cert_request:
description:
- Action based on client certificate request during the POP3S handshake.
+ type: str
choices:
- bypass
- inspect
- block
- smtps-client-cert-request:
+ smtps_client_cert_request:
description:
- Action based on client certificate request during the SMTPS handshake.
+ type: str
choices:
- bypass
- inspect
- block
- ssl-other-client-cert-request:
+ ssl_other_client_cert_request:
description:
- Action based on client certificate request during an SSL protocol handshake.
+ type: str
choices:
- bypass
- inspect
- block
- untrusted-caname:
+ untrusted_caname:
description:
- Untrusted CA certificate used by SSL Inspection. Source vpn.certificate.local.name.
- use-ssl-server:
+ type: str
+ use_ssl_server:
description:
- Enable/disable the use of SSL server table for SSL offloading.
+ type: str
choices:
- disable
- enable
whitelist:
description:
- Enable/disable exempting servers by FortiGuard whitelist.
+ type: str
choices:
- enable
- disable
@@ -512,6 +600,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure SSL/SSH protocol options.
fortios_firewall_ssl_ssh_profile:
@@ -520,87 +609,87 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
firewall_ssl_ssh_profile:
- state: "present"
caname: " (source vpn.certificate.local.name)"
comment: "Optional comments."
ftps:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
ports: "8"
status: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
https:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
ports: "15"
status: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
imaps:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
ports: "22"
status: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
- mapi-over-https: "enable"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
+ mapi_over_https: "enable"
name: "default_name_27"
pop3s:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
ports: "31"
status: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
- rpc-over-https: "enable"
- server-cert: " (source vpn.certificate.local.name)"
- server-cert-mode: "re-sign"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
+ rpc_over_https: "enable"
+ server_cert: " (source vpn.certificate.local.name)"
+ server_cert_mode: "re-sign"
smtps:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
ports: "41"
status: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
ssh:
- inspect-all: "disable"
+ inspect_all: "disable"
ports: "47"
- ssh-algorithm: "compatible"
- ssh-policy-check: "disable"
- ssh-tun-policy-check: "disable"
+ ssh_algorithm: "compatible"
+ ssh_policy_check: "disable"
+ ssh_tun_policy_check: "disable"
status: "disable"
- unsupported-version: "bypass"
+ unsupported_version: "bypass"
ssl:
- allow-invalid-server-cert: "enable"
- client-cert-request: "bypass"
- inspect-all: "disable"
- unsupported-ssl: "bypass"
- untrusted-cert: "allow"
- ssl-anomalies-log: "disable"
- ssl-exempt:
+ allow_invalid_server_cert: "enable"
+ client_cert_request: "bypass"
+ inspect_all: "disable"
+ unsupported_ssl: "bypass"
+ untrusted_cert: "allow"
+ ssl_anomalies_log: "disable"
+ ssl_exempt:
-
address: " (source firewall.address.name firewall.addrgrp.name)"
address6: " (source firewall.address6.name firewall.addrgrp6.name)"
- fortiguard-category: "63"
+ fortiguard_category: "63"
id: "64"
regex: ""
type: "fortiguard-category"
- wildcard-fqdn: " (source firewall.wildcard-fqdn.custom.name firewall.wildcard-fqdn.group.name)"
- ssl-exemptions-log: "disable"
- ssl-server:
+ wildcard_fqdn: " (source firewall.wildcard-fqdn.custom.name firewall.wildcard-fqdn.group.name)"
+ ssl_exemptions_log: "disable"
+ ssl_server:
-
- ftps-client-cert-request: "bypass"
- https-client-cert-request: "bypass"
+ ftps_client_cert_request: "bypass"
+ https_client_cert_request: "bypass"
id: "72"
- imaps-client-cert-request: "bypass"
+ imaps_client_cert_request: "bypass"
ip: ""
- pop3s-client-cert-request: "bypass"
- smtps-client-cert-request: "bypass"
- ssl-other-client-cert-request: "bypass"
- untrusted-caname: " (source vpn.certificate.local.name)"
- use-ssl-server: "disable"
+ pop3s_client_cert_request: "bypass"
+ smtps_client_cert_request: "bypass"
+ ssl_other_client_cert_request: "bypass"
+ untrusted_caname: " (source vpn.certificate.local.name)"
+ use_ssl_server: "disable"
whitelist: "enable"
'''
@@ -664,14 +753,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']:
@@ -679,17 +770,17 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_ssl_ssh_profile_data(json):
option_list = ['caname', 'comment', 'ftps',
- 'https', 'imaps', 'mapi-over-https',
- 'name', 'pop3s', 'rpc-over-https',
- 'server-cert', 'server-cert-mode', 'smtps',
- 'ssh', 'ssl', 'ssl-anomalies-log',
- 'ssl-exempt', 'ssl-exemptions-log', 'ssl-server',
- 'untrusted-caname', 'use-ssl-server', 'whitelist']
+ 'https', 'imaps', 'mapi_over_https',
+ 'name', 'pop3s', 'rpc_over_https',
+ 'server_cert', 'server_cert_mode', 'smtps',
+ 'ssh', 'ssl', 'ssl_anomalies_log',
+ 'ssl_exempt', 'ssl_exemptions_log', 'ssl_server',
+ 'untrusted_caname', 'use_ssl_server', 'whitelist']
dictionary = {}
for attribute in option_list:
@@ -699,192 +790,210 @@ def filter_firewall_ssl_ssh_profile_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_ssl_ssh_profile(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_ssl_ssh_profile_data = data['firewall_ssl_ssh_profile']
- filtered_data = filter_firewall_ssl_ssh_profile_data(firewall_ssl_ssh_profile_data)
- if firewall_ssl_ssh_profile_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_ssl_ssh_profile_data(firewall_ssl_ssh_profile_data))
+
+ if state == "present":
return fos.set('firewall',
'ssl-ssh-profile',
data=filtered_data,
vdom=vdom)
- elif firewall_ssl_ssh_profile_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'ssl-ssh-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_firewall(data, fos):
- login(data)
- methodlist = ['firewall_ssl_ssh_profile']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_ssl_ssh_profile']:
+ resp = firewall_ssl_ssh_profile(data, fos)
- fos.logout()
- return not resp['status'] == "success", resp['status'] == "success", resp
+ return not is_successful_status(resp), \
+ resp['status'] == "success", \
+ resp
def main():
fields = {
- "host": {"required": True, "type": "str"},
- "username": {"required": True, "type": "str"},
- "password": {"required": False, "type": "str", "no_log": True},
+ "host": {"required": False, "type": "str"},
+ "username": {"required": False, "type": "str"},
+ "password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
+ "ssl_verify": {"required": False, "type": "bool", "default": True},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"firewall_ssl_ssh_profile": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"caname": {"required": False, "type": "str"},
"comment": {"required": False, "type": "str"},
"ftps": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ports": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
"https": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ports": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "certificate-inspection", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
"imaps": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ports": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
- "mapi-over-https": {"required": False, "type": "str",
+ "mapi_over_https": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"},
"pop3s": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ports": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
- "rpc-over-https": {"required": False, "type": "str",
+ "rpc_over_https": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "server-cert": {"required": False, "type": "str"},
- "server-cert-mode": {"required": False, "type": "str",
+ "server_cert": {"required": False, "type": "str"},
+ "server_cert_mode": {"required": False, "type": "str",
"choices": ["re-sign", "replace"]},
"smtps": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ports": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
"ssh": {"required": False, "type": "dict",
"options": {
- "inspect-all": {"required": False, "type": "str",
+ "inspect_all": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
"ports": {"required": False, "type": "int"},
- "ssh-algorithm": {"required": False, "type": "str",
+ "ssh_algorithm": {"required": False, "type": "str",
"choices": ["compatible", "high-encryption"]},
- "ssh-policy-check": {"required": False, "type": "str",
+ "ssh_policy_check": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssh-tun-policy-check": {"required": False, "type": "str",
+ "ssh_tun_policy_check": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"status": {"required": False, "type": "str",
"choices": ["disable", "deep-inspection"]},
- "unsupported-version": {"required": False, "type": "str",
+ "unsupported_version": {"required": False, "type": "str",
"choices": ["bypass", "block"]}
}},
"ssl": {"required": False, "type": "dict",
"options": {
- "allow-invalid-server-cert": {"required": False, "type": "str",
+ "allow_invalid_server_cert": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "client-cert-request": {"required": False, "type": "str",
+ "client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "inspect-all": {"required": False, "type": "str",
+ "inspect_all": {"required": False, "type": "str",
"choices": ["disable", "certificate-inspection", "deep-inspection"]},
- "unsupported-ssl": {"required": False, "type": "str",
+ "unsupported_ssl": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "untrusted-cert": {"required": False, "type": "str",
+ "untrusted_cert": {"required": False, "type": "str",
"choices": ["allow", "block", "ignore"]}
}},
- "ssl-anomalies-log": {"required": False, "type": "str",
+ "ssl_anomalies_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-exempt": {"required": False, "type": "list",
+ "ssl_exempt": {"required": False, "type": "list",
"options": {
"address": {"required": False, "type": "str"},
"address6": {"required": False, "type": "str"},
- "fortiguard-category": {"required": False, "type": "int"},
+ "fortiguard_category": {"required": False, "type": "int"},
"id": {"required": True, "type": "int"},
"regex": {"required": False, "type": "str"},
"type": {"required": False, "type": "str",
"choices": ["fortiguard-category", "address", "address6",
"wildcard-fqdn", "regex"]},
- "wildcard-fqdn": {"required": False, "type": "str"}
+ "wildcard_fqdn": {"required": False, "type": "str"}
}},
- "ssl-exemptions-log": {"required": False, "type": "str",
+ "ssl_exemptions_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-server": {"required": False, "type": "list",
+ "ssl_server": {"required": False, "type": "list",
"options": {
- "ftps-client-cert-request": {"required": False, "type": "str",
+ "ftps_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "https-client-cert-request": {"required": False, "type": "str",
+ "https_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"id": {"required": True, "type": "int"},
- "imaps-client-cert-request": {"required": False, "type": "str",
+ "imaps_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
"ip": {"required": False, "type": "str"},
- "pop3s-client-cert-request": {"required": False, "type": "str",
+ "pop3s_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "smtps-client-cert-request": {"required": False, "type": "str",
+ "smtps_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]},
- "ssl-other-client-cert-request": {"required": False, "type": "str",
+ "ssl_other_client_cert_request": {"required": False, "type": "str",
"choices": ["bypass", "inspect", "block"]}
}},
- "untrusted-caname": {"required": False, "type": "str"},
- "use-ssl-server": {"required": False, "type": "str",
+ "untrusted_caname": {"required": False, "type": "str"},
+ "use_ssl_server": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"whitelist": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
@@ -895,15 +1004,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py b/lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py
index 3cb04e804e9..941c2db677a 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_ttl_policy
short_description: Configure TTL policies in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and ttl_policy category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and ttl_policy category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,43 +41,57 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_ttl_policy:
description:
- Configure TTL policies.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
action:
description:
- - Action to be performed on traffic matching this policy (default = deny).
+ - Action to be performed on traffic matching this policy .
+ type: str
choices:
- accept
- deny
@@ -88,38 +99,47 @@ options:
description:
- ID.
required: true
+ type: int
schedule:
description:
- Schedule object from available options. Source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group
.name.
+ type: str
service:
description:
- Service object(s) from available options. Separate multiple names with a space.
+ type: list
suboptions:
name:
description:
- Service name. Source firewall.service.custom.name firewall.service.group.name.
required: true
+ type: str
srcaddr:
description:
- Source address object(s) from available options. Separate multiple names with a space.
+ type: list
suboptions:
name:
description:
- Address name. Source firewall.address.name firewall.addrgrp.name.
required: true
+ type: str
srcintf:
description:
- Source interface name from available interfaces. Source system.zone.name system.interface.name.
+ type: str
status:
description:
- Enable/disable this TTL policy.
+ type: str
choices:
- enable
- disable
ttl:
description:
- "Value/range to match against the packet's Time to Live value (format: ttl[ - ttl_high], 1 - 255)."
+ type: str
'''
EXAMPLES = '''
@@ -129,6 +149,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure TTL policies.
fortios_firewall_ttl_policy:
@@ -137,8 +158,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
firewall_ttl_policy:
- state: "present"
action: "accept"
id: "4"
schedule: " (source firewall.schedule.onetime.name firewall.schedule.recurring.name firewall.schedule.group.name)"
@@ -213,14 +234,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
-
-fos = None
+from ansible.module_utils.connection import Connection
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
-def login(data):
+def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
+ ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@@ -228,7 +251,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_ttl_policy_data(json):
@@ -244,48 +267,66 @@ def filter_firewall_ttl_policy_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_ttl_policy(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_ttl_policy_data = data['firewall_ttl_policy']
- filtered_data = filter_firewall_ttl_policy_data(firewall_ttl_policy_data)
- if firewall_ttl_policy_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_ttl_policy_data(firewall_ttl_policy_data))
+
+ if state == "present":
return fos.set('firewall',
'ttl-policy',
data=filtered_data,
vdom=vdom)
- elif firewall_ttl_policy_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'ttl-policy',
mkey=filtered_data['id'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_ttl_policy']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_ttl_policy']:
+ resp = firewall_ttl_policy(data, fos)
- fos.logout()
- return not resp['status'] == "success", resp['status'] == "success", resp
+ return not is_successful_status(resp), \
+ resp['status'] == "success", \
+ resp
def main():
fields = {
- "host": {"required": True, "type": "str"},
- "username": {"required": True, "type": "str"},
- "password": {"required": False, "type": "str", "no_log": True},
+ "host": {"required": False, "type": "str"},
+ "username": {"required": False, "type": "str"},
+ "password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
+ "ssl_verify": {"required": False, "type": "bool", "default": True},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"firewall_ttl_policy": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"action": {"required": False, "type": "str",
"choices": ["accept", "deny"]},
"id": {"required": True, "type": "int"},
@@ -309,15 +350,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vip.py b/lib/ansible/modules/network/fortios/fortios_firewall_vip.py
index 86f9b44fb50..79a09f002ef 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vip.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vip.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vip
short_description: Configure virtual IP for IPv4 in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vip category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vip 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,129 +41,164 @@ 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
firewall_vip:
description:
- Configure virtual IP for IPv4.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
- arp-reply:
+ arp_reply:
description:
- Enable to respond to ARP requests for this virtual IP address. Enabled by default.
+ type: str
choices:
- disable
- enable
color:
description:
- Color of icon on the GUI.
+ type: int
comment:
description:
- Comment.
- dns-mapping-ttl:
+ type: str
+ dns_mapping_ttl:
description:
- - DNS mapping TTL (Set to zero to use TTL in DNS response, default = 0).
+ - DNS mapping TTL (Set to zero to use TTL in DNS response).
+ type: int
extaddr:
description:
- External FQDN address name.
+ type: list
suboptions:
name:
description:
- Address name. Source firewall.address.name firewall.addrgrp.name.
required: true
+ type: str
extintf:
description:
- Interface connected to the source network that receives the packets that will be forwarded to the destination network. Source system
.interface.name.
+ type: str
extip:
description:
- IP address or address range on the external interface that you want to map to an address or address range on the destination network.
+ type: str
extport:
description:
- Incoming port number range that you want to map to a port number range on the destination network.
- gratuitous-arp-interval:
+ type: str
+ gratuitous_arp_interval:
description:
- Enable to have the VIP send gratuitous ARPs. 0=disabled. Set from 5 up to 8640000 seconds to enable.
- http-cookie-age:
+ type: int
+ http_cookie_age:
description:
- Time in minutes that client web browsers should keep a cookie. Default is 60 seconds. 0 = no time limit.
- http-cookie-domain:
+ type: int
+ http_cookie_domain:
description:
- Domain that HTTP cookie persistence should apply to.
- http-cookie-domain-from-host:
+ type: str
+ http_cookie_domain_from_host:
description:
- Enable/disable use of HTTP cookie domain from host field in HTTP.
+ type: str
choices:
- disable
- enable
- http-cookie-generation:
+ http_cookie_generation:
description:
- Generation of HTTP cookie to be accepted. Changing invalidates all existing cookies.
- http-cookie-path:
+ type: int
+ http_cookie_path:
description:
- Limit HTTP cookie persistence to the specified path.
- http-cookie-share:
+ type: str
+ http_cookie_share:
description:
- Control sharing of cookies across virtual servers. same-ip means a cookie from one virtual server can be used by another. Disable stops
cookie sharing.
+ type: str
choices:
- disable
- same-ip
- http-ip-header:
+ http_ip_header:
description:
- For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header.
+ type: str
choices:
- enable
- disable
- http-ip-header-name:
+ http_ip_header_name:
description:
- For HTTP multiplexing, enter a custom HTTPS header name. The original client IP address is added to this header. If empty,
X-Forwarded-For is used.
- http-multiplex:
+ type: str
+ http_multiplex:
description:
- Enable/disable HTTP multiplexing.
+ type: str
choices:
- enable
- disable
- https-cookie-secure:
+ https_cookie_secure:
description:
- Enable/disable verification that inserted HTTPS cookies are secure.
+ type: str
choices:
- disable
- enable
id:
description:
- Custom defined ID.
- ldb-method:
+ type: int
+ ldb_method:
description:
- Method used to distribute sessions to real servers.
+ type: str
choices:
- static
- round-robin
@@ -175,50 +207,61 @@ options:
- least-rtt
- first-alive
- http-host
- mapped-addr:
+ mapped_addr:
description:
- Mapped FQDN address name. Source firewall.address.name.
+ type: str
mappedip:
description:
- IP address or address range on the destination network to which the external IP address is mapped.
+ type: list
suboptions:
range:
description:
- Mapped IP range.
required: true
+ type: str
mappedport:
description:
- Port number range on the destination network to which the external port number range is mapped.
- max-embryonic-connections:
+ type: str
+ max_embryonic_connections:
description:
- Maximum number of incomplete connections.
+ type: int
monitor:
description:
- Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
+ type: list
suboptions:
name:
description:
- Health monitor name. Source firewall.ldb-monitor.name.
required: true
+ type: str
name:
description:
- Virtual IP name.
required: true
- nat-source-vip:
+ type: str
+ nat_source_vip:
description:
- - Enable to prevent unintended servers from using a virtual IP. Disable to use the actual IP address of the server as the source address.
+ - Enable/disable forcing the source NAT mapped IP to the external IP for all traffic.
+ type: str
choices:
- disable
- enable
- outlook-web-access:
+ outlook_web_access:
description:
- Enable to add the Front-End-Https header for Microsoft Outlook Web Access.
+ type: str
choices:
- disable
- enable
persistence:
description:
- Configure how to make sure that clients connect to the same server every time they make a request that is part of the same session.
+ type: str
choices:
- none
- http-cookie
@@ -226,18 +269,21 @@ options:
portforward:
description:
- Enable/disable port forwarding.
+ type: str
choices:
- disable
- enable
- portmapping-type:
+ portmapping_type:
description:
- Port mapping type.
+ type: str
choices:
- 1-to-1
- m-to-n
protocol:
description:
- Protocol to use when forwarding packets.
+ type: str
choices:
- tcp
- udp
@@ -246,43 +292,54 @@ options:
realservers:
description:
- Select the real servers that this server load balancing VIP will distribute traffic to.
+ type: list
suboptions:
- client-ip:
+ client_ip:
description:
- Only clients in this IP range can connect to this real server.
+ type: str
healthcheck:
description:
- Enable to check the responsiveness of the real server before forwarding traffic.
+ type: str
choices:
- disable
- enable
- vip
- holddown-interval:
+ holddown_interval:
description:
- Time in seconds that the health check monitor continues to monitor and unresponsive server that should be active.
- http-host:
+ type: int
+ http_host:
description:
- HTTP server domain name in HTTP header.
+ type: str
id:
description:
- Real server ID.
required: true
+ type: int
ip:
description:
- IP address of the real server.
- max-connections:
+ type: str
+ max_connections:
description:
- Max number of active connections that can be directed to the real server. When reached, sessions are sent to other real servers.
+ type: int
monitor:
description:
- Name of the health check monitor to use when polling to determine a virtual server's connectivity status. Source firewall
.ldb-monitor.name.
+ type: str
port:
description:
- Port for communicating with the real server. Required if port forwarding is enabled.
+ type: int
status:
description:
- Set the status of the real server to active so that it can accept traffic, or on standby or disabled so no traffic is sent.
+ type: str
choices:
- active
- standby
@@ -290,9 +347,11 @@ options:
weight:
description:
- Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more connections.
- server-type:
+ type: int
+ server_type:
description:
- Protocol to be load balanced by the virtual server (also called the server load balance virtual IP).
+ type: str
choices:
- http
- https
@@ -306,45 +365,54 @@ options:
service:
description:
- Service name.
+ type: list
suboptions:
name:
description:
- Service name. Source firewall.service.custom.name firewall.service.group.name.
required: true
- src-filter:
+ type: str
+ src_filter:
description:
- Source address filter. Each address must be either an IP/subnet (x.x.x.x/n) or a range (x.x.x.x-y.y.y.y). Separate addresses with spaces.
+ type: list
suboptions:
range:
description:
- Source-filter range.
required: true
- srcintf-filter:
+ type: str
+ srcintf_filter:
description:
- Interfaces to which the VIP applies. Separate the names with spaces.
+ type: list
suboptions:
- interface-name:
+ interface_name:
description:
- Interface name. Source system.interface.name.
- required: true
- ssl-algorithm:
+ type: str
+ ssl_algorithm:
description:
- Permitted encryption algorithms for SSL sessions according to encryption strength.
+ type: str
choices:
- high
- medium
- low
- custom
- ssl-certificate:
+ ssl_certificate:
description:
- The name of the SSL certificate to use for SSL acceleration. Source vpn.certificate.local.name.
- ssl-cipher-suites:
+ type: str
+ ssl_cipher_suites:
description:
- SSL/TLS cipher suites acceptable from a client, ordered by priority.
+ type: list
suboptions:
cipher:
description:
- Cipher suite name.
+ type: str
choices:
- TLS-RSA-WITH-3DES-EDE-CBC-SHA
- TLS-DHE-RSA-WITH-DES-CBC-SHA
@@ -353,44 +421,52 @@ options:
description:
- SSL/TLS cipher suites priority.
required: true
+ type: int
versions:
description:
- SSL/TLS versions that the cipher suite can be used with.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-client-fallback:
+ ssl_client_fallback:
description:
- Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507).
+ type: str
choices:
- disable
- enable
- ssl-client-renegotiation:
+ ssl_client_renegotiation:
description:
- Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746.
+ type: str
choices:
- allow
- deny
- secure
- ssl-client-session-state-max:
+ ssl_client_session_state_max:
description:
- Maximum number of client to FortiGate SSL session states to keep.
- ssl-client-session-state-timeout:
+ type: int
+ ssl_client_session_state_timeout:
description:
- Number of minutes to keep client to FortiGate SSL session state.
- ssl-client-session-state-type:
+ type: int
+ ssl_client_session_state_type:
description:
- How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate.
+ type: str
choices:
- disable
- time
- count
- both
- ssl-dh-bits:
+ ssl_dh_bits:
description:
- Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions.
+ type: str
choices:
- 768
- 1024
@@ -398,111 +474,130 @@ options:
- 2048
- 3072
- 4096
- ssl-hpkp:
+ ssl_hpkp:
description:
- Enable/disable including HPKP header in response.
+ type: str
choices:
- disable
- enable
- report-only
- ssl-hpkp-age:
+ ssl_hpkp_age:
description:
- Number of seconds the client should honour the HPKP setting.
- ssl-hpkp-backup:
+ type: int
+ ssl_hpkp_backup:
description:
- Certificate to generate backup HPKP pin from. Source vpn.certificate.local.name vpn.certificate.ca.name.
- ssl-hpkp-include-subdomains:
+ type: str
+ ssl_hpkp_include_subdomains:
description:
- Indicate that HPKP header applies to all subdomains.
+ type: str
choices:
- disable
- enable
- ssl-hpkp-primary:
+ ssl_hpkp_primary:
description:
- Certificate to generate primary HPKP pin from. Source vpn.certificate.local.name vpn.certificate.ca.name.
- ssl-hpkp-report-uri:
+ type: str
+ ssl_hpkp_report_uri:
description:
- URL to report HPKP violations to.
- ssl-hsts:
+ type: str
+ ssl_hsts:
description:
- Enable/disable including HSTS header in response.
+ type: str
choices:
- disable
- enable
- ssl-hsts-age:
+ ssl_hsts_age:
description:
- Number of seconds the client should honour the HSTS setting.
- ssl-hsts-include-subdomains:
+ type: int
+ ssl_hsts_include_subdomains:
description:
- Indicate that HSTS header applies to all subdomains.
+ type: str
choices:
- disable
- enable
- ssl-http-location-conversion:
+ ssl_http_location_conversion:
description:
- Enable to replace HTTP with HTTPS in the reply's Location HTTP header field.
+ type: str
choices:
- enable
- disable
- ssl-http-match-host:
+ ssl_http_match_host:
description:
- Enable/disable HTTP host matching for location conversion.
+ type: str
choices:
- enable
- disable
- ssl-max-version:
+ ssl_max_version:
description:
- Highest SSL/TLS version acceptable from a client.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-min-version:
+ ssl_min_version:
description:
- Lowest SSL/TLS version acceptable from a client.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-mode:
+ ssl_mode:
description:
- Apply SSL offloading between the client and the FortiGate (half) or from the client to the FortiGate and from the FortiGate to the
server (full).
+ type: str
choices:
- half
- full
- ssl-pfs:
+ ssl_pfs:
description:
- Select the cipher suites that can be used for SSL perfect forward secrecy (PFS). Applies to both client and server sessions.
+ type: str
choices:
- require
- deny
- allow
- ssl-send-empty-frags:
+ ssl_send_empty_frags:
description:
- Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 & TLS 1.0 only). May need to be disabled for compatibility with
older systems.
+ type: str
choices:
- enable
- disable
- ssl-server-algorithm:
+ ssl_server_algorithm:
description:
- Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength.
+ type: str
choices:
- high
- medium
- low
- custom
- client
- ssl-server-cipher-suites:
+ ssl_server_cipher_suites:
description:
- SSL/TLS cipher suites to offer to a server, ordered by priority.
+ type: list
suboptions:
cipher:
description:
- Cipher suite name.
+ type: str
choices:
- TLS-RSA-WITH-3DES-EDE-CBC-SHA
- TLS-DHE-RSA-WITH-DES-CBC-SHA
@@ -511,41 +606,48 @@ options:
description:
- SSL/TLS cipher suites priority.
required: true
+ type: int
versions:
description:
- SSL/TLS versions that the cipher suite can be used with.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-server-max-version:
+ ssl_server_max_version:
description:
- Highest SSL/TLS version acceptable from a server. Use the client setting by default.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- client
- ssl-server-min-version:
+ ssl_server_min_version:
description:
- Lowest SSL/TLS version acceptable from a server. Use the client setting by default.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- client
- ssl-server-session-state-max:
+ ssl_server_session_state_max:
description:
- Maximum number of FortiGate to Server SSL session states to keep.
- ssl-server-session-state-timeout:
+ type: int
+ ssl_server_session_state_timeout:
description:
- Number of minutes to keep FortiGate to Server SSL session state.
- ssl-server-session-state-type:
+ type: int
+ ssl_server_session_state_type:
description:
- How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate.
+ type: str
choices:
- disable
- time
@@ -554,6 +656,7 @@ options:
type:
description:
- Configure a static NAT, load balance, server load balance, DNS translation, or FQDN VIP.
+ type: str
choices:
- static-nat
- load-balance
@@ -563,15 +666,18 @@ options:
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
- weblogic-server:
+ type: str
+ weblogic_server:
description:
- Enable to add an HTTP header to indicate SSL offloading for a WebLogic server.
+ type: str
choices:
- disable
- enable
- websphere-server:
+ websphere_server:
description:
- Enable to add an HTTP header to indicate SSL offloading for a WebSphere server.
+ type: str
choices:
- disable
- enable
@@ -584,6 +690,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure virtual IP for IPv4.
fortios_firewall_vip:
@@ -591,114 +698,115 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vip:
- state: "present"
- arp-reply: "disable"
+ arp_reply: "disable"
color: "4"
comment: "Comment."
- dns-mapping-ttl: "6"
+ dns_mapping_ttl: "6"
extaddr:
-
name: "default_name_8 (source firewall.address.name firewall.addrgrp.name)"
extintf: " (source system.interface.name)"
extip: ""
extport: ""
- gratuitous-arp-interval: "12"
- http-cookie-age: "13"
- http-cookie-domain: ""
- http-cookie-domain-from-host: "disable"
- http-cookie-generation: "16"
- http-cookie-path: ""
- http-cookie-share: "disable"
- http-ip-header: "enable"
- http-ip-header-name: ""
- http-multiplex: "enable"
- https-cookie-secure: "disable"
+ gratuitous_arp_interval: "12"
+ http_cookie_age: "13"
+ http_cookie_domain: ""
+ http_cookie_domain_from_host: "disable"
+ http_cookie_generation: "16"
+ http_cookie_path: ""
+ http_cookie_share: "disable"
+ http_ip_header: "enable"
+ http_ip_header_name: ""
+ http_multiplex: "enable"
+ https_cookie_secure: "disable"
id: "23"
- ldb-method: "static"
- mapped-addr: " (source firewall.address.name)"
+ ldb_method: "static"
+ mapped_addr: " (source firewall.address.name)"
mappedip:
-
range: ""
mappedport: ""
- max-embryonic-connections: "29"
+ max_embryonic_connections: "29"
monitor:
-
name: "default_name_31 (source firewall.ldb-monitor.name)"
name: "default_name_32"
- nat-source-vip: "disable"
- outlook-web-access: "disable"
+ nat_source_vip: "disable"
+ outlook_web_access: "disable"
persistence: "none"
portforward: "disable"
- portmapping-type: "1-to-1"
+ portmapping_type: "1-to-1"
protocol: "tcp"
realservers:
-
- client-ip: ""
+ client_ip: ""
healthcheck: "disable"
- holddown-interval: "42"
- http-host: "myhostname"
+ holddown_interval: "42"
+ http_host: "myhostname"
id: "44"
ip: ""
- max-connections: "46"
+ max_connections: "46"
monitor: " (source firewall.ldb-monitor.name)"
port: "48"
status: "active"
weight: "50"
- server-type: "http"
+ server_type: "http"
service:
-
name: "default_name_53 (source firewall.service.custom.name firewall.service.group.name)"
- src-filter:
+ src_filter:
-
range: ""
- srcintf-filter:
+ srcintf_filter:
-
- interface-name: " (source system.interface.name)"
- ssl-algorithm: "high"
- ssl-certificate: " (source vpn.certificate.local.name)"
- ssl-cipher-suites:
+ interface_name: " (source system.interface.name)"
+ ssl_algorithm: "high"
+ ssl_certificate: " (source vpn.certificate.local.name)"
+ ssl_cipher_suites:
-
cipher: "TLS-RSA-WITH-3DES-EDE-CBC-SHA"
priority: "62"
versions: "ssl-3.0"
- ssl-client-fallback: "disable"
- ssl-client-renegotiation: "allow"
- ssl-client-session-state-max: "66"
- ssl-client-session-state-timeout: "67"
- ssl-client-session-state-type: "disable"
- ssl-dh-bits: "768"
- ssl-hpkp: "disable"
- ssl-hpkp-age: "71"
- ssl-hpkp-backup: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
- ssl-hpkp-include-subdomains: "disable"
- ssl-hpkp-primary: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
- ssl-hpkp-report-uri: ""
- ssl-hsts: "disable"
- ssl-hsts-age: "77"
- ssl-hsts-include-subdomains: "disable"
- ssl-http-location-conversion: "enable"
- ssl-http-match-host: "enable"
- ssl-max-version: "ssl-3.0"
- ssl-min-version: "ssl-3.0"
- ssl-mode: "half"
- ssl-pfs: "require"
- ssl-send-empty-frags: "enable"
- ssl-server-algorithm: "high"
- ssl-server-cipher-suites:
+ ssl_client_fallback: "disable"
+ ssl_client_renegotiation: "allow"
+ ssl_client_session_state_max: "66"
+ ssl_client_session_state_timeout: "67"
+ ssl_client_session_state_type: "disable"
+ ssl_dh_bits: "768"
+ ssl_hpkp: "disable"
+ ssl_hpkp_age: "71"
+ ssl_hpkp_backup: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
+ ssl_hpkp_include_subdomains: "disable"
+ ssl_hpkp_primary: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
+ ssl_hpkp_report_uri: ""
+ ssl_hsts: "disable"
+ ssl_hsts_age: "77"
+ ssl_hsts_include_subdomains: "disable"
+ ssl_http_location_conversion: "enable"
+ ssl_http_match_host: "enable"
+ ssl_max_version: "ssl-3.0"
+ ssl_min_version: "ssl-3.0"
+ ssl_mode: "half"
+ ssl_pfs: "require"
+ ssl_send_empty_frags: "enable"
+ ssl_server_algorithm: "high"
+ ssl_server_cipher_suites:
-
cipher: "TLS-RSA-WITH-3DES-EDE-CBC-SHA"
priority: "89"
versions: "ssl-3.0"
- ssl-server-max-version: "ssl-3.0"
- ssl-server-min-version: "ssl-3.0"
- ssl-server-session-state-max: "93"
- ssl-server-session-state-timeout: "94"
- ssl-server-session-state-type: "disable"
+ ssl_server_max_version: "ssl-3.0"
+ ssl_server_min_version: "ssl-3.0"
+ ssl_server_session_state_max: "93"
+ ssl_server_session_state_timeout: "94"
+ ssl_server_session_state_type: "disable"
type: "static-nat"
uuid: ""
- weblogic-server: "disable"
- websphere-server: "disable"
+ weblogic_server: "disable"
+ websphere_server: "disable"
'''
RETURN = '''
@@ -721,7 +829,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
@@ -761,14 +869,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']:
@@ -776,35 +886,35 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vip_data(json):
- option_list = ['arp-reply', 'color', 'comment',
- 'dns-mapping-ttl', 'extaddr', 'extintf',
- 'extip', 'extport', 'gratuitous-arp-interval',
- 'http-cookie-age', 'http-cookie-domain', 'http-cookie-domain-from-host',
- 'http-cookie-generation', 'http-cookie-path', 'http-cookie-share',
- 'http-ip-header', 'http-ip-header-name', 'http-multiplex',
- 'https-cookie-secure', 'id', 'ldb-method',
- 'mapped-addr', 'mappedip', 'mappedport',
- 'max-embryonic-connections', 'monitor', 'name',
- 'nat-source-vip', 'outlook-web-access', 'persistence',
- 'portforward', 'portmapping-type', 'protocol',
- 'realservers', 'server-type', 'service',
- 'src-filter', 'srcintf-filter', 'ssl-algorithm',
- 'ssl-certificate', 'ssl-cipher-suites', 'ssl-client-fallback',
- 'ssl-client-renegotiation', 'ssl-client-session-state-max', 'ssl-client-session-state-timeout',
- 'ssl-client-session-state-type', 'ssl-dh-bits', 'ssl-hpkp',
- 'ssl-hpkp-age', 'ssl-hpkp-backup', 'ssl-hpkp-include-subdomains',
- 'ssl-hpkp-primary', 'ssl-hpkp-report-uri', 'ssl-hsts',
- 'ssl-hsts-age', 'ssl-hsts-include-subdomains', 'ssl-http-location-conversion',
- 'ssl-http-match-host', 'ssl-max-version', 'ssl-min-version',
- 'ssl-mode', 'ssl-pfs', 'ssl-send-empty-frags',
- 'ssl-server-algorithm', 'ssl-server-cipher-suites', 'ssl-server-max-version',
- 'ssl-server-min-version', 'ssl-server-session-state-max', 'ssl-server-session-state-timeout',
- 'ssl-server-session-state-type', 'type', 'uuid',
- 'weblogic-server', 'websphere-server']
+ option_list = ['arp_reply', 'color', 'comment',
+ 'dns_mapping_ttl', 'extaddr', 'extintf',
+ 'extip', 'extport', 'gratuitous_arp_interval',
+ 'http_cookie_age', 'http_cookie_domain', 'http_cookie_domain_from_host',
+ 'http_cookie_generation', 'http_cookie_path', 'http_cookie_share',
+ 'http_ip_header', 'http_ip_header_name', 'http_multiplex',
+ 'https_cookie_secure', 'id', 'ldb_method',
+ 'mapped_addr', 'mappedip', 'mappedport',
+ 'max_embryonic_connections', 'monitor', 'name',
+ 'nat_source_vip', 'outlook_web_access', 'persistence',
+ 'portforward', 'portmapping_type', 'protocol',
+ 'realservers', 'server_type', 'service',
+ 'src_filter', 'srcintf_filter', 'ssl_algorithm',
+ 'ssl_certificate', 'ssl_cipher_suites', 'ssl_client_fallback',
+ 'ssl_client_renegotiation', 'ssl_client_session_state_max', 'ssl_client_session_state_timeout',
+ 'ssl_client_session_state_type', 'ssl_dh_bits', 'ssl_hpkp',
+ 'ssl_hpkp_age', 'ssl_hpkp_backup', 'ssl_hpkp_include_subdomains',
+ 'ssl_hpkp_primary', 'ssl_hpkp_report_uri', 'ssl_hsts',
+ 'ssl_hsts_age', 'ssl_hsts_include_subdomains', 'ssl_http_location_conversion',
+ 'ssl_http_match_host', 'ssl_max_version', 'ssl_min_version',
+ 'ssl_mode', 'ssl_pfs', 'ssl_send_empty_frags',
+ 'ssl_server_algorithm', 'ssl_server_cipher_suites', 'ssl_server_max_version',
+ 'ssl_server_min_version', 'ssl_server_session_state_max', 'ssl_server_session_state_timeout',
+ 'ssl_server_session_state_type', 'type', 'uuid',
+ 'weblogic_server', 'websphere_server']
dictionary = {}
for attribute in option_list:
@@ -814,53 +924,71 @@ def filter_firewall_vip_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vip(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vip_data = data['firewall_vip']
- filtered_data = filter_firewall_vip_data(firewall_vip_data)
- if firewall_vip_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vip_data(firewall_vip_data))
+
+ if state == "present":
return fos.set('firewall',
'vip',
data=filtered_data,
vdom=vdom)
- elif firewall_vip_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vip',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vip']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vip']:
+ resp = firewall_vip(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"]},
"firewall_vip": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
- "arp-reply": {"required": False, "type": "str",
+ "arp_reply": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
- "dns-mapping-ttl": {"required": False, "type": "int"},
+ "dns_mapping_ttl": {"required": False, "type": "int"},
"extaddr": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
@@ -868,69 +996,69 @@ def main():
"extintf": {"required": False, "type": "str"},
"extip": {"required": False, "type": "str"},
"extport": {"required": False, "type": "str"},
- "gratuitous-arp-interval": {"required": False, "type": "int"},
- "http-cookie-age": {"required": False, "type": "int"},
- "http-cookie-domain": {"required": False, "type": "str"},
- "http-cookie-domain-from-host": {"required": False, "type": "str",
+ "gratuitous_arp_interval": {"required": False, "type": "int"},
+ "http_cookie_age": {"required": False, "type": "int"},
+ "http_cookie_domain": {"required": False, "type": "str"},
+ "http_cookie_domain_from_host": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "http-cookie-generation": {"required": False, "type": "int"},
- "http-cookie-path": {"required": False, "type": "str"},
- "http-cookie-share": {"required": False, "type": "str",
+ "http_cookie_generation": {"required": False, "type": "int"},
+ "http_cookie_path": {"required": False, "type": "str"},
+ "http_cookie_share": {"required": False, "type": "str",
"choices": ["disable", "same-ip"]},
- "http-ip-header": {"required": False, "type": "str",
+ "http_ip_header": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "http-ip-header-name": {"required": False, "type": "str"},
- "http-multiplex": {"required": False, "type": "str",
+ "http_ip_header_name": {"required": False, "type": "str"},
+ "http_multiplex": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "https-cookie-secure": {"required": False, "type": "str",
+ "https_cookie_secure": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"id": {"required": False, "type": "int"},
- "ldb-method": {"required": False, "type": "str",
+ "ldb_method": {"required": False, "type": "str",
"choices": ["static", "round-robin", "weighted",
"least-session", "least-rtt", "first-alive",
"http-host"]},
- "mapped-addr": {"required": False, "type": "str"},
+ "mapped_addr": {"required": False, "type": "str"},
"mappedip": {"required": False, "type": "list",
"options": {
"range": {"required": True, "type": "str"}
}},
"mappedport": {"required": False, "type": "str"},
- "max-embryonic-connections": {"required": False, "type": "int"},
+ "max_embryonic_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"name": {"required": True, "type": "str"},
- "nat-source-vip": {"required": False, "type": "str",
+ "nat_source_vip": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "outlook-web-access": {"required": False, "type": "str",
+ "outlook_web_access": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"persistence": {"required": False, "type": "str",
"choices": ["none", "http-cookie", "ssl-session-id"]},
"portforward": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "portmapping-type": {"required": False, "type": "str",
+ "portmapping_type": {"required": False, "type": "str",
"choices": ["1-to-1", "m-to-n"]},
"protocol": {"required": False, "type": "str",
"choices": ["tcp", "udp", "sctp",
"icmp"]},
"realservers": {"required": False, "type": "list",
"options": {
- "client-ip": {"required": False, "type": "str"},
+ "client_ip": {"required": False, "type": "str"},
"healthcheck": {"required": False, "type": "str",
"choices": ["disable", "enable", "vip"]},
- "holddown-interval": {"required": False, "type": "int"},
- "http-host": {"required": False, "type": "str"},
+ "holddown_interval": {"required": False, "type": "int"},
+ "http_host": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"ip": {"required": False, "type": "str"},
- "max-connections": {"required": False, "type": "int"},
+ "max_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "str"},
"port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["active", "standby", "disable"]},
"weight": {"required": False, "type": "int"}
}},
- "server-type": {"required": False, "type": "str",
+ "server_type": {"required": False, "type": "str",
"choices": ["http", "https", "imaps",
"pop3s", "smtps", "ssl",
"tcp", "udp", "ip"]},
@@ -938,102 +1066,100 @@ def main():
"options": {
"name": {"required": True, "type": "str"}
}},
- "src-filter": {"required": False, "type": "list",
+ "src_filter": {"required": False, "type": "list",
"options": {
"range": {"required": True, "type": "str"}
}},
- "srcintf-filter": {"required": False, "type": "list",
+ "srcintf_filter": {"required": False, "type": "list",
"options": {
- "interface-name": {"required": True, "type": "str"}
+ "interface_name": {"required": False, "type": "str"}
}},
- "ssl-algorithm": {"required": False, "type": "str",
+ "ssl_algorithm": {"required": False, "type": "str",
"choices": ["high", "medium", "low",
"custom"]},
- "ssl-certificate": {"required": False, "type": "str"},
- "ssl-cipher-suites": {"required": False, "type": "list",
+ "ssl_certificate": {"required": False, "type": "str"},
+ "ssl_cipher_suites": {"required": False, "type": "list",
"options": {
"cipher": {"required": False, "type": "str",
- "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
+ "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA",
"TLS-DHE-DSS-WITH-DES-CBC-SHA"]},
"priority": {"required": True, "type": "int"},
"versions": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]}
}},
- "ssl-client-fallback": {"required": False, "type": "str",
+ "ssl_client_fallback": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-client-renegotiation": {"required": False, "type": "str",
+ "ssl_client_renegotiation": {"required": False, "type": "str",
"choices": ["allow", "deny", "secure"]},
- "ssl-client-session-state-max": {"required": False, "type": "int"},
- "ssl-client-session-state-timeout": {"required": False, "type": "int"},
- "ssl-client-session-state-type": {"required": False, "type": "str",
+ "ssl_client_session_state_max": {"required": False, "type": "int"},
+ "ssl_client_session_state_timeout": {"required": False, "type": "int"},
+ "ssl_client_session_state_type": {"required": False, "type": "str",
"choices": ["disable", "time", "count",
"both"]},
- "ssl-dh-bits": {"required": False, "type": "str",
+ "ssl_dh_bits": {"required": False, "type": "str",
"choices": ["768", "1024", "1536",
"2048", "3072", "4096"]},
- "ssl-hpkp": {"required": False, "type": "str",
+ "ssl_hpkp": {"required": False, "type": "str",
"choices": ["disable", "enable", "report-only"]},
- "ssl-hpkp-age": {"required": False, "type": "int"},
- "ssl-hpkp-backup": {"required": False, "type": "str"},
- "ssl-hpkp-include-subdomains": {"required": False, "type": "str",
+ "ssl_hpkp_age": {"required": False, "type": "int"},
+ "ssl_hpkp_backup": {"required": False, "type": "str"},
+ "ssl_hpkp_include_subdomains": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-hpkp-primary": {"required": False, "type": "str"},
- "ssl-hpkp-report-uri": {"required": False, "type": "str"},
- "ssl-hsts": {"required": False, "type": "str",
+ "ssl_hpkp_primary": {"required": False, "type": "str"},
+ "ssl_hpkp_report_uri": {"required": False, "type": "str"},
+ "ssl_hsts": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-hsts-age": {"required": False, "type": "int"},
- "ssl-hsts-include-subdomains": {"required": False, "type": "str",
+ "ssl_hsts_age": {"required": False, "type": "int"},
+ "ssl_hsts_include_subdomains": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-http-location-conversion": {"required": False, "type": "str",
+ "ssl_http_location_conversion": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-http-match-host": {"required": False, "type": "str",
+ "ssl_http_match_host": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-max-version": {"required": False, "type": "str",
+ "ssl_max_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]},
- "ssl-min-version": {"required": False, "type": "str",
+ "ssl_min_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]},
- "ssl-mode": {"required": False, "type": "str",
+ "ssl_mode": {"required": False, "type": "str",
"choices": ["half", "full"]},
- "ssl-pfs": {"required": False, "type": "str",
+ "ssl_pfs": {"required": False, "type": "str",
"choices": ["require", "deny", "allow"]},
- "ssl-send-empty-frags": {"required": False, "type": "str",
+ "ssl_send_empty_frags": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-server-algorithm": {"required": False, "type": "str",
+ "ssl_server_algorithm": {"required": False, "type": "str",
"choices": ["high", "medium", "low",
"custom", "client"]},
- "ssl-server-cipher-suites": {"required": False, "type": "list",
+ "ssl_server_cipher_suites": {"required": False, "type": "list",
"options": {
"cipher": {"required": False, "type": "str",
- "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
+ "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA",
"TLS-DHE-DSS-WITH-DES-CBC-SHA"]},
"priority": {"required": True, "type": "int"},
"versions": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]}
}},
- "ssl-server-max-version": {"required": False, "type": "str",
+ "ssl_server_max_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2", "client"]},
- "ssl-server-min-version": {"required": False, "type": "str",
+ "ssl_server_min_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2", "client"]},
- "ssl-server-session-state-max": {"required": False, "type": "int"},
- "ssl-server-session-state-timeout": {"required": False, "type": "int"},
- "ssl-server-session-state-type": {"required": False, "type": "str",
+ "ssl_server_session_state_max": {"required": False, "type": "int"},
+ "ssl_server_session_state_timeout": {"required": False, "type": "int"},
+ "ssl_server_session_state_type": {"required": False, "type": "str",
"choices": ["disable", "time", "count",
"both"]},
"type": {"required": False, "type": "str",
"choices": ["static-nat", "load-balance", "server-load-balance",
"dns-translation", "fqdn"]},
"uuid": {"required": False, "type": "str"},
- "weblogic-server": {"required": False, "type": "str",
+ "weblogic_server": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "websphere-server": {"required": False, "type": "str",
+ "websphere_server": {"required": False, "type": "str",
"choices": ["disable", "enable"]}
}
@@ -1042,15 +1168,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vip46.py b/lib/ansible/modules/network/fortios/fortios_firewall_vip46.py
index 1409e9a79e0..90f70a0c892 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vip46.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vip46.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vip46
short_description: Configure IPv4 to IPv6 virtual IPs in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vip46 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vip46 category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,64 +41,84 @@ 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vip46:
description:
- Configure IPv4 to IPv6 virtual IPs.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
- arp-reply:
+ arp_reply:
description:
- Enable ARP reply.
+ type: str
choices:
- disable
- enable
color:
description:
- Color of icon on the GUI.
+ type: int
comment:
description:
- Comment.
+ type: str
extip:
description:
- Start-external-IP [-end-external-IP].
+ type: str
extport:
description:
- External service port.
+ type: str
id:
description:
- Custom defined id.
- ldb-method:
+ type: int
+ ldb_method:
description:
- Load balance method.
+ type: str
choices:
- static
- round-robin
@@ -112,69 +129,86 @@ options:
mappedip:
description:
- Start-mapped-IP [-end mapped-IP].
+ type: str
mappedport:
description:
- Mapped service port.
+ type: str
monitor:
description:
- Health monitors.
+ type: list
suboptions:
name:
description:
- Health monitor name. Source firewall.ldb-monitor.name.
required: true
+ type: str
name:
description:
- VIP46 name.
required: true
+ type: str
portforward:
description:
- Enable port forwarding.
+ type: str
choices:
- disable
- enable
protocol:
description:
- Mapped port protocol.
+ type: str
choices:
- tcp
- udp
realservers:
description:
- Real servers.
+ type: list
suboptions:
- client-ip:
+ client_ip:
description:
- Restrict server to a client IP in this range.
+ type: str
healthcheck:
description:
- Per server health check.
+ type: str
choices:
- disable
- enable
- vip
- holddown-interval:
+ holddown_interval:
description:
- Hold down interval.
+ type: int
id:
description:
- Real server ID.
required: true
+ type: int
ip:
description:
- Mapped server IPv6.
- max-connections:
+ type: str
+ max_connections:
description:
- Maximum number of connections allowed to server.
+ type: int
monitor:
description:
- Health monitors. Source firewall.ldb-monitor.name.
+ type: str
port:
description:
- Mapped server port.
+ type: int
status:
description:
- Server administrative status.
+ type: str
choices:
- active
- standby
@@ -182,31 +216,37 @@ options:
weight:
description:
- weight
- server-type:
+ type: int
+ server_type:
description:
- Server type.
+ type: str
choices:
- http
- tcp
- udp
- ip
- src-filter:
+ src_filter:
description:
- Source IP filter (x.x.x.x/x).
+ type: list
suboptions:
range:
description:
- Src-filter range.
required: true
+ type: str
type:
description:
- "VIP type: static NAT or server load balance."
+ type: str
choices:
- static-nat
- server-load-balance
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -216,6 +256,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv4 to IPv6 virtual IPs.
fortios_firewall_vip46:
@@ -223,15 +264,16 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vip46:
- state: "present"
- arp-reply: "disable"
+ arp_reply: "disable"
color: "4"
comment: "Comment."
extip: ""
extport: ""
id: "8"
- ldb-method: "static"
+ ldb_method: "static"
mappedip: ""
mappedport: ""
monitor:
@@ -242,18 +284,18 @@ EXAMPLES = '''
protocol: "tcp"
realservers:
-
- client-ip: ""
+ client_ip: ""
healthcheck: "disable"
- holddown-interval: "20"
+ holddown_interval: "20"
id: "21"
ip: ""
- max-connections: "23"
+ max_connections: "23"
monitor: " (source firewall.ldb-monitor.name)"
port: "25"
status: "active"
weight: "27"
- server-type: "http"
- src-filter:
+ server_type: "http"
+ src_filter:
-
range: ""
type: "static-nat"
@@ -280,7 +322,7 @@ mkey:
description: Master key (id) used in the last call to FortiGate
returned: success
type: str
- sample: "key1"
+ sample: "id"
name:
description: Name of the table used to fulfill the request
returned: always
@@ -320,14 +362,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
-
-fos = None
+from ansible.module_utils.connection import Connection
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
-def login(data):
+def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
+ ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@@ -335,16 +379,16 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vip46_data(json):
- option_list = ['arp-reply', 'color', 'comment',
+ option_list = ['arp_reply', 'color', 'comment',
'extip', 'extport', 'id',
- 'ldb-method', 'mappedip', 'mappedport',
+ 'ldb_method', 'mappedip', 'mappedport',
'monitor', 'name', 'portforward',
- 'protocol', 'realservers', 'server-type',
- 'src-filter', 'type', 'uuid']
+ 'protocol', 'realservers', 'server_type',
+ 'src_filter', 'type', 'uuid']
dictionary = {}
for attribute in option_list:
@@ -354,56 +398,74 @@ def filter_firewall_vip46_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vip46(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vip46_data = data['firewall_vip46']
- filtered_data = filter_firewall_vip46_data(firewall_vip46_data)
- if firewall_vip46_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vip46_data(firewall_vip46_data))
+
+ if state == "present":
return fos.set('firewall',
'vip46',
data=filtered_data,
vdom=vdom)
- elif firewall_vip46_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vip46',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vip46']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vip46']:
+ resp = firewall_vip46(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"]},
"firewall_vip46": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
- "arp-reply": {"required": False, "type": "str",
+ "arp_reply": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
"extip": {"required": False, "type": "str"},
"extport": {"required": False, "type": "str"},
"id": {"required": False, "type": "int"},
- "ldb-method": {"required": False, "type": "str",
+ "ldb_method": {"required": False, "type": "str",
"choices": ["static", "round-robin", "weighted",
"least-session", "least-rtt", "first-alive"]},
"mappedip": {"required": False, "type": "str"},
@@ -419,23 +481,23 @@ def main():
"choices": ["tcp", "udp"]},
"realservers": {"required": False, "type": "list",
"options": {
- "client-ip": {"required": False, "type": "str"},
+ "client_ip": {"required": False, "type": "str"},
"healthcheck": {"required": False, "type": "str",
"choices": ["disable", "enable", "vip"]},
- "holddown-interval": {"required": False, "type": "int"},
+ "holddown_interval": {"required": False, "type": "int"},
"id": {"required": True, "type": "int"},
"ip": {"required": False, "type": "str"},
- "max-connections": {"required": False, "type": "int"},
+ "max_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "str"},
"port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["active", "standby", "disable"]},
"weight": {"required": False, "type": "int"}
}},
- "server-type": {"required": False, "type": "str",
+ "server_type": {"required": False, "type": "str",
"choices": ["http", "tcp", "udp",
"ip"]},
- "src-filter": {"required": False, "type": "list",
+ "src_filter": {"required": False, "type": "list",
"options": {
"range": {"required": True, "type": "str"}
}},
@@ -449,15 +511,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vip6.py b/lib/ansible/modules/network/fortios/fortios_firewall_vip6.py
index 07972642e45..f5757806fe8 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vip6.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vip6.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vip6
short_description: Configure virtual IP for IPv6 in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vip6 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vip6 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,111 +41,141 @@ 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vip6:
description:
- Configure virtual IP for IPv6.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
- arp-reply:
+ arp_reply:
description:
- Enable to respond to ARP requests for this virtual IP address. Enabled by default.
+ type: str
choices:
- disable
- enable
color:
description:
- Color of icon on the GUI.
+ type: int
comment:
description:
- Comment.
+ type: str
extip:
description:
- IP address or address range on the external interface that you want to map to an address or address range on the destination network.
+ type: str
extport:
description:
- Incoming port number range that you want to map to a port number range on the destination network.
- http-cookie-age:
+ type: str
+ http_cookie_age:
description:
- Time in minutes that client web browsers should keep a cookie. Default is 60 seconds. 0 = no time limit.
- http-cookie-domain:
+ type: int
+ http_cookie_domain:
description:
- Domain that HTTP cookie persistence should apply to.
- http-cookie-domain-from-host:
+ type: str
+ http_cookie_domain_from_host:
description:
- Enable/disable use of HTTP cookie domain from host field in HTTP.
+ type: str
choices:
- disable
- enable
- http-cookie-generation:
+ http_cookie_generation:
description:
- Generation of HTTP cookie to be accepted. Changing invalidates all existing cookies.
- http-cookie-path:
+ type: int
+ http_cookie_path:
description:
- Limit HTTP cookie persistence to the specified path.
- http-cookie-share:
+ type: str
+ http_cookie_share:
description:
- Control sharing of cookies across virtual servers. same-ip means a cookie from one virtual server can be used by another. Disable stops
cookie sharing.
+ type: str
choices:
- disable
- same-ip
- http-ip-header:
+ http_ip_header:
description:
- For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header.
+ type: str
choices:
- enable
- disable
- http-ip-header-name:
+ http_ip_header_name:
description:
- For HTTP multiplexing, enter a custom HTTPS header name. The original client IP address is added to this header. If empty,
X-Forwarded-For is used.
- http-multiplex:
+ type: str
+ http_multiplex:
description:
- Enable/disable HTTP multiplexing.
+ type: str
choices:
- enable
- disable
- https-cookie-secure:
+ https_cookie_secure:
description:
- Enable/disable verification that inserted HTTPS cookies are secure.
+ type: str
choices:
- disable
- enable
id:
description:
- Custom defined ID.
- ldb-method:
+ type: int
+ ldb_method:
description:
- Method used to distribute sessions to real servers.
+ type: str
choices:
- static
- round-robin
@@ -160,33 +187,41 @@ options:
mappedip:
description:
- Mapped IP address range in the format startIP-endIP.
+ type: str
mappedport:
description:
- Port number range on the destination network to which the external port number range is mapped.
- max-embryonic-connections:
+ type: str
+ max_embryonic_connections:
description:
- Maximum number of incomplete connections.
+ type: int
monitor:
description:
- Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
+ type: list
suboptions:
name:
description:
- Health monitor name. Source firewall.ldb-monitor.name.
required: true
+ type: str
name:
description:
- Virtual ip6 name.
required: true
- outlook-web-access:
+ type: str
+ outlook_web_access:
description:
- Enable to add the Front-End-Https header for Microsoft Outlook Web Access.
+ type: str
choices:
- disable
- enable
persistence:
description:
- Configure how to make sure that clients connect to the same server every time they make a request that is part of the same session.
+ type: str
choices:
- none
- http-cookie
@@ -194,12 +229,14 @@ options:
portforward:
description:
- Enable port forwarding.
+ type: str
choices:
- disable
- enable
protocol:
description:
- Protocol to use when forwarding packets.
+ type: str
choices:
- tcp
- udp
@@ -207,43 +244,54 @@ options:
realservers:
description:
- Select the real servers that this server load balancing VIP will distribute traffic to.
+ type: list
suboptions:
- client-ip:
+ client_ip:
description:
- Only clients in this IP range can connect to this real server.
+ type: str
healthcheck:
description:
- Enable to check the responsiveness of the real server before forwarding traffic.
+ type: str
choices:
- disable
- enable
- vip
- holddown-interval:
+ holddown_interval:
description:
- Time in seconds that the health check monitor continues to monitor an unresponsive server that should be active.
- http-host:
+ type: int
+ http_host:
description:
- HTTP server domain name in HTTP header.
+ type: str
id:
description:
- Real server ID.
required: true
+ type: int
ip:
description:
- IPv6 address of the real server.
- max-connections:
+ type: str
+ max_connections:
description:
- Max number of active connections that can directed to the real server. When reached, sessions are sent to other real servers.
+ type: int
monitor:
description:
- Name of the health check monitor to use when polling to determine a virtual server's connectivity status. Source firewall
.ldb-monitor.name.
+ type: str
port:
description:
- Port for communicating with the real server. Required if port forwarding is enabled.
+ type: int
status:
description:
- Set the status of the real server to active so that it can accept traffic, or on standby or disabled so no traffic is sent.
+ type: str
choices:
- active
- standby
@@ -251,9 +299,11 @@ options:
weight:
description:
- Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more connections.
- server-type:
+ type: int
+ server_type:
description:
- Protocol to be load balanced by the virtual server (also called the server load balance virtual IP).
+ type: str
choices:
- http
- https
@@ -264,32 +314,38 @@ options:
- tcp
- udp
- ip
- src-filter:
+ src_filter:
description:
- "Source IP6 filter (x:x:x:x:x:x:x:x/x). Separate addresses with spaces."
+ type: list
suboptions:
range:
description:
- Source-filter range.
required: true
- ssl-algorithm:
+ type: str
+ ssl_algorithm:
description:
- Permitted encryption algorithms for SSL sessions according to encryption strength.
+ type: str
choices:
- high
- medium
- low
- custom
- ssl-certificate:
+ ssl_certificate:
description:
- The name of the SSL certificate to use for SSL acceleration. Source vpn.certificate.local.name.
- ssl-cipher-suites:
+ type: str
+ ssl_cipher_suites:
description:
- SSL/TLS cipher suites acceptable from a client, ordered by priority.
+ type: list
suboptions:
cipher:
description:
- Cipher suite name.
+ type: str
choices:
- TLS-RSA-WITH-3DES-EDE-CBC-SHA
- TLS-DHE-RSA-WITH-DES-CBC-SHA
@@ -298,44 +354,52 @@ options:
description:
- SSL/TLS cipher suites priority.
required: true
+ type: int
versions:
description:
- SSL/TLS versions that the cipher suite can be used with.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-client-fallback:
+ ssl_client_fallback:
description:
- Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507).
+ type: str
choices:
- disable
- enable
- ssl-client-renegotiation:
+ ssl_client_renegotiation:
description:
- Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746.
+ type: str
choices:
- allow
- deny
- secure
- ssl-client-session-state-max:
+ ssl_client_session_state_max:
description:
- Maximum number of client to FortiGate SSL session states to keep.
- ssl-client-session-state-timeout:
+ type: int
+ ssl_client_session_state_timeout:
description:
- Number of minutes to keep client to FortiGate SSL session state.
- ssl-client-session-state-type:
+ type: int
+ ssl_client_session_state_type:
description:
- How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate.
+ type: str
choices:
- disable
- time
- count
- both
- ssl-dh-bits:
+ ssl_dh_bits:
description:
- Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions.
+ type: str
choices:
- 768
- 1024
@@ -343,111 +407,130 @@ options:
- 2048
- 3072
- 4096
- ssl-hpkp:
+ ssl_hpkp:
description:
- Enable/disable including HPKP header in response.
+ type: str
choices:
- disable
- enable
- report-only
- ssl-hpkp-age:
+ ssl_hpkp_age:
description:
- Number of minutes the web browser should keep HPKP.
- ssl-hpkp-backup:
+ type: int
+ ssl_hpkp_backup:
description:
- Certificate to generate backup HPKP pin from. Source vpn.certificate.local.name vpn.certificate.ca.name.
- ssl-hpkp-include-subdomains:
+ type: str
+ ssl_hpkp_include_subdomains:
description:
- Indicate that HPKP header applies to all subdomains.
+ type: str
choices:
- disable
- enable
- ssl-hpkp-primary:
+ ssl_hpkp_primary:
description:
- Certificate to generate primary HPKP pin from. Source vpn.certificate.local.name vpn.certificate.ca.name.
- ssl-hpkp-report-uri:
+ type: str
+ ssl_hpkp_report_uri:
description:
- URL to report HPKP violations to.
- ssl-hsts:
+ type: str
+ ssl_hsts:
description:
- Enable/disable including HSTS header in response.
+ type: str
choices:
- disable
- enable
- ssl-hsts-age:
+ ssl_hsts_age:
description:
- Number of seconds the client should honour the HSTS setting.
- ssl-hsts-include-subdomains:
+ type: int
+ ssl_hsts_include_subdomains:
description:
- Indicate that HSTS header applies to all subdomains.
+ type: str
choices:
- disable
- enable
- ssl-http-location-conversion:
+ ssl_http_location_conversion:
description:
- Enable to replace HTTP with HTTPS in the reply's Location HTTP header field.
+ type: str
choices:
- enable
- disable
- ssl-http-match-host:
+ ssl_http_match_host:
description:
- Enable/disable HTTP host matching for location conversion.
+ type: str
choices:
- enable
- disable
- ssl-max-version:
+ ssl_max_version:
description:
- Highest SSL/TLS version acceptable from a client.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-min-version:
+ ssl_min_version:
description:
- Lowest SSL/TLS version acceptable from a client.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-mode:
+ ssl_mode:
description:
- Apply SSL offloading between the client and the FortiGate (half) or from the client to the FortiGate and from the FortiGate to the
server (full).
+ type: str
choices:
- half
- full
- ssl-pfs:
+ ssl_pfs:
description:
- Select the cipher suites that can be used for SSL perfect forward secrecy (PFS). Applies to both client and server sessions.
+ type: str
choices:
- require
- deny
- allow
- ssl-send-empty-frags:
+ ssl_send_empty_frags:
description:
- Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 & TLS 1.0 only). May need to be disabled for compatibility with
older systems.
+ type: str
choices:
- enable
- disable
- ssl-server-algorithm:
+ ssl_server_algorithm:
description:
- Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength.
+ type: str
choices:
- high
- medium
- low
- custom
- client
- ssl-server-cipher-suites:
+ ssl_server_cipher_suites:
description:
- SSL/TLS cipher suites to offer to a server, ordered by priority.
+ type: list
suboptions:
cipher:
description:
- Cipher suite name.
+ type: str
choices:
- TLS-RSA-WITH-3DES-EDE-CBC-SHA
- TLS-DHE-RSA-WITH-DES-CBC-SHA
@@ -456,41 +539,48 @@ options:
description:
- SSL/TLS cipher suites priority.
required: true
+ type: int
versions:
description:
- SSL/TLS versions that the cipher suite can be used with.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- ssl-server-max-version:
+ ssl_server_max_version:
description:
- Highest SSL/TLS version acceptable from a server. Use the client setting by default.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- client
- ssl-server-min-version:
+ ssl_server_min_version:
description:
- Lowest SSL/TLS version acceptable from a server. Use the client setting by default.
+ type: str
choices:
- ssl-3.0
- tls-1.0
- tls-1.1
- tls-1.2
- client
- ssl-server-session-state-max:
+ ssl_server_session_state_max:
description:
- Maximum number of FortiGate to Server SSL session states to keep.
- ssl-server-session-state-timeout:
+ type: int
+ ssl_server_session_state_timeout:
description:
- Number of minutes to keep FortiGate to Server SSL session state.
- ssl-server-session-state-type:
+ type: int
+ ssl_server_session_state_type:
description:
- How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate.
+ type: str
choices:
- disable
- time
@@ -499,21 +589,25 @@ options:
type:
description:
- Configure a static NAT or server load balance VIP.
+ type: str
choices:
- static-nat
- server-load-balance
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
- weblogic-server:
+ type: str
+ weblogic_server:
description:
- Enable to add an HTTP header to indicate SSL offloading for a WebLogic server.
+ type: str
choices:
- disable
- enable
- websphere-server:
+ websphere_server:
description:
- Enable to add an HTTP header to indicate SSL offloading for a WebSphere server.
+ type: str
choices:
- disable
- enable
@@ -526,6 +620,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure virtual IP for IPv6.
fortios_firewall_vip6:
@@ -533,97 +628,98 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vip6:
- state: "present"
- arp-reply: "disable"
+ arp_reply: "disable"
color: "4"
comment: "Comment."
extip: ""
extport: ""
- http-cookie-age: "8"
- http-cookie-domain: ""
- http-cookie-domain-from-host: "disable"
- http-cookie-generation: "11"
- http-cookie-path: ""
- http-cookie-share: "disable"
- http-ip-header: "enable"
- http-ip-header-name: ""
- http-multiplex: "enable"
- https-cookie-secure: "disable"
+ http_cookie_age: "8"
+ http_cookie_domain: ""
+ http_cookie_domain_from_host: "disable"
+ http_cookie_generation: "11"
+ http_cookie_path: ""
+ http_cookie_share: "disable"
+ http_ip_header: "enable"
+ http_ip_header_name: ""
+ http_multiplex: "enable"
+ https_cookie_secure: "disable"
id: "18"
- ldb-method: "static"
+ ldb_method: "static"
mappedip: ""
mappedport: ""
- max-embryonic-connections: "22"
+ max_embryonic_connections: "22"
monitor:
-
name: "default_name_24 (source firewall.ldb-monitor.name)"
name: "default_name_25"
- outlook-web-access: "disable"
+ outlook_web_access: "disable"
persistence: "none"
portforward: "disable"
protocol: "tcp"
realservers:
-
- client-ip: ""
+ client_ip: ""
healthcheck: "disable"
- holddown-interval: "33"
- http-host: "myhostname"
+ holddown_interval: "33"
+ http_host: "myhostname"
id: "35"
ip: ""
- max-connections: "37"
+ max_connections: "37"
monitor: " (source firewall.ldb-monitor.name)"
port: "39"
status: "active"
weight: "41"
- server-type: "http"
- src-filter:
+ server_type: "http"
+ src_filter:
-
range: ""
- ssl-algorithm: "high"
- ssl-certificate: " (source vpn.certificate.local.name)"
- ssl-cipher-suites:
+ ssl_algorithm: "high"
+ ssl_certificate: " (source vpn.certificate.local.name)"
+ ssl_cipher_suites:
-
cipher: "TLS-RSA-WITH-3DES-EDE-CBC-SHA"
priority: "49"
versions: "ssl-3.0"
- ssl-client-fallback: "disable"
- ssl-client-renegotiation: "allow"
- ssl-client-session-state-max: "53"
- ssl-client-session-state-timeout: "54"
- ssl-client-session-state-type: "disable"
- ssl-dh-bits: "768"
- ssl-hpkp: "disable"
- ssl-hpkp-age: "58"
- ssl-hpkp-backup: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
- ssl-hpkp-include-subdomains: "disable"
- ssl-hpkp-primary: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
- ssl-hpkp-report-uri: ""
- ssl-hsts: "disable"
- ssl-hsts-age: "64"
- ssl-hsts-include-subdomains: "disable"
- ssl-http-location-conversion: "enable"
- ssl-http-match-host: "enable"
- ssl-max-version: "ssl-3.0"
- ssl-min-version: "ssl-3.0"
- ssl-mode: "half"
- ssl-pfs: "require"
- ssl-send-empty-frags: "enable"
- ssl-server-algorithm: "high"
- ssl-server-cipher-suites:
+ ssl_client_fallback: "disable"
+ ssl_client_renegotiation: "allow"
+ ssl_client_session_state_max: "53"
+ ssl_client_session_state_timeout: "54"
+ ssl_client_session_state_type: "disable"
+ ssl_dh_bits: "768"
+ ssl_hpkp: "disable"
+ ssl_hpkp_age: "58"
+ ssl_hpkp_backup: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
+ ssl_hpkp_include_subdomains: "disable"
+ ssl_hpkp_primary: " (source vpn.certificate.local.name vpn.certificate.ca.name)"
+ ssl_hpkp_report_uri: ""
+ ssl_hsts: "disable"
+ ssl_hsts_age: "64"
+ ssl_hsts_include_subdomains: "disable"
+ ssl_http_location_conversion: "enable"
+ ssl_http_match_host: "enable"
+ ssl_max_version: "ssl-3.0"
+ ssl_min_version: "ssl-3.0"
+ ssl_mode: "half"
+ ssl_pfs: "require"
+ ssl_send_empty_frags: "enable"
+ ssl_server_algorithm: "high"
+ ssl_server_cipher_suites:
-
cipher: "TLS-RSA-WITH-3DES-EDE-CBC-SHA"
priority: "76"
versions: "ssl-3.0"
- ssl-server-max-version: "ssl-3.0"
- ssl-server-min-version: "ssl-3.0"
- ssl-server-session-state-max: "80"
- ssl-server-session-state-timeout: "81"
- ssl-server-session-state-type: "disable"
+ ssl_server_max_version: "ssl-3.0"
+ ssl_server_min_version: "ssl-3.0"
+ ssl_server_session_state_max: "80"
+ ssl_server_session_state_timeout: "81"
+ ssl_server_session_state_type: "disable"
type: "static-nat"
uuid: ""
- weblogic-server: "disable"
- websphere-server: "disable"
+ weblogic_server: "disable"
+ websphere_server: "disable"
'''
RETURN = '''
@@ -646,7 +742,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
@@ -686,14 +782,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']:
@@ -701,32 +799,32 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vip6_data(json):
- option_list = ['arp-reply', 'color', 'comment',
- 'extip', 'extport', 'http-cookie-age',
- 'http-cookie-domain', 'http-cookie-domain-from-host', 'http-cookie-generation',
- 'http-cookie-path', 'http-cookie-share', 'http-ip-header',
- 'http-ip-header-name', 'http-multiplex', 'https-cookie-secure',
- 'id', 'ldb-method', 'mappedip',
- 'mappedport', 'max-embryonic-connections', 'monitor',
- 'name', 'outlook-web-access', 'persistence',
+ option_list = ['arp_reply', 'color', 'comment',
+ 'extip', 'extport', 'http_cookie_age',
+ 'http_cookie_domain', 'http_cookie_domain_from_host', 'http_cookie_generation',
+ 'http_cookie_path', 'http_cookie_share', 'http_ip_header',
+ 'http_ip_header_name', 'http_multiplex', 'https_cookie_secure',
+ 'id', 'ldb_method', 'mappedip',
+ 'mappedport', 'max_embryonic_connections', 'monitor',
+ 'name', 'outlook_web_access', 'persistence',
'portforward', 'protocol', 'realservers',
- 'server-type', 'src-filter', 'ssl-algorithm',
- 'ssl-certificate', 'ssl-cipher-suites', 'ssl-client-fallback',
- 'ssl-client-renegotiation', 'ssl-client-session-state-max', 'ssl-client-session-state-timeout',
- 'ssl-client-session-state-type', 'ssl-dh-bits', 'ssl-hpkp',
- 'ssl-hpkp-age', 'ssl-hpkp-backup', 'ssl-hpkp-include-subdomains',
- 'ssl-hpkp-primary', 'ssl-hpkp-report-uri', 'ssl-hsts',
- 'ssl-hsts-age', 'ssl-hsts-include-subdomains', 'ssl-http-location-conversion',
- 'ssl-http-match-host', 'ssl-max-version', 'ssl-min-version',
- 'ssl-mode', 'ssl-pfs', 'ssl-send-empty-frags',
- 'ssl-server-algorithm', 'ssl-server-cipher-suites', 'ssl-server-max-version',
- 'ssl-server-min-version', 'ssl-server-session-state-max', 'ssl-server-session-state-timeout',
- 'ssl-server-session-state-type', 'type', 'uuid',
- 'weblogic-server', 'websphere-server']
+ 'server_type', 'src_filter', 'ssl_algorithm',
+ 'ssl_certificate', 'ssl_cipher_suites', 'ssl_client_fallback',
+ 'ssl_client_renegotiation', 'ssl_client_session_state_max', 'ssl_client_session_state_timeout',
+ 'ssl_client_session_state_type', 'ssl_dh_bits', 'ssl_hpkp',
+ 'ssl_hpkp_age', 'ssl_hpkp_backup', 'ssl_hpkp_include_subdomains',
+ 'ssl_hpkp_primary', 'ssl_hpkp_report_uri', 'ssl_hsts',
+ 'ssl_hsts_age', 'ssl_hsts_include_subdomains', 'ssl_http_location_conversion',
+ 'ssl_http_match_host', 'ssl_max_version', 'ssl_min_version',
+ 'ssl_mode', 'ssl_pfs', 'ssl_send_empty_frags',
+ 'ssl_server_algorithm', 'ssl_server_cipher_suites', 'ssl_server_max_version',
+ 'ssl_server_min_version', 'ssl_server_session_state_max', 'ssl_server_session_state_timeout',
+ 'ssl_server_session_state_type', 'type', 'uuid',
+ 'weblogic_server', 'websphere_server']
dictionary = {}
for attribute in option_list:
@@ -736,83 +834,101 @@ def filter_firewall_vip6_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vip6(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vip6_data = data['firewall_vip6']
- filtered_data = filter_firewall_vip6_data(firewall_vip6_data)
- if firewall_vip6_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vip6_data(firewall_vip6_data))
+
+ if state == "present":
return fos.set('firewall',
'vip6',
data=filtered_data,
vdom=vdom)
- elif firewall_vip6_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vip6',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vip6']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vip6']:
+ resp = firewall_vip6(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"]},
"firewall_vip6": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
- "arp-reply": {"required": False, "type": "str",
+ "arp_reply": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
"extip": {"required": False, "type": "str"},
"extport": {"required": False, "type": "str"},
- "http-cookie-age": {"required": False, "type": "int"},
- "http-cookie-domain": {"required": False, "type": "str"},
- "http-cookie-domain-from-host": {"required": False, "type": "str",
+ "http_cookie_age": {"required": False, "type": "int"},
+ "http_cookie_domain": {"required": False, "type": "str"},
+ "http_cookie_domain_from_host": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "http-cookie-generation": {"required": False, "type": "int"},
- "http-cookie-path": {"required": False, "type": "str"},
- "http-cookie-share": {"required": False, "type": "str",
+ "http_cookie_generation": {"required": False, "type": "int"},
+ "http_cookie_path": {"required": False, "type": "str"},
+ "http_cookie_share": {"required": False, "type": "str",
"choices": ["disable", "same-ip"]},
- "http-ip-header": {"required": False, "type": "str",
+ "http_ip_header": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "http-ip-header-name": {"required": False, "type": "str"},
- "http-multiplex": {"required": False, "type": "str",
+ "http_ip_header_name": {"required": False, "type": "str"},
+ "http_multiplex": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "https-cookie-secure": {"required": False, "type": "str",
+ "https_cookie_secure": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"id": {"required": False, "type": "int"},
- "ldb-method": {"required": False, "type": "str",
+ "ldb_method": {"required": False, "type": "str",
"choices": ["static", "round-robin", "weighted",
"least-session", "least-rtt", "first-alive",
"http-host"]},
"mappedip": {"required": False, "type": "str"},
"mappedport": {"required": False, "type": "str"},
- "max-embryonic-connections": {"required": False, "type": "int"},
+ "max_embryonic_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"name": {"required": True, "type": "str"},
- "outlook-web-access": {"required": False, "type": "str",
+ "outlook_web_access": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"persistence": {"required": False, "type": "str",
"choices": ["none", "http-cookie", "ssl-session-id"]},
@@ -822,115 +938,113 @@ def main():
"choices": ["tcp", "udp", "sctp"]},
"realservers": {"required": False, "type": "list",
"options": {
- "client-ip": {"required": False, "type": "str"},
+ "client_ip": {"required": False, "type": "str"},
"healthcheck": {"required": False, "type": "str",
"choices": ["disable", "enable", "vip"]},
- "holddown-interval": {"required": False, "type": "int"},
- "http-host": {"required": False, "type": "str"},
+ "holddown_interval": {"required": False, "type": "int"},
+ "http_host": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"ip": {"required": False, "type": "str"},
- "max-connections": {"required": False, "type": "int"},
+ "max_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "str"},
"port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["active", "standby", "disable"]},
"weight": {"required": False, "type": "int"}
}},
- "server-type": {"required": False, "type": "str",
+ "server_type": {"required": False, "type": "str",
"choices": ["http", "https", "imaps",
"pop3s", "smtps", "ssl",
"tcp", "udp", "ip"]},
- "src-filter": {"required": False, "type": "list",
+ "src_filter": {"required": False, "type": "list",
"options": {
"range": {"required": True, "type": "str"}
}},
- "ssl-algorithm": {"required": False, "type": "str",
+ "ssl_algorithm": {"required": False, "type": "str",
"choices": ["high", "medium", "low",
"custom"]},
- "ssl-certificate": {"required": False, "type": "str"},
- "ssl-cipher-suites": {"required": False, "type": "list",
+ "ssl_certificate": {"required": False, "type": "str"},
+ "ssl_cipher_suites": {"required": False, "type": "list",
"options": {
"cipher": {"required": False, "type": "str",
- "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
+ "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA",
"TLS-DHE-DSS-WITH-DES-CBC-SHA"]},
"priority": {"required": True, "type": "int"},
"versions": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]}
}},
- "ssl-client-fallback": {"required": False, "type": "str",
+ "ssl_client_fallback": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-client-renegotiation": {"required": False, "type": "str",
+ "ssl_client_renegotiation": {"required": False, "type": "str",
"choices": ["allow", "deny", "secure"]},
- "ssl-client-session-state-max": {"required": False, "type": "int"},
- "ssl-client-session-state-timeout": {"required": False, "type": "int"},
- "ssl-client-session-state-type": {"required": False, "type": "str",
+ "ssl_client_session_state_max": {"required": False, "type": "int"},
+ "ssl_client_session_state_timeout": {"required": False, "type": "int"},
+ "ssl_client_session_state_type": {"required": False, "type": "str",
"choices": ["disable", "time", "count",
"both"]},
- "ssl-dh-bits": {"required": False, "type": "str",
+ "ssl_dh_bits": {"required": False, "type": "str",
"choices": ["768", "1024", "1536",
"2048", "3072", "4096"]},
- "ssl-hpkp": {"required": False, "type": "str",
+ "ssl_hpkp": {"required": False, "type": "str",
"choices": ["disable", "enable", "report-only"]},
- "ssl-hpkp-age": {"required": False, "type": "int"},
- "ssl-hpkp-backup": {"required": False, "type": "str"},
- "ssl-hpkp-include-subdomains": {"required": False, "type": "str",
+ "ssl_hpkp_age": {"required": False, "type": "int"},
+ "ssl_hpkp_backup": {"required": False, "type": "str"},
+ "ssl_hpkp_include_subdomains": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-hpkp-primary": {"required": False, "type": "str"},
- "ssl-hpkp-report-uri": {"required": False, "type": "str"},
- "ssl-hsts": {"required": False, "type": "str",
+ "ssl_hpkp_primary": {"required": False, "type": "str"},
+ "ssl_hpkp_report_uri": {"required": False, "type": "str"},
+ "ssl_hsts": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-hsts-age": {"required": False, "type": "int"},
- "ssl-hsts-include-subdomains": {"required": False, "type": "str",
+ "ssl_hsts_age": {"required": False, "type": "int"},
+ "ssl_hsts_include_subdomains": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "ssl-http-location-conversion": {"required": False, "type": "str",
+ "ssl_http_location_conversion": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-http-match-host": {"required": False, "type": "str",
+ "ssl_http_match_host": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-max-version": {"required": False, "type": "str",
+ "ssl_max_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]},
- "ssl-min-version": {"required": False, "type": "str",
+ "ssl_min_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]},
- "ssl-mode": {"required": False, "type": "str",
+ "ssl_mode": {"required": False, "type": "str",
"choices": ["half", "full"]},
- "ssl-pfs": {"required": False, "type": "str",
+ "ssl_pfs": {"required": False, "type": "str",
"choices": ["require", "deny", "allow"]},
- "ssl-send-empty-frags": {"required": False, "type": "str",
+ "ssl_send_empty_frags": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "ssl-server-algorithm": {"required": False, "type": "str",
+ "ssl_server_algorithm": {"required": False, "type": "str",
"choices": ["high", "medium", "low",
"custom", "client"]},
- "ssl-server-cipher-suites": {"required": False, "type": "list",
+ "ssl_server_cipher_suites": {"required": False, "type": "list",
"options": {
"cipher": {"required": False, "type": "str",
- "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
+ "choices": ["TLS-RSA-WITH-3DES-EDE-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA",
"TLS-DHE-DSS-WITH-DES-CBC-SHA"]},
"priority": {"required": True, "type": "int"},
"versions": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2"]}
}},
- "ssl-server-max-version": {"required": False, "type": "str",
+ "ssl_server_max_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2", "client"]},
- "ssl-server-min-version": {"required": False, "type": "str",
+ "ssl_server_min_version": {"required": False, "type": "str",
"choices": ["ssl-3.0", "tls-1.0", "tls-1.1",
"tls-1.2", "client"]},
- "ssl-server-session-state-max": {"required": False, "type": "int"},
- "ssl-server-session-state-timeout": {"required": False, "type": "int"},
- "ssl-server-session-state-type": {"required": False, "type": "str",
+ "ssl_server_session_state_max": {"required": False, "type": "int"},
+ "ssl_server_session_state_timeout": {"required": False, "type": "int"},
+ "ssl_server_session_state_type": {"required": False, "type": "str",
"choices": ["disable", "time", "count",
"both"]},
"type": {"required": False, "type": "str",
"choices": ["static-nat", "server-load-balance"]},
"uuid": {"required": False, "type": "str"},
- "weblogic-server": {"required": False, "type": "str",
+ "weblogic_server": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "websphere-server": {"required": False, "type": "str",
+ "websphere_server": {"required": False, "type": "str",
"choices": ["disable", "enable"]}
}
@@ -939,15 +1053,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vip64.py b/lib/ansible/modules/network/fortios/fortios_firewall_vip64.py
index 5d093783e78..7c45cc13903 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vip64.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vip64.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vip64
short_description: Configure IPv6 to IPv4 virtual IPs in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vip64 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vip64 category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,64 +41,84 @@ 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vip64:
description:
- Configure IPv6 to IPv4 virtual IPs.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
- arp-reply:
+ arp_reply:
description:
- Enable ARP reply.
+ type: str
choices:
- disable
- enable
color:
description:
- Color of icon on the GUI.
+ type: int
comment:
description:
- Comment.
+ type: str
extip:
description:
- Start-external-IP [-end-external-IP].
+ type: str
extport:
description:
- External service port.
+ type: str
id:
description:
- Custom defined id.
- ldb-method:
+ type: int
+ ldb_method:
description:
- Load balance method.
+ type: str
choices:
- static
- round-robin
@@ -112,69 +129,86 @@ options:
mappedip:
description:
- Start-mapped-IP [-end-mapped-IP].
+ type: str
mappedport:
description:
- Mapped service port.
+ type: str
monitor:
description:
- Health monitors.
+ type: list
suboptions:
name:
description:
- Health monitor name. Source firewall.ldb-monitor.name.
required: true
+ type: str
name:
description:
- VIP64 name.
required: true
+ type: str
portforward:
description:
- Enable port forwarding.
+ type: str
choices:
- disable
- enable
protocol:
description:
- Mapped port protocol.
+ type: str
choices:
- tcp
- udp
realservers:
description:
- Real servers.
+ type: list
suboptions:
- client-ip:
+ client_ip:
description:
- Restrict server to a client IP in this range.
+ type: str
healthcheck:
description:
- Per server health check.
+ type: str
choices:
- disable
- enable
- vip
- holddown-interval:
+ holddown_interval:
description:
- Hold down interval.
+ type: int
id:
description:
- Real server ID.
required: true
+ type: int
ip:
description:
- Mapped server IP.
- max-connections:
+ type: str
+ max_connections:
description:
- Maximum number of connections allowed to server.
+ type: int
monitor:
description:
- Health monitors. Source firewall.ldb-monitor.name.
+ type: str
port:
description:
- Mapped server port.
+ type: int
status:
description:
- Server administrative status.
+ type: str
choices:
- active
- standby
@@ -182,31 +216,37 @@ options:
weight:
description:
- weight
- server-type:
+ type: int
+ server_type:
description:
- Server type.
+ type: str
choices:
- http
- tcp
- udp
- ip
- src-filter:
+ src_filter:
description:
- "Source IP6 filter (x:x:x:x:x:x:x:x/x)."
+ type: list
suboptions:
range:
description:
- Src-filter range.
required: true
+ type: str
type:
description:
- "VIP type: static NAT or server load balance."
+ type: str
choices:
- static-nat
- server-load-balance
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -216,6 +256,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv6 to IPv4 virtual IPs.
fortios_firewall_vip64:
@@ -223,15 +264,16 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vip64:
- state: "present"
- arp-reply: "disable"
+ arp_reply: "disable"
color: "4"
comment: "Comment."
extip: ""
extport: ""
id: "8"
- ldb-method: "static"
+ ldb_method: "static"
mappedip: ""
mappedport: ""
monitor:
@@ -242,18 +284,18 @@ EXAMPLES = '''
protocol: "tcp"
realservers:
-
- client-ip: ""
+ client_ip: ""
healthcheck: "disable"
- holddown-interval: "20"
+ holddown_interval: "20"
id: "21"
ip: ""
- max-connections: "23"
+ max_connections: "23"
monitor: " (source firewall.ldb-monitor.name)"
port: "25"
status: "active"
weight: "27"
- server-type: "http"
- src-filter:
+ server_type: "http"
+ src_filter:
-
range: ""
type: "static-nat"
@@ -280,7 +322,7 @@ mkey:
description: Master key (id) used in the last call to FortiGate
returned: success
type: str
- sample: "key1"
+ sample: "id"
name:
description: Name of the table used to fulfill the request
returned: always
@@ -320,14 +362,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
-
-fos = None
+from ansible.module_utils.connection import Connection
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
-def login(data):
+def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
+ ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@@ -335,16 +379,16 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vip64_data(json):
- option_list = ['arp-reply', 'color', 'comment',
+ option_list = ['arp_reply', 'color', 'comment',
'extip', 'extport', 'id',
- 'ldb-method', 'mappedip', 'mappedport',
+ 'ldb_method', 'mappedip', 'mappedport',
'monitor', 'name', 'portforward',
- 'protocol', 'realservers', 'server-type',
- 'src-filter', 'type', 'uuid']
+ 'protocol', 'realservers', 'server_type',
+ 'src_filter', 'type', 'uuid']
dictionary = {}
for attribute in option_list:
@@ -354,56 +398,74 @@ def filter_firewall_vip64_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vip64(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vip64_data = data['firewall_vip64']
- filtered_data = filter_firewall_vip64_data(firewall_vip64_data)
- if firewall_vip64_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vip64_data(firewall_vip64_data))
+
+ if state == "present":
return fos.set('firewall',
'vip64',
data=filtered_data,
vdom=vdom)
- elif firewall_vip64_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vip64',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vip64']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vip64']:
+ resp = firewall_vip64(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"]},
"firewall_vip64": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
- "arp-reply": {"required": False, "type": "str",
+ "arp_reply": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
"extip": {"required": False, "type": "str"},
"extport": {"required": False, "type": "str"},
"id": {"required": False, "type": "int"},
- "ldb-method": {"required": False, "type": "str",
+ "ldb_method": {"required": False, "type": "str",
"choices": ["static", "round-robin", "weighted",
"least-session", "least-rtt", "first-alive"]},
"mappedip": {"required": False, "type": "str"},
@@ -419,23 +481,23 @@ def main():
"choices": ["tcp", "udp"]},
"realservers": {"required": False, "type": "list",
"options": {
- "client-ip": {"required": False, "type": "str"},
+ "client_ip": {"required": False, "type": "str"},
"healthcheck": {"required": False, "type": "str",
"choices": ["disable", "enable", "vip"]},
- "holddown-interval": {"required": False, "type": "int"},
+ "holddown_interval": {"required": False, "type": "int"},
"id": {"required": True, "type": "int"},
"ip": {"required": False, "type": "str"},
- "max-connections": {"required": False, "type": "int"},
+ "max_connections": {"required": False, "type": "int"},
"monitor": {"required": False, "type": "str"},
"port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["active", "standby", "disable"]},
"weight": {"required": False, "type": "int"}
}},
- "server-type": {"required": False, "type": "str",
+ "server_type": {"required": False, "type": "str",
"choices": ["http", "tcp", "udp",
"ip"]},
- "src-filter": {"required": False, "type": "list",
+ "src_filter": {"required": False, "type": "list",
"options": {
"range": {"required": True, "type": "str"}
}},
@@ -449,15 +511,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp.py b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp.py
index f85889ca4de..16b3017c647 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vipgrp
short_description: Configure IPv4 virtual IP groups in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vipgrp category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vipgrp category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,64 +41,84 @@ 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vipgrp:
description:
- Configure IPv4 virtual IP groups.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- - Integer value to determine the color of the icon in the GUI (range 1 to 32, default = 0, which sets the value to 1).
+ - Integer value to determine the color of the icon in the GUI (range 1 to 32).
+ type: int
comments:
description:
- Comment.
+ type: str
interface:
description:
- interface Source system.interface.name.
+ type: str
member:
description:
- Member VIP objects of the group (Separate multiple objects with a space).
+ type: list
suboptions:
name:
description:
- VIP name. Source firewall.vip.name.
required: true
+ type: str
name:
description:
- VIP group name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -111,6 +128,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv4 virtual IP groups.
fortios_firewall_vipgrp:
@@ -118,8 +136,9 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vipgrp:
- state: "present"
color: "3"
comments: ""
interface: " (source system.interface.name)"
@@ -150,7 +169,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
@@ -190,14 +209,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']:
@@ -205,7 +226,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vipgrp_data(json):
@@ -220,48 +241,66 @@ def filter_firewall_vipgrp_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vipgrp(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vipgrp_data = data['firewall_vipgrp']
- filtered_data = filter_firewall_vipgrp_data(firewall_vipgrp_data)
- if firewall_vipgrp_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vipgrp_data(firewall_vipgrp_data))
+
+ if state == "present":
return fos.set('firewall',
'vipgrp',
data=filtered_data,
vdom=vdom)
- elif firewall_vipgrp_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vipgrp',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vipgrp']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vipgrp']:
+ resp = firewall_vipgrp(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"]},
"firewall_vipgrp": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comments": {"required": False, "type": "str"},
"interface": {"required": False, "type": "str"},
@@ -278,15 +317,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp46.py b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp46.py
index fb42f196b9d..79574e6db30 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp46.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp46.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vipgrp46
short_description: Configure IPv4 to IPv6 virtual IP groups in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vipgrp46 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vipgrp46 category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,61 +41,80 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vipgrp46:
description:
- Configure IPv4 to IPv6 virtual IP groups.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- - Integer value to determine the color of the icon in the GUI (range 1 to 32, default = 0, which sets the value to 1).
+ - Integer value to determine the color of the icon in the GUI (range 1 to 32).
+ type: int
comments:
description:
- Comment.
+ type: str
member:
description:
- Member VIP objects of the group (Separate multiple objects with a space).
+ type: list
suboptions:
name:
description:
- VIP46 name. Source firewall.vip46.name.
required: true
+ type: str
name:
description:
- VIP46 group name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -108,6 +124,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv4 to IPv6 virtual IP groups.
fortios_firewall_vipgrp46:
@@ -115,8 +132,9 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vipgrp46:
- state: "present"
color: "3"
comments: ""
member:
@@ -146,7 +164,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
@@ -186,14 +204,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']:
@@ -201,7 +221,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vipgrp46_data(json):
@@ -216,48 +236,66 @@ def filter_firewall_vipgrp46_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vipgrp46(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vipgrp46_data = data['firewall_vipgrp46']
- filtered_data = filter_firewall_vipgrp46_data(firewall_vipgrp46_data)
- if firewall_vipgrp46_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vipgrp46_data(firewall_vipgrp46_data))
+
+ if state == "present":
return fos.set('firewall',
'vipgrp46',
data=filtered_data,
vdom=vdom)
- elif firewall_vipgrp46_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vipgrp46',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vipgrp46']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vipgrp46']:
+ resp = firewall_vipgrp46(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"]},
"firewall_vipgrp46": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comments": {"required": False, "type": "str"},
"member": {"required": False, "type": "list",
@@ -273,15 +311,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp6.py b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp6.py
index b3556c00ac2..87ac72b79c8 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp6.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp6.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vipgrp6
short_description: Configure IPv6 virtual IP groups in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vipgrp6 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vipgrp6 category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,61 +41,80 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vipgrp6:
description:
- Configure IPv6 virtual IP groups.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- - Integer value to determine the color of the icon in the GUI (range 1 to 32, default = 0, which sets the value to 1).
+ - Integer value to determine the color of the icon in the GUI (range 1 to 32).
+ type: int
comments:
description:
- Comment.
+ type: str
member:
description:
- Member VIP objects of the group (Separate multiple objects with a space).
+ type: list
suboptions:
name:
description:
- IPv6 VIP name. Source firewall.vip6.name.
required: true
+ type: str
name:
description:
- IPv6 VIP group name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -108,6 +124,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv6 virtual IP groups.
fortios_firewall_vipgrp6:
@@ -115,8 +132,9 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vipgrp6:
- state: "present"
color: "3"
comments: ""
member:
@@ -146,7 +164,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
@@ -186,14 +204,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']:
@@ -201,7 +221,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vipgrp6_data(json):
@@ -216,48 +236,66 @@ def filter_firewall_vipgrp6_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vipgrp6(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vipgrp6_data = data['firewall_vipgrp6']
- filtered_data = filter_firewall_vipgrp6_data(firewall_vipgrp6_data)
- if firewall_vipgrp6_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vipgrp6_data(firewall_vipgrp6_data))
+
+ if state == "present":
return fos.set('firewall',
'vipgrp6',
data=filtered_data,
vdom=vdom)
- elif firewall_vipgrp6_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vipgrp6',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vipgrp6']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vipgrp6']:
+ resp = firewall_vipgrp6(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"]},
"firewall_vipgrp6": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comments": {"required": False, "type": "str"},
"member": {"required": False, "type": "list",
@@ -273,15 +311,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp64.py b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp64.py
index 62c4f117d0b..e0e48058237 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp64.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_vipgrp64.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
-# Copyright 2018 Fortinet, Inc.
+# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_vipgrp64
short_description: Configure IPv6 to IPv4 virtual IP groups in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall feature and vipgrp64 category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall feature and vipgrp64 category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,61 +41,80 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip 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
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_vipgrp64:
description:
- Configure IPv6 to IPv4 virtual IP groups.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- - Integer value to determine the color of the icon in the GUI (range 1 to 32, default = 0, which sets the value to 1).
+ - Integer value to determine the color of the icon in the GUI (range 1 to 32).
+ type: int
comments:
description:
- Comment.
+ type: str
member:
description:
- Member VIP objects of the group (Separate multiple objects with a space).
+ type: list
suboptions:
name:
description:
- VIP64 name. Source firewall.vip64.name.
required: true
+ type: str
name:
description:
- VIP64 group name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
'''
EXAMPLES = '''
@@ -108,6 +124,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPv6 to IPv4 virtual IP groups.
fortios_firewall_vipgrp64:
@@ -115,8 +132,9 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
+ https: "False"
+ state: "present"
firewall_vipgrp64:
- state: "present"
color: "3"
comments: ""
member:
@@ -146,7 +164,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
@@ -186,14 +204,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']:
@@ -201,7 +221,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_vipgrp64_data(json):
@@ -216,48 +236,66 @@ def filter_firewall_vipgrp64_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_vipgrp64(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_vipgrp64_data = data['firewall_vipgrp64']
- filtered_data = filter_firewall_vipgrp64_data(firewall_vipgrp64_data)
- if firewall_vipgrp64_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_vipgrp64_data(firewall_vipgrp64_data))
+
+ if state == "present":
return fos.set('firewall',
'vipgrp64',
data=filtered_data,
vdom=vdom)
- elif firewall_vipgrp64_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall',
'vipgrp64',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall(data, fos):
- login(data)
- methodlist = ['firewall_vipgrp64']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_vipgrp64']:
+ resp = firewall_vipgrp64(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"]},
"firewall_vipgrp64": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comments": {"required": False, "type": "str"},
"member": {"required": False, "type": "list",
@@ -273,15 +311,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py b/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py
index e09324b5167..92385e744b3 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_wildcard_fqdn_custom
short_description: Config global/VDOM Wildcard FQDN address in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall_wildcard_fqdn feature and custom category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall_wildcard_fqdn feature and custom category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,62 +41,81 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_wildcard_fqdn_custom:
description:
- Config global/VDOM Wildcard FQDN address.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- GUI icon color.
+ type: int
comment:
description:
- Comment.
+ type: str
name:
description:
- Address name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
visibility:
description:
- Enable/disable address visibility.
+ type: str
choices:
- enable
- disable
- wildcard-fqdn:
+ wildcard_fqdn:
description:
- Wildcard FQDN.
+ type: str
'''
EXAMPLES = '''
@@ -109,6 +125,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Config global/VDOM Wildcard FQDN address.
fortios_firewall_wildcard_fqdn_custom:
@@ -117,14 +134,14 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
firewall_wildcard_fqdn_custom:
- state: "present"
color: "3"
comment: "Comment."
name: "default_name_5"
uuid: ""
visibility: "enable"
- wildcard-fqdn: ""
+ wildcard_fqdn: ""
'''
RETURN = '''
@@ -187,14 +204,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']:
@@ -202,12 +221,12 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_wildcard_fqdn_custom_data(json):
option_list = ['color', 'comment', 'name',
- 'uuid', 'visibility', 'wildcard-fqdn']
+ 'uuid', 'visibility', 'wildcard_fqdn']
dictionary = {}
for attribute in option_list:
@@ -217,55 +236,73 @@ def filter_firewall_wildcard_fqdn_custom_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_wildcard_fqdn_custom(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_wildcard_fqdn_custom_data = data['firewall_wildcard_fqdn_custom']
- filtered_data = filter_firewall_wildcard_fqdn_custom_data(firewall_wildcard_fqdn_custom_data)
- if firewall_wildcard_fqdn_custom_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_wildcard_fqdn_custom_data(firewall_wildcard_fqdn_custom_data))
+
+ if state == "present":
return fos.set('firewall.wildcard-fqdn',
'custom',
data=filtered_data,
vdom=vdom)
- elif firewall_wildcard_fqdn_custom_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall.wildcard-fqdn',
'custom',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall_wildcard_fqdn(data, fos):
- login(data)
- methodlist = ['firewall_wildcard_fqdn_custom']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_wildcard_fqdn_custom']:
+ resp = firewall_wildcard_fqdn_custom(data, fos)
- fos.logout()
- return not resp['status'] == "success", resp['status'] == "success", resp
+ return not is_successful_status(resp), \
+ resp['status'] == "success", \
+ resp
def main():
fields = {
- "host": {"required": True, "type": "str"},
- "username": {"required": True, "type": "str"},
- "password": {"required": False, "type": "str", "no_log": True},
+ "host": {"required": False, "type": "str"},
+ "username": {"required": False, "type": "str"},
+ "password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
+ "ssl_verify": {"required": False, "type": "bool", "default": True},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"firewall_wildcard_fqdn_custom": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"uuid": {"required": False, "type": "str"},
"visibility": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "wildcard-fqdn": {"required": False, "type": "str"}
+ "wildcard_fqdn": {"required": False, "type": "str"}
}
}
@@ -273,15 +310,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_firewall_wildcard_fqdn(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall_wildcard_fqdn(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall_wildcard_fqdn(module.params, fos)
+ fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)
diff --git a/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_group.py b/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_group.py
index 6565b44ca6d..ccb445378de 100644
--- a/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_group.py
+++ b/lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_group.py
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_firewall_wildcard_fqdn_group
short_description: Config global Wildcard FQDN address groups in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure firewall_wildcard_fqdn feature and group category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify firewall_wildcard_fqdn feature and group category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,64 +41,84 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
firewall_wildcard_fqdn_group:
description:
- Config global Wildcard FQDN address groups.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
color:
description:
- GUI icon color.
+ type: int
comment:
description:
- Comment.
+ type: str
member:
description:
- Address group members.
+ type: list
suboptions:
name:
description:
- Address name. Source firewall.wildcard-fqdn.custom.name.
required: true
+ type: str
name:
description:
- Address group name.
required: true
+ type: str
uuid:
description:
- Universally Unique Identifier (UUID; automatically assigned but can be manually reset).
+ type: str
visibility:
description:
- Enable/disable address visibility.
+ type: str
choices:
- enable
- disable
@@ -114,6 +131,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Config global Wildcard FQDN address groups.
fortios_firewall_wildcard_fqdn_group:
@@ -122,8 +140,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
firewall_wildcard_fqdn_group:
- state: "present"
color: "3"
comment: "Comment."
member:
@@ -194,14 +212,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']:
@@ -209,7 +229,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_firewall_wildcard_fqdn_group_data(json):
@@ -224,48 +244,66 @@ def filter_firewall_wildcard_fqdn_group_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def firewall_wildcard_fqdn_group(data, fos):
vdom = data['vdom']
+ state = data['state']
firewall_wildcard_fqdn_group_data = data['firewall_wildcard_fqdn_group']
- filtered_data = filter_firewall_wildcard_fqdn_group_data(firewall_wildcard_fqdn_group_data)
- if firewall_wildcard_fqdn_group_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_firewall_wildcard_fqdn_group_data(firewall_wildcard_fqdn_group_data))
+
+ if state == "present":
return fos.set('firewall.wildcard-fqdn',
'group',
data=filtered_data,
vdom=vdom)
- elif firewall_wildcard_fqdn_group_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('firewall.wildcard-fqdn',
'group',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_firewall_wildcard_fqdn(data, fos):
- login(data)
- methodlist = ['firewall_wildcard_fqdn_group']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['firewall_wildcard_fqdn_group']:
+ resp = firewall_wildcard_fqdn_group(data, fos)
- fos.logout()
- return not resp['status'] == "success", resp['status'] == "success", resp
+ return not is_successful_status(resp), \
+ resp['status'] == "success", \
+ resp
def main():
fields = {
- "host": {"required": True, "type": "str"},
- "username": {"required": True, "type": "str"},
- "password": {"required": False, "type": "str", "no_log": True},
+ "host": {"required": False, "type": "str"},
+ "username": {"required": False, "type": "str"},
+ "password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
+ "ssl_verify": {"required": False, "type": "bool", "default": True},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"firewall_wildcard_fqdn_group": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"color": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"},
"member": {"required": False, "type": "list",
@@ -283,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_firewall_wildcard_fqdn(module.params, fos)
+ else:
+ module.fail_json(**FAIL_SOCKET_MSG)
+ else:
+ try:
+ from fortiosapi import FortiOSAPI
+ except ImportError:
+ module.fail_json(msg="fortiosapi module is required")
+
+ fos = FortiOSAPI()
- is_error, has_changed, result = fortios_firewall_wildcard_fqdn(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_firewall_wildcard_fqdn(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_ftp_proxy_explicit.py b/lib/ansible/modules/network/fortios/fortios_ftp_proxy_explicit.py
index 3532a722d9c..fd394d9f442 100644
--- a/lib/ansible/modules/network/fortios/fortios_ftp_proxy_explicit.py
+++ b/lib/ansible/modules/network/fortios/fortios_ftp_proxy_explicit.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_ftp_proxy_explicit
short_description: Configure explicit FTP proxy settings in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ftp_proxy feature and explicit 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 ftp_proxy feature and explicit 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,52 +41,67 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
ftp_proxy_explicit:
description:
- Configure explicit FTP proxy settings.
default: null
+ type: dict
suboptions:
- incoming-ip:
+ incoming_ip:
description:
- Accept incoming FTP requests from this IP address. An interface must have this IP address.
- incoming-port:
+ type: str
+ incoming_port:
description:
- Accept incoming FTP requests on one or more ports.
- outgoing-ip:
+ type: str
+ outgoing_ip:
description:
- Outgoing FTP requests will leave from this IP address. An interface must have this IP address.
- sec-default-action:
+ type: str
+ sec_default_action:
description:
- Accept or deny explicit FTP proxy sessions when no FTP proxy firewall policy exists.
+ type: str
choices:
- accept
- deny
status:
description:
- Enable/disable the explicit FTP proxy.
+ type: str
choices:
- enable
- disable
@@ -102,6 +114,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure explicit FTP proxy settings.
fortios_ftp_proxy_explicit:
@@ -111,10 +124,10 @@ EXAMPLES = '''
vdom: "{{ vdom }}"
https: "False"
ftp_proxy_explicit:
- incoming-ip: ""
- incoming-port: ""
- outgoing-ip: ""
- sec-default-action: "accept"
+ incoming_ip: ""
+ incoming_port: ""
+ outgoing_ip: ""
+ sec_default_action: "accept"
status: "enable"
'''
@@ -178,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']:
@@ -193,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_ftp_proxy_explicit_data(json):
- option_list = ['incoming-ip', 'incoming-port', 'outgoing-ip',
- 'sec-default-action', 'status']
+ option_list = ['incoming_ip', 'incoming_port', 'outgoing_ip',
+ 'sec_default_action', 'status']
dictionary = {}
for attribute in option_list:
@@ -208,43 +223,60 @@ def filter_ftp_proxy_explicit_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 ftp_proxy_explicit(data, fos):
vdom = data['vdom']
ftp_proxy_explicit_data = data['ftp_proxy_explicit']
- filtered_data = filter_ftp_proxy_explicit_data(ftp_proxy_explicit_data)
+ filtered_data = underscore_to_hyphen(filter_ftp_proxy_explicit_data(ftp_proxy_explicit_data))
+
return fos.set('ftp-proxy',
'explicit',
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_ftp_proxy(data, fos):
- login(data)
- methodlist = ['ftp_proxy_explicit']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ftp_proxy_explicit']:
+ resp = ftp_proxy_explicit(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},
"ftp_proxy_explicit": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "incoming-ip": {"required": False, "type": "str"},
- "incoming-port": {"required": False, "type": "str"},
- "outgoing-ip": {"required": False, "type": "str"},
- "sec-default-action": {"required": False, "type": "str",
+ "incoming_ip": {"required": False, "type": "str"},
+ "incoming_port": {"required": False, "type": "str"},
+ "outgoing_ip": {"required": False, "type": "str"},
+ "sec_default_action": {"required": False, "type": "str",
"choices": ["accept", "deny"]},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
@@ -255,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_ftp_proxy(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_ftp_proxy(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ftp_proxy(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_icap_profile.py b/lib/ansible/modules/network/fortios/fortios_icap_profile.py
index 3f3ed997e35..9ca910e07ee 100644
--- a/lib/ansible/modules/network/fortios/fortios_icap_profile.py
+++ b/lib/ansible/modules/network/fortios/fortios_icap_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_icap_profile
short_description: Configure ICAP profiles in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure icap feature and profile category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify icap feature and profile category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,43 +41,57 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
icap_profile:
description:
- Configure ICAP profiles.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
methods:
description:
- The allowed HTTP methods that will be sent to ICAP server for further processing.
+ type: str
choices:
- delete
- get
@@ -94,48 +105,59 @@ options:
description:
- ICAP profile name.
required: true
- replacemsg-group:
+ type: str
+ replacemsg_group:
description:
- Replacement message group. Source system.replacemsg-group.name.
+ type: str
request:
description:
- Enable/disable whether an HTTP request is passed to an ICAP server.
+ type: str
choices:
- disable
- enable
- request-failure:
+ request_failure:
description:
- Action to take if the ICAP server cannot be contacted when processing an HTTP request.
+ type: str
choices:
- error
- bypass
- request-path:
+ request_path:
description:
- Path component of the ICAP URI that identifies the HTTP request processing service.
- request-server:
+ type: str
+ request_server:
description:
- ICAP server to use for an HTTP request. Source icap.server.name.
+ type: str
response:
description:
- Enable/disable whether an HTTP response is passed to an ICAP server.
+ type: str
choices:
- disable
- enable
- response-failure:
+ response_failure:
description:
- Action to take if the ICAP server cannot be contacted when processing an HTTP response.
+ type: str
choices:
- error
- bypass
- response-path:
+ response_path:
description:
- Path component of the ICAP URI that identifies the HTTP response processing service.
- response-server:
+ type: str
+ response_server:
description:
- ICAP server to use for an HTTP response. Source icap.server.name.
- streaming-content-bypass:
+ type: str
+ streaming_content_bypass:
description:
- Enable/disable bypassing of ICAP server for streaming content.
+ type: str
choices:
- disable
- enable
@@ -148,6 +170,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure ICAP profiles.
fortios_icap_profile:
@@ -156,20 +179,20 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
icap_profile:
- state: "present"
methods: "delete"
name: "default_name_4"
- replacemsg-group: " (source system.replacemsg-group.name)"
+ replacemsg_group: " (source system.replacemsg-group.name)"
request: "disable"
- request-failure: "error"
- request-path: ""
- request-server: " (source icap.server.name)"
+ request_failure: "error"
+ request_path: ""
+ request_server: " (source icap.server.name)"
response: "disable"
- response-failure: "error"
- response-path: ""
- response-server: " (source icap.server.name)"
- streaming-content-bypass: "disable"
+ response_failure: "error"
+ response_path: ""
+ response_server: " (source icap.server.name)"
+ streaming_content_bypass: "disable"
'''
RETURN = '''
@@ -232,14 +255,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,14 +272,14 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_icap_profile_data(json):
- option_list = ['methods', 'name', 'replacemsg-group',
- 'request', 'request-failure', 'request-path',
- 'request-server', 'response', 'response-failure',
- 'response-path', 'response-server', 'streaming-content-bypass']
+ option_list = ['methods', 'name', 'replacemsg_group',
+ 'request', 'request_failure', 'request_path',
+ 'request_server', 'response', 'response_failure',
+ 'response_path', 'response_server', 'streaming_content_bypass']
dictionary = {}
for attribute in option_list:
@@ -264,67 +289,85 @@ def filter_icap_profile_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def icap_profile(data, fos):
vdom = data['vdom']
+ state = data['state']
icap_profile_data = data['icap_profile']
- filtered_data = filter_icap_profile_data(icap_profile_data)
- if icap_profile_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_icap_profile_data(icap_profile_data))
+
+ if state == "present":
return fos.set('icap',
'profile',
data=filtered_data,
vdom=vdom)
- elif icap_profile_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('icap',
'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_icap(data, fos):
- login(data)
- methodlist = ['icap_profile']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['icap_profile']:
+ resp = icap_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"]},
"icap_profile": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"methods": {"required": False, "type": "str",
"choices": ["delete", "get", "head",
"options", "post", "put",
"trace", "other"]},
"name": {"required": True, "type": "str"},
- "replacemsg-group": {"required": False, "type": "str"},
+ "replacemsg_group": {"required": False, "type": "str"},
"request": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "request-failure": {"required": False, "type": "str",
+ "request_failure": {"required": False, "type": "str",
"choices": ["error", "bypass"]},
- "request-path": {"required": False, "type": "str"},
- "request-server": {"required": False, "type": "str"},
+ "request_path": {"required": False, "type": "str"},
+ "request_server": {"required": False, "type": "str"},
"response": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "response-failure": {"required": False, "type": "str",
+ "response_failure": {"required": False, "type": "str",
"choices": ["error", "bypass"]},
- "response-path": {"required": False, "type": "str"},
- "response-server": {"required": False, "type": "str"},
- "streaming-content-bypass": {"required": False, "type": "str",
+ "response_path": {"required": False, "type": "str"},
+ "response_server": {"required": False, "type": "str"},
+ "streaming_content_bypass": {"required": False, "type": "str",
"choices": ["disable", "enable"]}
}
@@ -333,15 +376,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_icap(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_icap(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_icap(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_icap_server.py b/lib/ansible/modules/network/fortios/fortios_icap_server.py
index 65bc37436bf..2e14636edbf 100644
--- a/lib/ansible/modules/network/fortios/fortios_icap_server.py
+++ b/lib/ansible/modules/network/fortios/fortios_icap_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_icap_server
short_description: Configure ICAP servers in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure icap feature and server category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify icap feature and server category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,62 +41,81 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
icap_server:
description:
- Configure ICAP servers.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
- ip-address:
+ ip_address:
description:
- IPv4 address of the ICAP server.
- ip-version:
+ type: str
+ ip_version:
description:
- IP version.
+ type: str
choices:
- 4
- 6
- ip6-address:
+ ip6_address:
description:
- IPv6 address of the ICAP server.
- max-connections:
+ type: str
+ max_connections:
description:
- Maximum number of concurrent connections to ICAP server.
+ type: int
name:
description:
- Server name.
required: true
+ type: str
port:
description:
- ICAP server port.
+ type: int
'''
EXAMPLES = '''
@@ -109,6 +125,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure ICAP servers.
fortios_icap_server:
@@ -117,12 +134,12 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
icap_server:
- state: "present"
- ip-address: ""
- ip-version: "4"
- ip6-address: ""
- max-connections: "6"
+ ip_address: ""
+ ip_version: "4"
+ ip6_address: ""
+ max_connections: "6"
name: "default_name_7"
port: "8"
'''
@@ -187,14 +204,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']:
@@ -202,12 +221,12 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_icap_server_data(json):
- option_list = ['ip-address', 'ip-version', 'ip6-address',
- 'max-connections', 'name', 'port']
+ option_list = ['ip_address', 'ip_version', 'ip6_address',
+ 'max_connections', 'name', 'port']
dictionary = {}
for attribute in option_list:
@@ -217,53 +236,71 @@ def filter_icap_server_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def icap_server(data, fos):
vdom = data['vdom']
+ state = data['state']
icap_server_data = data['icap_server']
- filtered_data = filter_icap_server_data(icap_server_data)
- if icap_server_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_icap_server_data(icap_server_data))
+
+ if state == "present":
return fos.set('icap',
'server',
data=filtered_data,
vdom=vdom)
- elif icap_server_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('icap',
'server',
mkey=filtered_data['name'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_icap(data, fos):
- login(data)
- methodlist = ['icap_server']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['icap_server']:
+ resp = icap_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"]},
"icap_server": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
- "ip-address": {"required": False, "type": "str"},
- "ip-version": {"required": False, "type": "str",
+ "ip_address": {"required": False, "type": "str"},
+ "ip_version": {"required": False, "type": "str",
"choices": ["4", "6"]},
- "ip6-address": {"required": False, "type": "str"},
- "max-connections": {"required": False, "type": "int"},
+ "ip6_address": {"required": False, "type": "str"},
+ "max_connections": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"},
"port": {"required": False, "type": "int"}
@@ -273,15 +310,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_icap(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_icap(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_icap(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_ips_custom.py b/lib/ansible/modules/network/fortios/fortios_ips_custom.py
index 920b238850a..d1672e12ea0 100644
--- a/lib/ansible/modules/network/fortios/fortios_ips_custom.py
+++ b/lib/ansible/modules/network/fortios/fortios_ips_custom.py
@@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#
-# the lib use python logging can get it if the following is set in your
-# Ansible config.
__metaclass__ = type
@@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_ips_custom
short_description: Configure IPS custom signature in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ips feature and custom category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify ips feature and custom category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,88 +41,114 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
ips_custom:
description:
- Configure IPS custom signature.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
action:
description:
- Default action (pass or block) for this signature.
+ type: str
choices:
- pass
- block
application:
description:
- Applications to be protected. Blank for all applications.
+ type: str
comment:
description:
- Comment.
+ type: str
location:
description:
- Protect client or server traffic.
+ type: str
log:
description:
- Enable/disable logging.
+ type: str
choices:
- disable
- enable
- log-packet:
+ log_packet:
description:
- Enable/disable packet logging.
+ type: str
choices:
- disable
- enable
os:
description:
- Operating system(s) that the signature protects. Blank for all operating systems.
+ type: str
protocol:
description:
- Protocol(s) that the signature scans. Blank for all protocols.
- rule-id:
+ type: str
+ rule_id:
description:
- Signature ID.
+ type: int
severity:
description:
- Relative severity of the signature, from info to critical. Log messages generated by the signature include the severity.
- sig-name:
+ type: str
+ sig_name:
description:
- Signature name.
+ type: str
signature:
description:
- Custom signature enclosed in single quotes.
+ type: str
status:
description:
- Enable/disable this signature.
+ type: str
choices:
- disable
- enable
@@ -133,6 +156,7 @@ options:
description:
- Signature tag.
required: true
+ type: str
'''
EXAMPLES = '''
@@ -142,6 +166,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPS custom signature.
fortios_ips_custom:
@@ -150,19 +175,19 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
ips_custom:
- state: "present"
action: "pass"
application: ""
comment: "Comment."
location: ""
log: "disable"
- log-packet: "disable"
+ log_packet: "disable"
os: ""
protocol: ""
- rule-id: "11"
+ rule_id: "11"
severity: ""
- sig-name: ""
+ sig_name: ""
signature: ""
status: "disable"
tag: ""
@@ -228,14 +253,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']:
@@ -243,14 +270,14 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_ips_custom_data(json):
option_list = ['action', 'application', 'comment',
- 'location', 'log', 'log-packet',
- 'os', 'protocol', 'rule-id',
- 'severity', 'sig-name', 'signature',
+ 'location', 'log', 'log_packet',
+ 'os', 'protocol', 'rule_id',
+ 'severity', 'sig_name', 'signature',
'status', 'tag']
dictionary = {}
@@ -261,48 +288,66 @@ def filter_ips_custom_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def ips_custom(data, fos):
vdom = data['vdom']
+ state = data['state']
ips_custom_data = data['ips_custom']
- filtered_data = filter_ips_custom_data(ips_custom_data)
- if ips_custom_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_ips_custom_data(ips_custom_data))
+
+ if state == "present":
return fos.set('ips',
'custom',
data=filtered_data,
vdom=vdom)
- elif ips_custom_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('ips',
'custom',
mkey=filtered_data['tag'],
vdom=vdom)
+def is_successful_status(status):
+ return status['status'] == "success" or \
+ status['http_method'] == "DELETE" and status['http_status'] == 404
+
+
def fortios_ips(data, fos):
- login(data)
- methodlist = ['ips_custom']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ips_custom']:
+ resp = ips_custom(data, fos)
- fos.logout()
- return not resp['status'] == "success", resp['status'] == "success", resp
+ return not is_successful_status(resp), \
+ resp['status'] == "success", \
+ resp
def main():
fields = {
- "host": {"required": True, "type": "str"},
- "username": {"required": True, "type": "str"},
- "password": {"required": False, "type": "str", "no_log": True},
+ "host": {"required": False, "type": "str"},
+ "username": {"required": False, "type": "str"},
+ "password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
+ "ssl_verify": {"required": False, "type": "bool", "default": True},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"ips_custom": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"action": {"required": False, "type": "str",
"choices": ["pass", "block"]},
"application": {"required": False, "type": "str"},
@@ -310,13 +355,13 @@ def main():
"location": {"required": False, "type": "str"},
"log": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "log-packet": {"required": False, "type": "str",
+ "log_packet": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"os": {"required": False, "type": "str"},
"protocol": {"required": False, "type": "str"},
- "rule-id": {"required": False, "type": "int"},
+ "rule_id": {"required": False, "type": "int"},
"severity": {"required": False, "type": "str"},
- "sig-name": {"required": False, "type": "str"},
+ "sig_name": {"required": False, "type": "str"},
"signature": {"required": False, "type": "str"},
"status": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
@@ -328,15 +373,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_ips(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_ips(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ips(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_ips_decoder.py b/lib/ansible/modules/network/fortios/fortios_ips_decoder.py
index 5ec15b5cdf9..9995021feb1 100644
--- a/lib/ansible/modules/network/fortios/fortios_ips_decoder.py
+++ b/lib/ansible/modules/network/fortios/fortios_ips_decoder.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_ips_decoder
short_description: Configure IPS decoder in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ips feature and decoder 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 ips feature and decoder category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,55 +41,72 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
ips_decoder:
description:
- Configure IPS decoder.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
name:
description:
- Decoder name.
required: true
+ type: str
parameter:
description:
- IPS group parameters.
+ type: list
suboptions:
name:
description:
- Parameter name.
required: true
+ type: str
value:
description:
- Parameter value.
+ type: str
'''
EXAMPLES = '''
@@ -102,6 +116,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPS decoder.
fortios_ips_decoder:
@@ -110,8 +125,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
ips_decoder:
- state: "present"
name: "default_name_3"
parameter:
-
@@ -179,14 +194,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
-
-fos = None
+from ansible.module_utils.connection import Connection
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
-def login(data):
+def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
+ ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@@ -194,7 +211,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_ips_decoder_data(json):
@@ -208,48 +225,66 @@ def filter_ips_decoder_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 ips_decoder(data, fos):
vdom = data['vdom']
+ state = data['state']
ips_decoder_data = data['ips_decoder']
- filtered_data = filter_ips_decoder_data(ips_decoder_data)
- if ips_decoder_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_ips_decoder_data(ips_decoder_data))
+
+ if state == "present":
return fos.set('ips',
'decoder',
data=filtered_data,
vdom=vdom)
- elif ips_decoder_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('ips',
'decoder',
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_ips(data, fos):
- login(data)
- methodlist = ['ips_decoder']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ips_decoder']:
+ resp = ips_decoder(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"]},
"ips_decoder": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"name": {"required": True, "type": "str"},
"parameter": {"required": False, "type": "list",
"options": {
@@ -263,15 +298,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
- try:
- from fortiosapi import FortiOSAPI
- except ImportError:
- module.fail_json(msg="fortiosapi module is required")
- global fos
- fos = FortiOSAPI()
+ # legacy_mode refers to using fortiosapi instead of HTTPAPI
+ legacy_mode = 'host' in module.params and module.params['host'] is not None and \
+ 'username' in module.params and module.params['username'] is not None and \
+ 'password' in module.params and module.params['password'] is not None
+
+ if not legacy_mode:
+ if module._socket_path:
+ connection = Connection(module._socket_path)
+ fos = FortiOSHandler(connection)
+
+ is_error, has_changed, result = fortios_ips(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_ips(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ips(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_ips_global.py b/lib/ansible/modules/network/fortios/fortios_ips_global.py
index 2b20d593cab..43134ff3322 100644
--- a/lib/ansible/modules/network/fortios/fortios_ips_global.py
+++ b/lib/ansible/modules/network/fortios/fortios_ips_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_ips_global
short_description: Configure IPS global parameter in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ips feature and global 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 ips feature and global 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,37 +41,48 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
ips_global:
description:
- Configure IPS global parameter.
default: null
+ type: dict
suboptions:
- anomaly-mode:
+ anomaly_mode:
description:
- Global blocking mode for rate-based anomalies.
+ type: str
choices:
- periodical
- continuous
@@ -82,59 +90,71 @@ options:
description:
- Regular or extended IPS database. Regular protects against the latest common and in-the-wild attacks. Extended includes protection from
legacy attacks.
+ type: str
choices:
- regular
- extended
- deep-app-insp-db-limit:
+ deep_app_insp_db_limit:
description:
- Limit on number of entries in deep application inspection database (1 - 2147483647, 0 = use recommended setting)
- deep-app-insp-timeout:
+ type: int
+ deep_app_insp_timeout:
description:
- Timeout for Deep application inspection (1 - 2147483647 sec., 0 = use recommended setting).
- engine-count:
+ type: int
+ engine_count:
description:
- Number of IPS engines running. If set to the default value of 0, FortiOS sets the number to optimize performance depending on the number
of CPU cores.
- exclude-signatures:
+ type: int
+ exclude_signatures:
description:
- Excluded signatures.
+ type: str
choices:
- none
- industrial
- fail-open:
+ fail_open:
description:
- Enable to allow traffic if the IPS process crashes. Default is disable and IPS traffic is blocked when the IPS process crashes.
+ type: str
choices:
- enable
- disable
- intelligent-mode:
+ intelligent_mode:
description:
- Enable/disable IPS adaptive scanning (intelligent mode). Intelligent mode optimizes the scanning method for the type of traffic.
+ type: str
choices:
- enable
- disable
- session-limit-mode:
+ session_limit_mode:
description:
- Method of counting concurrent sessions used by session limit anomalies. Choose between greater accuracy (accurate) or improved
performance (heuristics).
+ type: str
choices:
- accurate
- heuristic
- skype-client-public-ipaddr:
+ skype_client_public_ipaddr:
description:
- Public IP addresses of your network that receive Skype sessions. Helps identify Skype sessions. Separate IP addresses with commas.
- socket-size:
+ type: str
+ socket_size:
description:
- IPS socket buffer size (0 - 256 MB). Default depends on available memory. Can be changed to tune performance.
- sync-session-ttl:
+ type: int
+ sync_session_ttl:
description:
- Enable/disable use of kernel session TTL for IPS sessions.
+ type: str
choices:
- enable
- disable
- traffic-submit:
+ traffic_submit:
description:
- Enable/disable submitting attack data found by this FortiGate to FortiGuard.
+ type: str
choices:
- enable
- disable
@@ -147,6 +167,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPS global parameter.
fortios_ips_global:
@@ -156,19 +177,19 @@ EXAMPLES = '''
vdom: "{{ vdom }}"
https: "False"
ips_global:
- anomaly-mode: "periodical"
+ anomaly_mode: "periodical"
database: "regular"
- deep-app-insp-db-limit: "5"
- deep-app-insp-timeout: "6"
- engine-count: "7"
- exclude-signatures: "none"
- fail-open: "enable"
- intelligent-mode: "enable"
- session-limit-mode: "accurate"
- skype-client-public-ipaddr: ""
- socket-size: "13"
- sync-session-ttl: "enable"
- traffic-submit: "enable"
+ deep_app_insp_db_limit: "5"
+ deep_app_insp_timeout: "6"
+ engine_count: "7"
+ exclude_signatures: "none"
+ fail_open: "enable"
+ intelligent_mode: "enable"
+ session_limit_mode: "accurate"
+ skype_client_public_ipaddr: ""
+ socket_size: "13"
+ sync_session_ttl: "enable"
+ traffic_submit: "enable"
'''
RETURN = '''
@@ -231,14 +252,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']:
@@ -246,15 +269,15 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_ips_global_data(json):
- option_list = ['anomaly-mode', 'database', 'deep-app-insp-db-limit',
- 'deep-app-insp-timeout', 'engine-count', 'exclude-signatures',
- 'fail-open', 'intelligent-mode', 'session-limit-mode',
- 'skype-client-public-ipaddr', 'socket-size', 'sync-session-ttl',
- 'traffic-submit']
+ option_list = ['anomaly_mode', 'database', 'deep_app_insp_db_limit',
+ 'deep_app_insp_timeout', 'engine_count', 'exclude_signatures',
+ 'fail_open', 'intelligent_mode', 'session_limit_mode',
+ 'skype_client_public_ipaddr', 'socket_size', 'sync_session_ttl',
+ 'traffic_submit']
dictionary = {}
for attribute in option_list:
@@ -264,59 +287,76 @@ def filter_ips_global_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 ips_global(data, fos):
vdom = data['vdom']
ips_global_data = data['ips_global']
- filtered_data = filter_ips_global_data(ips_global_data)
+ filtered_data = underscore_to_hyphen(filter_ips_global_data(ips_global_data))
+
return fos.set('ips',
'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_ips(data, fos):
- login(data)
- methodlist = ['ips_global']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ips_global']:
+ resp = ips_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},
"ips_global": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "anomaly-mode": {"required": False, "type": "str",
+ "anomaly_mode": {"required": False, "type": "str",
"choices": ["periodical", "continuous"]},
"database": {"required": False, "type": "str",
"choices": ["regular", "extended"]},
- "deep-app-insp-db-limit": {"required": False, "type": "int"},
- "deep-app-insp-timeout": {"required": False, "type": "int"},
- "engine-count": {"required": False, "type": "int"},
- "exclude-signatures": {"required": False, "type": "str",
+ "deep_app_insp_db_limit": {"required": False, "type": "int"},
+ "deep_app_insp_timeout": {"required": False, "type": "int"},
+ "engine_count": {"required": False, "type": "int"},
+ "exclude_signatures": {"required": False, "type": "str",
"choices": ["none", "industrial"]},
- "fail-open": {"required": False, "type": "str",
+ "fail_open": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "intelligent-mode": {"required": False, "type": "str",
+ "intelligent_mode": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "session-limit-mode": {"required": False, "type": "str",
+ "session_limit_mode": {"required": False, "type": "str",
"choices": ["accurate", "heuristic"]},
- "skype-client-public-ipaddr": {"required": False, "type": "str"},
- "socket-size": {"required": False, "type": "int"},
- "sync-session-ttl": {"required": False, "type": "str",
+ "skype_client_public_ipaddr": {"required": False, "type": "str"},
+ "socket_size": {"required": False, "type": "int"},
+ "sync_session_ttl": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
- "traffic-submit": {"required": False, "type": "str",
+ "traffic_submit": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}
@@ -325,15 +365,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_ips(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_ips(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ips(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_ips_rule.py b/lib/ansible/modules/network/fortios/fortios_ips_rule.py
index cb8b13df296..aadb3b22868 100644
--- a/lib/ansible/modules/network/fortios/fortios_ips_rule.py
+++ b/lib/ansible/modules/network/fortios/fortios_ips_rule.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_ips_rule
short_description: Configure IPS rules in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ips feature and rule 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 ips feature and rule 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,137 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
ips_rule:
description:
- Configure IPS rules.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
action:
description:
- Action.
+ type: str
choices:
- pass
- block
application:
description:
- Vulnerable applications.
+ type: str
date:
description:
- Date.
+ type: int
group:
description:
- Group.
+ type: str
location:
description:
- Vulnerable location.
+ type: str
log:
description:
- Enable/disable logging.
+ type: str
choices:
- disable
- enable
- log-packet:
+ log_packet:
description:
- Enable/disable packet logging.
+ type: str
choices:
- disable
- enable
metadata:
description:
- Meta data.
+ type: list
suboptions:
id:
description:
- ID.
required: true
+ type: int
metaid:
description:
- Meta ID.
+ type: int
valueid:
description:
- Value ID.
+ type: int
name:
description:
- Rule name.
required: true
+ type: str
os:
description:
- Vulnerable operation systems.
+ type: str
rev:
description:
- Revision.
- rule-id:
+ type: int
+ rule_id:
description:
- Rule ID.
+ type: int
service:
description:
- Vulnerable service.
+ type: str
severity:
description:
- Severity.
+ type: str
status:
description:
- Enable/disable status.
+ type: str
choices:
- disable
- enable
@@ -156,6 +184,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPS rules.
fortios_ips_rule:
@@ -164,15 +193,15 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
ips_rule:
- state: "present"
action: "pass"
application: ""
date: "5"
group: ""
location: ""
log: "disable"
- log-packet: "disable"
+ log_packet: "disable"
metadata:
-
id: "11"
@@ -181,7 +210,7 @@ EXAMPLES = '''
name: "default_name_14"
os: ""
rev: "16"
- rule-id: "17"
+ rule_id: "17"
service: ""
severity: ""
status: "disable"
@@ -247,14 +276,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,14 +293,14 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_ips_rule_data(json):
option_list = ['action', 'application', 'date',
'group', 'location', 'log',
- 'log-packet', 'metadata', 'name',
- 'os', 'rev', 'rule-id',
+ 'log_packet', 'metadata', 'name',
+ 'os', 'rev', 'rule_id',
'service', 'severity', 'status']
dictionary = {}
@@ -280,48 +311,66 @@ def filter_ips_rule_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 ips_rule(data, fos):
vdom = data['vdom']
+ state = data['state']
ips_rule_data = data['ips_rule']
- filtered_data = filter_ips_rule_data(ips_rule_data)
- if ips_rule_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_ips_rule_data(ips_rule_data))
+
+ if state == "present":
return fos.set('ips',
'rule',
data=filtered_data,
vdom=vdom)
- elif ips_rule_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('ips',
'rule',
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_ips(data, fos):
- login(data)
- methodlist = ['ips_rule']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ips_rule']:
+ resp = ips_rule(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"]},
"ips_rule": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"action": {"required": False, "type": "str",
"choices": ["pass", "block"]},
"application": {"required": False, "type": "str"},
@@ -330,7 +379,7 @@ def main():
"location": {"required": False, "type": "str"},
"log": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
- "log-packet": {"required": False, "type": "str",
+ "log_packet": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"metadata": {"required": False, "type": "list",
"options": {
@@ -341,7 +390,7 @@ def main():
"name": {"required": True, "type": "str"},
"os": {"required": False, "type": "str"},
"rev": {"required": False, "type": "int"},
- "rule-id": {"required": False, "type": "int"},
+ "rule_id": {"required": False, "type": "int"},
"service": {"required": False, "type": "str"},
"severity": {"required": False, "type": "str"},
"status": {"required": False, "type": "str",
@@ -353,15 +402,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_ips(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_ips(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ips(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_ips_rule_settings.py b/lib/ansible/modules/network/fortios/fortios_ips_rule_settings.py
index 6c835f049f9..4e6e55c0a20 100644
--- a/lib/ansible/modules/network/fortios/fortios_ips_rule_settings.py
+++ b/lib/ansible/modules/network/fortios/fortios_ips_rule_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_ips_rule_settings
short_description: Configure IPS rule setting in Fortinet's FortiOS and FortiGate.
description:
- - This module is able to configure a FortiGate or FortiOS by
- allowing the user to configure ips feature and rule_settings category.
- Examples includes all options and need to be adjusted to datasources before usage.
- Tested with FOS v6.0.2
+ - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
+ user to set and modify ips feature and rule_settings category.
+ Examples include all parameters and values need to be adjusted to datasources before usage.
+ Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@@ -44,44 +41,58 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
- description:
- - FortiOS or FortiGate ip adress.
- required: true
+ description:
+ - FortiOS or FortiGate IP address.
+ type: str
+ required: false
username:
description:
- FortiOS or FortiGate username.
- required: true
+ type: str
+ required: false
password:
description:
- FortiOS or FortiGate password.
+ type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
+ type: str
default: root
https:
description:
- - Indicates if the requests towards FortiGate must use HTTPS
- protocol
+ - Indicates if the requests towards FortiGate must use HTTPS protocol.
+ type: bool
+ default: true
+ ssl_verify:
+ description:
+ - Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
+ version_added: 2.9
+ state:
+ description:
+ - Indicates whether to create or remove the object.
+ type: str
+ required: true
+ choices:
+ - present
+ - absent
+ version_added: 2.9
ips_rule_settings:
description:
- Configure IPS rule setting.
default: null
+ type: dict
suboptions:
- state:
- description:
- - Indicates whether to create or remove the object
- choices:
- - present
- - absent
id:
description:
- Rule ID.
required: true
+ type: int
'''
EXAMPLES = '''
@@ -91,6 +102,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
+ ssl_verify: "False"
tasks:
- name: Configure IPS rule setting.
fortios_ips_rule_settings:
@@ -99,8 +111,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
+ state: "present"
ips_rule_settings:
- state: "present"
id: "3"
'''
@@ -164,14 +176,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']:
@@ -179,7 +193,7 @@ def login(data):
else:
fos.https('on')
- fos.login(host, username, password)
+ fos.login(host, username, password, verify=ssl_verify)
def filter_ips_rule_settings_data(json):
@@ -193,48 +207,66 @@ def filter_ips_rule_settings_data(json):
return dictionary
+def underscore_to_hyphen(data):
+ if isinstance(data, list):
+ for elem in data:
+ elem = underscore_to_hyphen(elem)
+ elif isinstance(data, dict):
+ new_data = {}
+ for k, v in data.items():
+ new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
+ data = new_data
+
+ return data
+
+
def ips_rule_settings(data, fos):
vdom = data['vdom']
+ state = data['state']
ips_rule_settings_data = data['ips_rule_settings']
- filtered_data = filter_ips_rule_settings_data(ips_rule_settings_data)
- if ips_rule_settings_data['state'] == "present":
+ filtered_data = underscore_to_hyphen(filter_ips_rule_settings_data(ips_rule_settings_data))
+
+ if state == "present":
return fos.set('ips',
'rule-settings',
data=filtered_data,
vdom=vdom)
- elif ips_rule_settings_data['state'] == "absent":
+ elif state == "absent":
return fos.delete('ips',
'rule-settings',
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_ips(data, fos):
- login(data)
- methodlist = ['ips_rule_settings']
- for method in methodlist:
- if data[method]:
- resp = eval(method)(data, fos)
- break
+ if data['ips_rule_settings']:
+ resp = ips_rule_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},
+ "state": {"required": True, "type": "str",
+ "choices": ["present", "absent"]},
"ips_rule_settings": {
- "required": False, "type": "dict",
+ "required": False, "type": "dict", "default": None,
"options": {
- "state": {"required": True, "type": "str",
- "choices": ["present", "absent"]},
"id": {"required": True, "type": "int"}
}
@@ -243,15 +275,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_ips(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_ips(module.params, fos)
+ login(module.params, fos)
+ is_error, has_changed, result = fortios_ips(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 2613efb9f21..ebae76d439b 100644
--- a/test/sanity/ignore.txt
+++ b/test/sanity/ignore.txt
@@ -3693,38 +3693,6 @@ lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy.py validate-modu
lib/ansible/modules/network/fortios/fortios_firewall_DoS_policy6.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_firewall_policy.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_ssl_ssh_profile.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_ttl_policy.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vip.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_vip.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vip46.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_vip46.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vip6.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_vip6.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vip64.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_vip64.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vipgrp.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vipgrp46.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vipgrp6.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_vipgrp64.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_custom.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_firewall_wildcard_fqdn_group.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ftp_proxy_explicit.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_ftp_proxy_explicit.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_icap_profile.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_icap_profile.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_icap_server.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_icap_server.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ips_custom.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_ips_custom.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ips_decoder.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ips_global.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_ips_global.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ips_rule.py validate-modules:E336
-lib/ansible/modules/network/fortios/fortios_ips_rule.py validate-modules:E337
-lib/ansible/modules/network/fortios/fortios_ips_rule_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_ips_sensor.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_ips_sensor.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_ips_settings.py validate-modules:E336
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ssl_ssh_profile.py b/test/units/modules/network/fortios/test_fortios_firewall_ssl_ssh_profile.py
new file mode 100644
index 00000000000..02a2b051ad2
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_ssl_ssh_profile.py
@@ -0,0 +1,309 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_ssl_ssh_profile
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ssl_ssh_profile.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_ssl_ssh_profile_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ssl_ssh_profile': {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi-over-https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc-over-https': 'enable',
+ 'server-cert': 'test_value_8',
+ 'server-cert-mode': 're-sign',
+ 'ssl-anomalies-log': 'disable',
+ 'ssl-exemptions-log': 'disable',
+ 'untrusted-caname': 'test_value_12',
+ 'use-ssl-server': 'disable',
+ 'whitelist': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_ssl_ssh_profile_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ssl_ssh_profile': {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi-over-https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc-over-https': 'enable',
+ 'server-cert': 'test_value_8',
+ 'server-cert-mode': 're-sign',
+ 'ssl-anomalies-log': 'disable',
+ 'ssl-exemptions-log': 'disable',
+ 'untrusted-caname': 'test_value_12',
+ 'use-ssl-server': 'disable',
+ 'whitelist': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_ssl_ssh_profile_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_ssl_ssh_profile': {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_ssl_ssh_profile_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_ssl_ssh_profile': {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_ssl_ssh_profile_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ssl_ssh_profile': {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi-over-https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc-over-https': 'enable',
+ 'server-cert': 'test_value_8',
+ 'server-cert-mode': 're-sign',
+ 'ssl-anomalies-log': 'disable',
+ 'ssl-exemptions-log': 'disable',
+ 'untrusted-caname': 'test_value_12',
+ 'use-ssl-server': 'disable',
+ 'whitelist': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_ssl_ssh_profile_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ssl_ssh_profile': {
+ 'random_attribute_not_valid': 'tag',
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi_over_https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc_over_https': 'enable',
+ 'server_cert': 'test_value_8',
+ 'server_cert_mode': 're-sign',
+ 'ssl_anomalies_log': 'disable',
+ 'ssl_exemptions_log': 'disable',
+ 'untrusted_caname': 'test_value_12',
+ 'use_ssl_server': 'disable',
+ 'whitelist': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ssl_ssh_profile.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'caname': 'test_value_3',
+ 'comment': 'Optional comments.',
+ 'mapi-over-https': 'enable',
+ 'name': 'default_name_6',
+ 'rpc-over-https': 'enable',
+ 'server-cert': 'test_value_8',
+ 'server-cert-mode': 're-sign',
+ 'ssl-anomalies-log': 'disable',
+ 'ssl-exemptions-log': 'disable',
+ 'untrusted-caname': 'test_value_12',
+ 'use-ssl-server': 'disable',
+ 'whitelist': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ssl-ssh-profile', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_ttl_policy.py b/test/units/modules/network/fortios/test_fortios_firewall_ttl_policy.py
new file mode 100644
index 00000000000..792fb758770
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_ttl_policy.py
@@ -0,0 +1,249 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_ttl_policy
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_ttl_policy.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_ttl_policy_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ttl_policy': {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ttl-policy', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_ttl_policy_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ttl_policy': {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ttl-policy', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_ttl_policy_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_ttl_policy': {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'ttl-policy', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_ttl_policy_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_ttl_policy': {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'ttl-policy', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_ttl_policy_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ttl_policy': {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ttl-policy', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_ttl_policy_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_ttl_policy': {
+ 'random_attribute_not_valid': 'tag',
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_ttl_policy.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'accept',
+ 'id': '4',
+ 'schedule': 'test_value_5',
+ 'srcintf': 'test_value_6',
+ 'status': 'enable',
+ 'ttl': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'ttl-policy', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vip.py b/test/units/modules/network/fortios/test_fortios_firewall_vip.py
new file mode 100644
index 00000000000..a24bdd6b8f3
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vip.py
@@ -0,0 +1,839 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vip
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vip.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vip_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns-mapping-ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous-arp-interval': '10',
+ 'http-cookie-age': '11',
+ 'http-cookie-domain': 'test_value_12',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '14',
+ 'http-cookie-path': 'test_value_15',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_18',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '21',
+ 'ldb-method': 'static',
+ 'mapped-addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max-embryonic-connections': '25',
+ 'name': 'default_name_26',
+ 'nat-source-vip': 'disable',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping-type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_35',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '38',
+ 'ssl-client-session-state-timeout': '39',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '43',
+ 'ssl-hpkp-backup': 'test_value_44',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_46',
+ 'ssl-hpkp-report-uri': 'test_value_47',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '49',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '61',
+ 'ssl-server-session-state-timeout': '62',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns-mapping-ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous-arp-interval': '10',
+ 'http-cookie-age': '11',
+ 'http-cookie-domain': 'test_value_12',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '14',
+ 'http-cookie-path': 'test_value_15',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_18',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '21',
+ 'ldb-method': 'static',
+ 'mapped-addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max-embryonic-connections': '25',
+ 'name': 'default_name_26',
+ 'nat-source-vip': 'disable',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping-type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_35',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '38',
+ 'ssl-client-session-state-timeout': '39',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '43',
+ 'ssl-hpkp-backup': 'test_value_44',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_46',
+ 'ssl-hpkp-report-uri': 'test_value_47',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '49',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '61',
+ 'ssl-server-session-state-timeout': '62',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns-mapping-ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous-arp-interval': '10',
+ 'http-cookie-age': '11',
+ 'http-cookie-domain': 'test_value_12',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '14',
+ 'http-cookie-path': 'test_value_15',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_18',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '21',
+ 'ldb-method': 'static',
+ 'mapped-addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max-embryonic-connections': '25',
+ 'name': 'default_name_26',
+ 'nat-source-vip': 'disable',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping-type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_35',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '38',
+ 'ssl-client-session-state-timeout': '39',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '43',
+ 'ssl-hpkp-backup': 'test_value_44',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_46',
+ 'ssl-hpkp-report-uri': 'test_value_47',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '49',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '61',
+ 'ssl-server-session-state-timeout': '62',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vip_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip': {
+ 'random_attribute_not_valid': 'tag',
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns_mapping_ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous_arp_interval': '10',
+ 'http_cookie_age': '11',
+ 'http_cookie_domain': 'test_value_12',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '14',
+ 'http_cookie_path': 'test_value_15',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_18',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '21',
+ 'ldb_method': 'static',
+ 'mapped_addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max_embryonic_connections': '25',
+ 'name': 'default_name_26',
+ 'nat_source_vip': 'disable',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping_type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_35',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '38',
+ 'ssl_client_session_state_timeout': '39',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '43',
+ 'ssl_hpkp_backup': 'test_value_44',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_46',
+ 'ssl_hpkp_report_uri': 'test_value_47',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '49',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '61',
+ 'ssl_server_session_state_timeout': '62',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'dns-mapping-ttl': '6',
+ 'extintf': 'test_value_7',
+ 'extip': 'test_value_8',
+ 'extport': 'test_value_9',
+ 'gratuitous-arp-interval': '10',
+ 'http-cookie-age': '11',
+ 'http-cookie-domain': 'test_value_12',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '14',
+ 'http-cookie-path': 'test_value_15',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_18',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '21',
+ 'ldb-method': 'static',
+ 'mapped-addr': 'test_value_23',
+ 'mappedport': 'test_value_24',
+ 'max-embryonic-connections': '25',
+ 'name': 'default_name_26',
+ 'nat-source-vip': 'disable',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'portmapping-type': '1-to-1',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_35',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '38',
+ 'ssl-client-session-state-timeout': '39',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '43',
+ 'ssl-hpkp-backup': 'test_value_44',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_46',
+ 'ssl-hpkp-report-uri': 'test_value_47',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '49',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '61',
+ 'ssl-server-session-state-timeout': '62',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_65',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vip46.py b/test/units/modules/network/fortios/test_fortios_firewall_vip46.py
new file mode 100644
index 00000000000..dd8cacb67da
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vip46.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_firewall_vip46
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vip46.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vip46_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip46': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip46_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip46': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip46_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip46': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip46', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip46_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip46': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip46', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip46_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip46': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vip46_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip46': {
+ 'random_attribute_not_valid': 'tag',
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vip6.py b/test/units/modules/network/fortios/test_fortios_firewall_vip6.py
new file mode 100644
index 00000000000..2d6aaf036c1
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vip6.py
@@ -0,0 +1,789 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vip6
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vip6.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vip6_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip6': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http-cookie-age': '8',
+ 'http-cookie-domain': 'test_value_9',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '11',
+ 'http-cookie-path': 'test_value_12',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_15',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '18',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max-embryonic-connections': '22',
+ 'name': 'default_name_23',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_30',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '33',
+ 'ssl-client-session-state-timeout': '34',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '38',
+ 'ssl-hpkp-backup': 'test_value_39',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_41',
+ 'ssl-hpkp-report-uri': 'test_value_42',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '44',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '56',
+ 'ssl-server-session-state-timeout': '57',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip6_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip6': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http-cookie-age': '8',
+ 'http-cookie-domain': 'test_value_9',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '11',
+ 'http-cookie-path': 'test_value_12',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_15',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '18',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max-embryonic-connections': '22',
+ 'name': 'default_name_23',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_30',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '33',
+ 'ssl-client-session-state-timeout': '34',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '38',
+ 'ssl-hpkp-backup': 'test_value_39',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_41',
+ 'ssl-hpkp-report-uri': 'test_value_42',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '44',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '56',
+ 'ssl-server-session-state-timeout': '57',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip6_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip6': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip6', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip6_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip6': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip6', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip6_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip6': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http-cookie-age': '8',
+ 'http-cookie-domain': 'test_value_9',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '11',
+ 'http-cookie-path': 'test_value_12',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_15',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '18',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max-embryonic-connections': '22',
+ 'name': 'default_name_23',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_30',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '33',
+ 'ssl-client-session-state-timeout': '34',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '38',
+ 'ssl-hpkp-backup': 'test_value_39',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_41',
+ 'ssl-hpkp-report-uri': 'test_value_42',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '44',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '56',
+ 'ssl-server-session-state-timeout': '57',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vip6_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip6': {
+ 'random_attribute_not_valid': 'tag',
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http_cookie_age': '8',
+ 'http_cookie_domain': 'test_value_9',
+ 'http_cookie_domain_from_host': 'disable',
+ 'http_cookie_generation': '11',
+ 'http_cookie_path': 'test_value_12',
+ 'http_cookie_share': 'disable',
+ 'http_ip_header': 'enable',
+ 'http_ip_header_name': 'test_value_15',
+ 'http_multiplex': 'enable',
+ 'https_cookie_secure': 'disable',
+ 'id': '18',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max_embryonic_connections': '22',
+ 'name': 'default_name_23',
+ 'outlook_web_access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'ssl_algorithm': 'high',
+ 'ssl_certificate': 'test_value_30',
+ 'ssl_client_fallback': 'disable',
+ 'ssl_client_renegotiation': 'allow',
+ 'ssl_client_session_state_max': '33',
+ 'ssl_client_session_state_timeout': '34',
+ 'ssl_client_session_state_type': 'disable',
+ 'ssl_dh_bits': '768',
+ 'ssl_hpkp': 'disable',
+ 'ssl_hpkp_age': '38',
+ 'ssl_hpkp_backup': 'test_value_39',
+ 'ssl_hpkp_include_subdomains': 'disable',
+ 'ssl_hpkp_primary': 'test_value_41',
+ 'ssl_hpkp_report_uri': 'test_value_42',
+ 'ssl_hsts': 'disable',
+ 'ssl_hsts_age': '44',
+ 'ssl_hsts_include_subdomains': 'disable',
+ 'ssl_http_location_conversion': 'enable',
+ 'ssl_http_match_host': 'enable',
+ 'ssl_max_version': 'ssl-3.0',
+ 'ssl_min_version': 'ssl-3.0',
+ 'ssl_mode': 'half',
+ 'ssl_pfs': 'require',
+ 'ssl_send_empty_frags': 'enable',
+ 'ssl_server_algorithm': 'high',
+ 'ssl_server_max_version': 'ssl-3.0',
+ 'ssl_server_min_version': 'ssl-3.0',
+ 'ssl_server_session_state_max': '56',
+ 'ssl_server_session_state_timeout': '57',
+ 'ssl_server_session_state_type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic_server': 'disable',
+ 'websphere_server': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'http-cookie-age': '8',
+ 'http-cookie-domain': 'test_value_9',
+ 'http-cookie-domain-from-host': 'disable',
+ 'http-cookie-generation': '11',
+ 'http-cookie-path': 'test_value_12',
+ 'http-cookie-share': 'disable',
+ 'http-ip-header': 'enable',
+ 'http-ip-header-name': 'test_value_15',
+ 'http-multiplex': 'enable',
+ 'https-cookie-secure': 'disable',
+ 'id': '18',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_20',
+ 'mappedport': 'test_value_21',
+ 'max-embryonic-connections': '22',
+ 'name': 'default_name_23',
+ 'outlook-web-access': 'disable',
+ 'persistence': 'none',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'ssl-algorithm': 'high',
+ 'ssl-certificate': 'test_value_30',
+ 'ssl-client-fallback': 'disable',
+ 'ssl-client-renegotiation': 'allow',
+ 'ssl-client-session-state-max': '33',
+ 'ssl-client-session-state-timeout': '34',
+ 'ssl-client-session-state-type': 'disable',
+ 'ssl-dh-bits': '768',
+ 'ssl-hpkp': 'disable',
+ 'ssl-hpkp-age': '38',
+ 'ssl-hpkp-backup': 'test_value_39',
+ 'ssl-hpkp-include-subdomains': 'disable',
+ 'ssl-hpkp-primary': 'test_value_41',
+ 'ssl-hpkp-report-uri': 'test_value_42',
+ 'ssl-hsts': 'disable',
+ 'ssl-hsts-age': '44',
+ 'ssl-hsts-include-subdomains': 'disable',
+ 'ssl-http-location-conversion': 'enable',
+ 'ssl-http-match-host': 'enable',
+ 'ssl-max-version': 'ssl-3.0',
+ 'ssl-min-version': 'ssl-3.0',
+ 'ssl-mode': 'half',
+ 'ssl-pfs': 'require',
+ 'ssl-send-empty-frags': 'enable',
+ 'ssl-server-algorithm': 'high',
+ 'ssl-server-max-version': 'ssl-3.0',
+ 'ssl-server-min-version': 'ssl-3.0',
+ 'ssl-server-session-state-max': '56',
+ 'ssl-server-session-state-timeout': '57',
+ 'ssl-server-session-state-type': 'disable',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_60',
+ 'weblogic-server': 'disable',
+ 'websphere-server': 'disable'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vip64.py b/test/units/modules/network/fortios/test_fortios_firewall_vip64.py
new file mode 100644
index 00000000000..b496be600b3
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vip64.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_firewall_vip64
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vip64.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vip64_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip64': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip64_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip64': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip64_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip64': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip64', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vip64_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vip64': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vip64', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vip64_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip64': {
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vip64_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vip64': {
+ 'random_attribute_not_valid': 'tag',
+ 'arp_reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb_method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server_type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vip64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'arp-reply': 'disable',
+ 'color': '4',
+ 'comment': 'Comment.',
+ 'extip': 'test_value_6',
+ 'extport': 'test_value_7',
+ 'id': '8',
+ 'ldb-method': 'static',
+ 'mappedip': 'test_value_10',
+ 'mappedport': 'test_value_11',
+ 'name': 'default_name_12',
+ 'portforward': 'disable',
+ 'protocol': 'tcp',
+ 'server-type': 'http',
+ 'type': 'static-nat',
+ 'uuid': 'test_value_17'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vip64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vipgrp.py b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp.py
new file mode 100644
index 00000000000..b4b94325698
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp.py
@@ -0,0 +1,239 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vipgrp
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vipgrp.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vipgrp_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vipgrp_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'interface': 'test_value_5',
+ 'name': 'default_name_6',
+ 'uuid': 'test_value_7'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vipgrp46.py b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp46.py
new file mode 100644
index 00000000000..9ab148df7d8
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp46.py
@@ -0,0 +1,229 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vipgrp46
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vipgrp46.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vipgrp46_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp46': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp46_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp46': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp46_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp46': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp46', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp46_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp46': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp46', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp46_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp46': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vipgrp46_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp46': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp46.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp46', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vipgrp6.py b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp6.py
new file mode 100644
index 00000000000..808a9c26a38
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp6.py
@@ -0,0 +1,229 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vipgrp6
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vipgrp6.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vipgrp6_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp6': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp6_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp6': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp6_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp6': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp6', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp6_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp6': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp6', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp6_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp6': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vipgrp6_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp6': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp6.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp6', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_vipgrp64.py b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp64.py
new file mode 100644
index 00000000000..41a48c9fa15
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_vipgrp64.py
@@ -0,0 +1,229 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_vipgrp64
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_vipgrp64.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_vipgrp64_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp64': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp64_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp64': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp64_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp64': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp64', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_vipgrp64_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_vipgrp64': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall', 'vipgrp64', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_vipgrp64_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp64': {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_vipgrp64_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_vipgrp64': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_vipgrp64.fortios_firewall(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comments': 'test_value_4',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6'
+ }
+
+ set_method_mock.assert_called_with('firewall', 'vipgrp64', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_custom.py b/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_custom.py
new file mode 100644
index 00000000000..55a91a37470
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_custom.py
@@ -0,0 +1,249 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_wildcard_fqdn_custom
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_wildcard_fqdn_custom.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_wildcard_fqdn_custom_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_custom': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard-fqdn': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_wildcard_fqdn_custom_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_custom': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard-fqdn': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_wildcard_fqdn_custom_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_wildcard_fqdn_custom': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_wildcard_fqdn_custom_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_wildcard_fqdn_custom': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_wildcard_fqdn_custom_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_custom': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard-fqdn': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_wildcard_fqdn_custom_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_custom': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard_fqdn': 'test_value_8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_custom.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable',
+ 'wildcard-fqdn': 'test_value_8'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_group.py b/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_group.py
new file mode 100644
index 00000000000..59e86978b71
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_firewall_wildcard_fqdn_group.py
@@ -0,0 +1,239 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_firewall_wildcard_fqdn_group
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_firewall_wildcard_fqdn_group.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_firewall_wildcard_fqdn_group_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_group': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_wildcard_fqdn_group_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_group': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_wildcard_fqdn_group_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_wildcard_fqdn_group': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_firewall_wildcard_fqdn_group_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'firewall_wildcard_fqdn_group': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_firewall_wildcard_fqdn_group_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_group': {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_firewall_wildcard_fqdn_group_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'firewall_wildcard_fqdn_group': {
+ 'random_attribute_not_valid': 'tag',
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_firewall_wildcard_fqdn_group.fortios_firewall_wildcard_fqdn(input_data, fos_instance)
+
+ expected_data = {
+ 'color': '3',
+ 'comment': 'Comment.',
+ 'name': 'default_name_5',
+ 'uuid': 'test_value_6',
+ 'visibility': 'enable'
+ }
+
+ set_method_mock.assert_called_with('firewall.wildcard-fqdn', 'group', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_ftp_proxy_explicit.py b/test/units/modules/network/fortios/test_fortios_ftp_proxy_explicit.py
new file mode 100644
index 00000000000..3773eda0e85
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ftp_proxy_explicit.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_ftp_proxy_explicit
+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_ftp_proxy_explicit.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ftp_proxy_explicit_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',
+ 'ftp_proxy_explicit': {
+ 'incoming_ip': 'test_value_3',
+ 'incoming_port': 'test_value_4',
+ 'outgoing_ip': 'test_value_5',
+ 'sec_default_action': 'accept',
+ 'status': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ftp_proxy_explicit.fortios_ftp_proxy(input_data, fos_instance)
+
+ expected_data = {
+ 'incoming-ip': 'test_value_3',
+ 'incoming-port': 'test_value_4',
+ 'outgoing-ip': 'test_value_5',
+ 'sec-default-action': 'accept',
+ 'status': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ftp-proxy', 'explicit', 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_ftp_proxy_explicit_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',
+ 'ftp_proxy_explicit': {
+ 'incoming_ip': 'test_value_3',
+ 'incoming_port': 'test_value_4',
+ 'outgoing_ip': 'test_value_5',
+ 'sec_default_action': 'accept',
+ 'status': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ftp_proxy_explicit.fortios_ftp_proxy(input_data, fos_instance)
+
+ expected_data = {
+ 'incoming-ip': 'test_value_3',
+ 'incoming-port': 'test_value_4',
+ 'outgoing-ip': 'test_value_5',
+ 'sec-default-action': 'accept',
+ 'status': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ftp-proxy', 'explicit', 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_ftp_proxy_explicit_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',
+ 'ftp_proxy_explicit': {
+ 'incoming_ip': 'test_value_3',
+ 'incoming_port': 'test_value_4',
+ 'outgoing_ip': 'test_value_5',
+ 'sec_default_action': 'accept',
+ 'status': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ftp_proxy_explicit.fortios_ftp_proxy(input_data, fos_instance)
+
+ expected_data = {
+ 'incoming-ip': 'test_value_3',
+ 'incoming-port': 'test_value_4',
+ 'outgoing-ip': 'test_value_5',
+ 'sec-default-action': 'accept',
+ 'status': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ftp-proxy', 'explicit', 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_ftp_proxy_explicit_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',
+ 'ftp_proxy_explicit': {
+ 'random_attribute_not_valid': 'tag',
+ 'incoming_ip': 'test_value_3',
+ 'incoming_port': 'test_value_4',
+ 'outgoing_ip': 'test_value_5',
+ 'sec_default_action': 'accept',
+ 'status': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ftp_proxy_explicit.fortios_ftp_proxy(input_data, fos_instance)
+
+ expected_data = {
+ 'incoming-ip': 'test_value_3',
+ 'incoming-port': 'test_value_4',
+ 'outgoing-ip': 'test_value_5',
+ 'sec-default-action': 'accept',
+ 'status': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ftp-proxy', 'explicit', 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_icap_profile.py b/test/units/modules/network/fortios/test_fortios_icap_profile.py
new file mode 100644
index 00000000000..1e2640bcf1a
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_icap_profile.py
@@ -0,0 +1,309 @@
+# 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_icap_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_icap_profile.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_icap_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',
+ 'icap_profile': {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg-group': 'test_value_5',
+ 'request': 'disable',
+ 'request-failure': 'error',
+ 'request-path': 'test_value_8',
+ 'request-server': 'test_value_9',
+ 'response': 'disable',
+ 'response-failure': 'error',
+ 'response-path': 'test_value_12',
+ 'response-server': 'test_value_13',
+ 'streaming-content-bypass': 'disable'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_profile': {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg-group': 'test_value_5',
+ 'request': 'disable',
+ 'request-failure': 'error',
+ 'request-path': 'test_value_8',
+ 'request-server': 'test_value_9',
+ 'response': 'disable',
+ 'response-failure': 'error',
+ 'response-path': 'test_value_12',
+ 'response-server': 'test_value_13',
+ 'streaming-content-bypass': 'disable'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_profile': {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_profile': {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_profile': {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg-group': 'test_value_5',
+ 'request': 'disable',
+ 'request-failure': 'error',
+ 'request-path': 'test_value_8',
+ 'request-server': 'test_value_9',
+ 'response': 'disable',
+ 'response-failure': 'error',
+ 'response-path': 'test_value_12',
+ 'response-server': 'test_value_13',
+ 'streaming-content-bypass': 'disable'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_profile': {
+ 'random_attribute_not_valid': 'tag',
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg_group': 'test_value_5',
+ 'request': 'disable',
+ 'request_failure': 'error',
+ 'request_path': 'test_value_8',
+ 'request_server': 'test_value_9',
+ 'response': 'disable',
+ 'response_failure': 'error',
+ 'response_path': 'test_value_12',
+ 'response_server': 'test_value_13',
+ 'streaming_content_bypass': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_profile.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'methods': 'delete',
+ 'name': 'default_name_4',
+ 'replacemsg-group': 'test_value_5',
+ 'request': 'disable',
+ 'request-failure': 'error',
+ 'request-path': 'test_value_8',
+ 'request-server': 'test_value_9',
+ 'response': 'disable',
+ 'response-failure': 'error',
+ 'response-path': 'test_value_12',
+ 'response-server': 'test_value_13',
+ 'streaming-content-bypass': 'disable'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_server.py b/test/units/modules/network/fortios/test_fortios_icap_server.py
new file mode 100644
index 00000000000..f430c3a219e
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_icap_server.py
@@ -0,0 +1,249 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_icap_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_icap_server.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_icap_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',
+ 'icap_server': {
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'ip-address': 'test_value_3',
+ 'ip-version': '4',
+ 'ip6-address': 'test_value_5',
+ 'max-connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_server': {
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'ip-address': 'test_value_3',
+ 'ip-version': '4',
+ 'ip6-address': 'test_value_5',
+ 'max-connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_server': {
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_server': {
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_server': {
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'ip-address': 'test_value_3',
+ 'ip-version': '4',
+ 'ip6-address': 'test_value_5',
+ 'max-connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_icap_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',
+ 'icap_server': {
+ 'random_attribute_not_valid': 'tag',
+ 'ip_address': 'test_value_3',
+ 'ip_version': '4',
+ 'ip6_address': 'test_value_5',
+ 'max_connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_icap_server.fortios_icap(input_data, fos_instance)
+
+ expected_data = {
+ 'ip-address': 'test_value_3',
+ 'ip-version': '4',
+ 'ip6-address': 'test_value_5',
+ 'max-connections': '6',
+ 'name': 'default_name_7',
+ 'port': '8'
+ }
+
+ set_method_mock.assert_called_with('icap', '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_ips_custom.py b/test/units/modules/network/fortios/test_fortios_ips_custom.py
new file mode 100644
index 00000000000..17b0599ec18
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ips_custom.py
@@ -0,0 +1,329 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_ips_custom
+except ImportError:
+ pytest.skip("Could not load required modules for testing", allow_module_level=True)
+
+
+@pytest.fixture(autouse=True)
+def connection_mock(mocker):
+ connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_ips_custom.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ips_custom_creation(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'ips_custom': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule-id': '11',
+ 'severity': 'test_value_12',
+ 'sig-name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ }
+
+ set_method_mock.assert_called_with('ips', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_ips_custom_creation_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'ips_custom': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule-id': '11',
+ 'severity': 'test_value_12',
+ 'sig-name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ }
+
+ set_method_mock.assert_called_with('ips', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_ips_custom_removal(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'ips_custom': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'custom', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
+
+
+def test_ips_custom_deletion_fails(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
+ delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'absent',
+ 'ips_custom': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'custom', mkey=ANY, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 500
+
+
+def test_ips_custom_idempotent(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'ips_custom': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule-id': '11',
+ 'severity': 'test_value_12',
+ 'sig-name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ }
+
+ set_method_mock.assert_called_with('ips', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert not changed
+ assert response['status'] == 'error'
+ assert response['http_status'] == 404
+
+
+def test_ips_custom_filter_foreign_attributes(mocker):
+ schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
+
+ set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
+ set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
+
+ input_data = {
+ 'username': 'admin',
+ 'state': 'present',
+ 'ips_custom': {
+ 'random_attribute_not_valid': 'tag',
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule_id': '11',
+ 'severity': 'test_value_12',
+ 'sig_name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_custom.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'comment': 'Comment.',
+ 'location': 'test_value_6',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'os': 'test_value_9',
+ 'protocol': 'test_value_10',
+ 'rule-id': '11',
+ 'severity': 'test_value_12',
+ 'sig-name': 'test_value_13',
+ 'signature': 'test_value_14',
+ 'status': 'disable',
+ 'tag': 'test_value_16'
+ }
+
+ set_method_mock.assert_called_with('ips', 'custom', data=expected_data, vdom='root')
+ schema_method_mock.assert_not_called()
+ assert not is_error
+ assert changed
+ assert response['status'] == 'success'
+ assert response['http_status'] == 200
diff --git a/test/units/modules/network/fortios/test_fortios_ips_decoder.py b/test/units/modules/network/fortios/test_fortios_ips_decoder.py
new file mode 100644
index 00000000000..4b1ed124166
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ips_decoder.py
@@ -0,0 +1,209 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_ips_decoder
+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_ips_decoder.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ips_decoder_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',
+ 'ips_decoder': {
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'name': 'default_name_3',
+
+ }
+
+ set_method_mock.assert_called_with('ips', 'decoder', 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_ips_decoder_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',
+ 'ips_decoder': {
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'name': 'default_name_3',
+
+ }
+
+ set_method_mock.assert_called_with('ips', 'decoder', 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_ips_decoder_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',
+ 'ips_decoder': {
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'decoder', 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_ips_decoder_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',
+ 'ips_decoder': {
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'decoder', 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_ips_decoder_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',
+ 'ips_decoder': {
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'name': 'default_name_3',
+
+ }
+
+ set_method_mock.assert_called_with('ips', 'decoder', 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_ips_decoder_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',
+ 'ips_decoder': {
+ 'random_attribute_not_valid': 'tag',
+ 'name': 'default_name_3',
+
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_decoder.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'name': 'default_name_3',
+
+ }
+
+ set_method_mock.assert_called_with('ips', 'decoder', 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_ips_global.py b/test/units/modules/network/fortios/test_fortios_ips_global.py
new file mode 100644
index 00000000000..a0772ab7ecd
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ips_global.py
@@ -0,0 +1,247 @@
+# 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_ips_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_ips_global.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ips_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',
+ 'ips_global': {
+ 'anomaly_mode': 'periodical',
+ 'database': 'regular',
+ 'deep_app_insp_db_limit': '5',
+ 'deep_app_insp_timeout': '6',
+ 'engine_count': '7',
+ 'exclude_signatures': 'none',
+ 'fail_open': 'enable',
+ 'intelligent_mode': 'enable',
+ 'session_limit_mode': 'accurate',
+ 'skype_client_public_ipaddr': 'test_value_12',
+ 'socket_size': '13',
+ 'sync_session_ttl': 'enable',
+ 'traffic_submit': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_global.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'anomaly-mode': 'periodical',
+ 'database': 'regular',
+ 'deep-app-insp-db-limit': '5',
+ 'deep-app-insp-timeout': '6',
+ 'engine-count': '7',
+ 'exclude-signatures': 'none',
+ 'fail-open': 'enable',
+ 'intelligent-mode': 'enable',
+ 'session-limit-mode': 'accurate',
+ 'skype-client-public-ipaddr': 'test_value_12',
+ 'socket-size': '13',
+ 'sync-session-ttl': 'enable',
+ 'traffic-submit': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ips', '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_ips_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',
+ 'ips_global': {
+ 'anomaly_mode': 'periodical',
+ 'database': 'regular',
+ 'deep_app_insp_db_limit': '5',
+ 'deep_app_insp_timeout': '6',
+ 'engine_count': '7',
+ 'exclude_signatures': 'none',
+ 'fail_open': 'enable',
+ 'intelligent_mode': 'enable',
+ 'session_limit_mode': 'accurate',
+ 'skype_client_public_ipaddr': 'test_value_12',
+ 'socket_size': '13',
+ 'sync_session_ttl': 'enable',
+ 'traffic_submit': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_global.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'anomaly-mode': 'periodical',
+ 'database': 'regular',
+ 'deep-app-insp-db-limit': '5',
+ 'deep-app-insp-timeout': '6',
+ 'engine-count': '7',
+ 'exclude-signatures': 'none',
+ 'fail-open': 'enable',
+ 'intelligent-mode': 'enable',
+ 'session-limit-mode': 'accurate',
+ 'skype-client-public-ipaddr': 'test_value_12',
+ 'socket-size': '13',
+ 'sync-session-ttl': 'enable',
+ 'traffic-submit': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ips', '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_ips_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',
+ 'ips_global': {
+ 'anomaly_mode': 'periodical',
+ 'database': 'regular',
+ 'deep_app_insp_db_limit': '5',
+ 'deep_app_insp_timeout': '6',
+ 'engine_count': '7',
+ 'exclude_signatures': 'none',
+ 'fail_open': 'enable',
+ 'intelligent_mode': 'enable',
+ 'session_limit_mode': 'accurate',
+ 'skype_client_public_ipaddr': 'test_value_12',
+ 'socket_size': '13',
+ 'sync_session_ttl': 'enable',
+ 'traffic_submit': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_global.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'anomaly-mode': 'periodical',
+ 'database': 'regular',
+ 'deep-app-insp-db-limit': '5',
+ 'deep-app-insp-timeout': '6',
+ 'engine-count': '7',
+ 'exclude-signatures': 'none',
+ 'fail-open': 'enable',
+ 'intelligent-mode': 'enable',
+ 'session-limit-mode': 'accurate',
+ 'skype-client-public-ipaddr': 'test_value_12',
+ 'socket-size': '13',
+ 'sync-session-ttl': 'enable',
+ 'traffic-submit': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ips', '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_ips_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',
+ 'ips_global': {
+ 'random_attribute_not_valid': 'tag',
+ 'anomaly_mode': 'periodical',
+ 'database': 'regular',
+ 'deep_app_insp_db_limit': '5',
+ 'deep_app_insp_timeout': '6',
+ 'engine_count': '7',
+ 'exclude_signatures': 'none',
+ 'fail_open': 'enable',
+ 'intelligent_mode': 'enable',
+ 'session_limit_mode': 'accurate',
+ 'skype_client_public_ipaddr': 'test_value_12',
+ 'socket_size': '13',
+ 'sync_session_ttl': 'enable',
+ 'traffic_submit': 'enable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_global.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'anomaly-mode': 'periodical',
+ 'database': 'regular',
+ 'deep-app-insp-db-limit': '5',
+ 'deep-app-insp-timeout': '6',
+ 'engine-count': '7',
+ 'exclude-signatures': 'none',
+ 'fail-open': 'enable',
+ 'intelligent-mode': 'enable',
+ 'session-limit-mode': 'accurate',
+ 'skype-client-public-ipaddr': 'test_value_12',
+ 'socket-size': '13',
+ 'sync-session-ttl': 'enable',
+ 'traffic-submit': 'enable'
+ }
+
+ set_method_mock.assert_called_with('ips', '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_ips_rule.py b/test/units/modules/network/fortios/test_fortios_ips_rule.py
new file mode 100644
index 00000000000..5ca2e06e26a
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ips_rule.py
@@ -0,0 +1,329 @@
+# Copyright 2019 Fortinet, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import json
+import pytest
+from mock import ANY
+from ansible.module_utils.network.fortios.fortios import FortiOSHandler
+
+try:
+ from ansible.modules.network.fortios import fortios_ips_rule
+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_ips_rule.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ips_rule_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',
+ 'ips_rule': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule-id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_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',
+ 'ips_rule': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule-id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_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',
+ 'ips_rule': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_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',
+ 'ips_rule': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_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',
+ 'ips_rule': {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule-id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_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',
+ 'ips_rule': {
+ 'random_attribute_not_valid': 'tag',
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log_packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule_id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'action': 'pass',
+ 'application': 'test_value_4',
+ 'date': '5',
+ 'group': 'test_value_6',
+ 'location': 'test_value_7,',
+ 'log': 'disable',
+ 'log-packet': 'disable',
+ 'name': 'default_name_10',
+ 'os': 'test_value_11',
+ 'rev': '12',
+ 'rule-id': '13',
+ 'service': 'test_value_14',
+ 'severity': 'test_value_15,',
+ 'status': 'disable'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule', 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_ips_rule_settings.py b/test/units/modules/network/fortios/test_fortios_ips_rule_settings.py
new file mode 100644
index 00000000000..73dc9015fb8
--- /dev/null
+++ b/test/units/modules/network/fortios/test_fortios_ips_rule_settings.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_ips_rule_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_ips_rule_settings.Connection')
+ return connection_class_mock
+
+
+fos_instance = FortiOSHandler(connection_mock)
+
+
+def test_ips_rule_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',
+ 'ips_rule_settings': {
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'id': '3'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule-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_ips_rule_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',
+ 'ips_rule_settings': {
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'id': '3'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule-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_ips_rule_settings_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',
+ 'ips_rule_settings': {
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'rule-settings', 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_ips_rule_settings_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',
+ 'ips_rule_settings': {
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ delete_method_mock.assert_called_with('ips', 'rule-settings', 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_ips_rule_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',
+ 'ips_rule_settings': {
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'id': '3'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule-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_ips_rule_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',
+ 'ips_rule_settings': {
+ 'random_attribute_not_valid': 'tag',
+ 'id': '3'
+ },
+ 'vdom': 'root'}
+
+ is_error, changed, response = fortios_ips_rule_settings.fortios_ips(input_data, fos_instance)
+
+ expected_data = {
+ 'id': '3'
+ }
+
+ set_method_mock.assert_called_with('ips', 'rule-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