FortiOS modules for 2.9 - 1 (#60469)

* FortiOS modules for 2.9 - 1

* Fix empty choices and avoid E337,E338 warnings

* Ansible comments on version_added and ignore.txt only on this PR files

* Add version_added also for state attribute

* Avoid null choices on dlp_sensor

* Change required flag according to argspec
pull/60490/head
Miguel Angel Muñoz González 5 years ago committed by Nilashish Chakraborty
parent 5923a64b20
commit 4cae96109b

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_antivirus_heuristic module: fortios_antivirus_heuristic
short_description: Configure global heuristic options in Fortinet's FortiOS and FortiGate. short_description: Configure global heuristic options in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure antivirus feature and heuristic category. user to set and modify antivirus feature and heuristic category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,37 +41,48 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: false default: true
version_added: 2.9
antivirus_heuristic: antivirus_heuristic:
description: description:
- Configure global heuristic options. - Configure global heuristic options.
default: null default: null
type: dict
suboptions: suboptions:
mode: mode:
description: description:
- Enable/disable heuristics and determine how the system behaves if heuristics detects a problem. - Enable/disable heuristics and determine how the system behaves if heuristics detects a problem.
type: str
choices: choices:
- pass - pass
- block - block
@ -88,6 +96,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure global heuristic options. - name: Configure global heuristic options.
fortios_antivirus_heuristic: fortios_antivirus_heuristic:
@ -95,6 +104,7 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
antivirus_heuristic: antivirus_heuristic:
mode: "pass" mode: "pass"
''' '''
@ -159,14 +169,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -174,7 +186,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_antivirus_heuristic_data(json): def filter_antivirus_heuristic_data(json):
@ -188,38 +200,55 @@ def filter_antivirus_heuristic_data(json):
return dictionary 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 antivirus_heuristic(data, fos): def antivirus_heuristic(data, fos):
vdom = data['vdom'] vdom = data['vdom']
antivirus_heuristic_data = data['antivirus_heuristic'] antivirus_heuristic_data = data['antivirus_heuristic']
filtered_data = filter_antivirus_heuristic_data(antivirus_heuristic_data) filtered_data = underscore_to_hyphen(filter_antivirus_heuristic_data(antivirus_heuristic_data))
return fos.set('antivirus', return fos.set('antivirus',
'heuristic', 'heuristic',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_antivirus(data, fos): def fortios_antivirus(data, fos):
login(data)
methodlist = ['antivirus_heuristic'] if data['antivirus_heuristic']:
for method in methodlist: resp = antivirus_heuristic(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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},
"antivirus_heuristic": { "antivirus_heuristic": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"mode": {"required": False, "type": "str", "mode": {"required": False, "type": "str",
"choices": ["pass", "block", "disable"]} "choices": ["pass", "block", "disable"]}
@ -230,15 +259,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_antivirus(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_antivirus(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_antivirus(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_antivirus_quarantine module: fortios_antivirus_quarantine
short_description: Configure quarantine options in Fortinet's FortiOS and FortiGate. short_description: Configure quarantine options in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure antivirus feature and quarantine category. user to set and modify antivirus feature and quarantine category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,47 +41,60 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: false default: true
version_added: 2.9
antivirus_quarantine: antivirus_quarantine:
description: description:
- Configure quarantine options. - Configure quarantine options.
default: null default: null
type: dict
suboptions: suboptions:
agelimit: agelimit:
description: description:
- Age limit for quarantined files (0 - 479 hours, 0 means forever). - Age limit for quarantined files (0 - 479 hours, 0 means forever).
type: int
destination: destination:
description: description:
- Choose whether to quarantine files to the FortiGate disk or to FortiAnalyzer or to delete them instead of quarantining them. - Choose whether to quarantine files to the FortiGate disk or to FortiAnalyzer or to delete them instead of quarantining them.
type: str
choices: choices:
- NULL - NULL
- disk - disk
- FortiAnalyzer - FortiAnalyzer
drop-blocked: drop_blocked:
description: description:
- Do not quarantine dropped files found in sessions using the selected protocols. Dropped files are deleted instead of being quarantined. - Do not quarantine dropped files found in sessions using the selected protocols. Dropped files are deleted instead of being quarantined.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -102,10 +112,11 @@ options:
- mm3 - mm3
- mm4 - mm4
- mm7 - mm7
drop-heuristic: drop_heuristic:
description: description:
- Do not quarantine files detected by heuristics found in sessions using the selected protocols. Dropped files are deleted instead of - Do not quarantine files detected by heuristics found in sessions using the selected protocols. Dropped files are deleted instead of
being quarantined. being quarantined.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -124,9 +135,10 @@ options:
- mm3 - mm3
- mm4 - mm4
- mm7 - mm7
drop-infected: drop_infected:
description: description:
- Do not quarantine infected files found in sessions using the selected protocols. Dropped files are deleted instead of being quarantined. - Do not quarantine infected files found in sessions using the selected protocols. Dropped files are deleted instead of being quarantined.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -148,18 +160,22 @@ options:
lowspace: lowspace:
description: description:
- Select the method for handling additional files when running low on disk space. - Select the method for handling additional files when running low on disk space.
type: str
choices: choices:
- drop-new - drop-new
- ovrw-old - ovrw-old
maxfilesize: maxfilesize:
description: description:
- Maximum file size to quarantine (0 - 500 Mbytes, 0 means unlimited). - Maximum file size to quarantine (0 - 500 Mbytes, 0 means unlimited).
quarantine-quota: type: int
quarantine_quota:
description: description:
- The amount of disk space to reserve for quarantining files (0 - 4294967295 Mbytes, depends on disk space). - The amount of disk space to reserve for quarantining files (0 - 4294967295 Mbytes, depends on disk space).
store-blocked: type: int
store_blocked:
description: description:
- Quarantine blocked files found in sessions using the selected protocols. - Quarantine blocked files found in sessions using the selected protocols.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -177,9 +193,10 @@ options:
- mm3 - mm3
- mm4 - mm4
- mm7 - mm7
store-heuristic: store_heuristic:
description: description:
- Quarantine files detected by heuristics found in sessions using the selected protocols. - Quarantine files detected by heuristics found in sessions using the selected protocols.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -198,9 +215,10 @@ options:
- mm3 - mm3
- mm4 - mm4
- mm7 - mm7
store-infected: store_infected:
description: description:
- Quarantine infected files found in sessions using the selected protocols. - Quarantine infected files found in sessions using the selected protocols.
type: str
choices: choices:
- imap - imap
- smtp - smtp
@ -228,6 +246,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure quarantine options. - name: Configure quarantine options.
fortios_antivirus_quarantine: fortios_antivirus_quarantine:
@ -235,18 +254,19 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
antivirus_quarantine: antivirus_quarantine:
agelimit: "3" agelimit: "3"
destination: "NULL" destination: "NULL"
drop-blocked: "imap" drop_blocked: "imap"
drop-heuristic: "imap" drop_heuristic: "imap"
drop-infected: "imap" drop_infected: "imap"
lowspace: "drop-new" lowspace: "drop-new"
maxfilesize: "9" maxfilesize: "9"
quarantine-quota: "10" quarantine_quota: "10"
store-blocked: "imap" store_blocked: "imap"
store-heuristic: "imap" store_heuristic: "imap"
store-infected: "imap" store_infected: "imap"
''' '''
RETURN = ''' RETURN = '''
@ -309,14 +329,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -324,14 +346,14 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_antivirus_quarantine_data(json): def filter_antivirus_quarantine_data(json):
option_list = ['agelimit', 'destination', 'drop-blocked', option_list = ['agelimit', 'destination', 'drop_blocked',
'drop-heuristic', 'drop-infected', 'lowspace', 'drop_heuristic', 'drop_infected', 'lowspace',
'maxfilesize', 'quarantine-quota', 'store-blocked', 'maxfilesize', 'quarantine_quota', 'store_blocked',
'store-heuristic', 'store-infected'] 'store_heuristic', 'store_infected']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -341,57 +363,74 @@ def filter_antivirus_quarantine_data(json):
return dictionary 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 antivirus_quarantine(data, fos): def antivirus_quarantine(data, fos):
vdom = data['vdom'] vdom = data['vdom']
antivirus_quarantine_data = data['antivirus_quarantine'] antivirus_quarantine_data = data['antivirus_quarantine']
filtered_data = filter_antivirus_quarantine_data(antivirus_quarantine_data) filtered_data = underscore_to_hyphen(filter_antivirus_quarantine_data(antivirus_quarantine_data))
return fos.set('antivirus', return fos.set('antivirus',
'quarantine', 'quarantine',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_antivirus(data, fos): def fortios_antivirus(data, fos):
login(data)
methodlist = ['antivirus_quarantine'] if data['antivirus_quarantine']:
for method in methodlist: resp = antivirus_quarantine(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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},
"antivirus_quarantine": { "antivirus_quarantine": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"agelimit": {"required": False, "type": "int"}, "agelimit": {"required": False, "type": "int"},
"destination": {"required": False, "type": "str", "destination": {"required": False, "type": "str",
"choices": ["NULL", "disk", "FortiAnalyzer"]}, "choices": ["NULL", "disk", "FortiAnalyzer"]},
"drop-blocked": {"required": False, "type": "str", "drop_blocked": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
"ftps", "mapi", "cifs", "ftps", "mapi", "cifs",
"mm1", "mm3", "mm4", "mm1", "mm3", "mm4",
"mm7"]}, "mm7"]},
"drop-heuristic": {"required": False, "type": "str", "drop_heuristic": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
"https", "ftps", "mapi", "https", "ftps", "mapi",
"cifs", "mm1", "mm3", "cifs", "mm1", "mm3",
"mm4", "mm7"]}, "mm4", "mm7"]},
"drop-infected": {"required": False, "type": "str", "drop_infected": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
@ -401,22 +440,22 @@ def main():
"lowspace": {"required": False, "type": "str", "lowspace": {"required": False, "type": "str",
"choices": ["drop-new", "ovrw-old"]}, "choices": ["drop-new", "ovrw-old"]},
"maxfilesize": {"required": False, "type": "int"}, "maxfilesize": {"required": False, "type": "int"},
"quarantine-quota": {"required": False, "type": "int"}, "quarantine_quota": {"required": False, "type": "int"},
"store-blocked": {"required": False, "type": "str", "store_blocked": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
"ftps", "mapi", "cifs", "ftps", "mapi", "cifs",
"mm1", "mm3", "mm4", "mm1", "mm3", "mm4",
"mm7"]}, "mm7"]},
"store-heuristic": {"required": False, "type": "str", "store_heuristic": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
"https", "ftps", "mapi", "https", "ftps", "mapi",
"cifs", "mm1", "mm3", "cifs", "mm1", "mm3",
"mm4", "mm7"]}, "mm4", "mm7"]},
"store-infected": {"required": False, "type": "str", "store_infected": {"required": False, "type": "str",
"choices": ["imap", "smtp", "pop3", "choices": ["imap", "smtp", "pop3",
"http", "ftp", "nntp", "http", "ftp", "nntp",
"imaps", "smtps", "pop3s", "imaps", "smtps", "pop3s",
@ -430,15 +469,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_antivirus(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_antivirus(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_antivirus(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_antivirus_settings module: fortios_antivirus_settings
short_description: Configure AntiVirus settings in Fortinet's FortiOS and FortiGate. short_description: Configure AntiVirus settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure antivirus feature and settings category. user to set and modify antivirus feature and settings category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,37 +41,48 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: false default: true
version_added: 2.9
antivirus_settings: antivirus_settings:
description: description:
- Configure AntiVirus settings. - Configure AntiVirus settings.
default: null default: null
type: dict
suboptions: suboptions:
default-db: default_db:
description: description:
- Select the AV database to be used for AV scanning. - Select the AV database to be used for AV scanning.
type: str
choices: choices:
- normal - normal
- extended - extended
@ -82,13 +90,15 @@ options:
grayware: grayware:
description: description:
- Enable/disable grayware detection when an AntiVirus profile is applied to traffic. - Enable/disable grayware detection when an AntiVirus profile is applied to traffic.
type: str
choices: choices:
- enable - enable
- disable - disable
override-timeout: override_timeout:
description: description:
- Override the large file scan timeout value in seconds (30 - 3600). Zero is the default value and is used to disable this command. When - Override the large file scan timeout value in seconds (30 - 3600). Zero is the default value and is used to disable this command. When
disabled, the daemon adjusts the large file scan timeout based on the file size. disabled, the daemon adjusts the large file scan timeout based on the file size.
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -98,6 +108,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure AntiVirus settings. - name: Configure AntiVirus settings.
fortios_antivirus_settings: fortios_antivirus_settings:
@ -105,10 +116,11 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
antivirus_settings: antivirus_settings:
default-db: "normal" default_db: "normal"
grayware: "enable" grayware: "enable"
override-timeout: "5" override_timeout: "5"
''' '''
RETURN = ''' RETURN = '''
@ -171,14 +183,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -186,11 +200,11 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_antivirus_settings_data(json): def filter_antivirus_settings_data(json):
option_list = ['default-db', 'grayware', 'override-timeout'] option_list = ['default_db', 'grayware', 'override_timeout']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -200,44 +214,61 @@ def filter_antivirus_settings_data(json):
return dictionary 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 antivirus_settings(data, fos): def antivirus_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
antivirus_settings_data = data['antivirus_settings'] antivirus_settings_data = data['antivirus_settings']
filtered_data = filter_antivirus_settings_data(antivirus_settings_data) filtered_data = underscore_to_hyphen(filter_antivirus_settings_data(antivirus_settings_data))
return fos.set('antivirus', return fos.set('antivirus',
'settings', 'settings',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_antivirus(data, fos): def fortios_antivirus(data, fos):
login(data)
methodlist = ['antivirus_settings'] if data['antivirus_settings']:
for method in methodlist: resp = antivirus_settings(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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},
"antivirus_settings": { "antivirus_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"default-db": {"required": False, "type": "str", "default_db": {"required": False, "type": "str",
"choices": ["normal", "extended", "extreme"]}, "choices": ["normal", "extended", "extreme"]},
"grayware": {"required": False, "type": "str", "grayware": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"override-timeout": {"required": False, "type": "int"} "override_timeout": {"required": False, "type": "int"}
} }
} }
@ -245,15 +276,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_antivirus(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_antivirus(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_antivirus(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_application_custom module: fortios_application_custom
short_description: Configure custom application signatures in Fortinet's FortiOS and FortiGate. short_description: Configure custom application signatures in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure application feature and custom category. user to set and modify application feature and custom category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,71 +41,93 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
application_custom: application_custom:
description: description:
- Configure custom application signatures. - Configure custom application signatures.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
behavior: behavior:
description: description:
- Custom application signature behavior. - Custom application signature behavior.
type: str
category: category:
description: description:
- Custom application category ID (use ? to view available options). - Custom application category ID (use ? to view available options).
type: int
comment: comment:
description: description:
- Comment. - Comment.
type: str
id: id:
description: description:
- Custom application category ID (use ? to view available options). - Custom application category ID (use ? to view available options).
type: int
name: name:
description: description:
- Name of this custom application signature. - Name of this custom application signature.
type: str
protocol: protocol:
description: description:
- Custom application signature protocol. - Custom application signature protocol.
type: str
signature: signature:
description: description:
- The text that makes up the actual custom application signature. - The text that makes up the actual custom application signature.
type: str
tag: tag:
description: description:
- Signature tag. - Signature tag.
required: true required: true
type: str
technology: technology:
description: description:
- Custom application signature technology. - Custom application signature technology.
type: str
vendor: vendor:
description: description:
- Custom application signature vendor. - Custom application signature vendor.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -118,6 +137,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure custom application signatures. - name: Configure custom application signatures.
fortios_application_custom: fortios_application_custom:
@ -125,8 +145,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
application_custom: application_custom:
state: "present"
behavior: "<your_own_value>" behavior: "<your_own_value>"
category: "4" category: "4"
comment: "Comment." comment: "Comment."
@ -199,14 +220,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -214,7 +237,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_application_custom_data(json): def filter_application_custom_data(json):
@ -231,48 +254,66 @@ def filter_application_custom_data(json):
return dictionary 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 application_custom(data, fos): def application_custom(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
application_custom_data = data['application_custom'] application_custom_data = data['application_custom']
filtered_data = filter_application_custom_data(application_custom_data) filtered_data = underscore_to_hyphen(filter_application_custom_data(application_custom_data))
if application_custom_data['state'] == "present":
if state == "present":
return fos.set('application', return fos.set('application',
'custom', 'custom',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif application_custom_data['state'] == "absent": elif state == "absent":
return fos.delete('application', return fos.delete('application',
'custom', 'custom',
mkey=filtered_data['tag'], mkey=filtered_data['tag'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_application(data, fos): def fortios_application(data, fos):
login(data)
methodlist = ['application_custom'] if data['application_custom']:
for method in methodlist: resp = application_custom(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"application_custom": { "application_custom": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"behavior": {"required": False, "type": "str"}, "behavior": {"required": False, "type": "str"},
"category": {"required": False, "type": "int"}, "category": {"required": False, "type": "int"},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
@ -290,15 +331,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_application(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_application(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_application(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_application_group module: fortios_application_group
short_description: Configure firewall application groups in Fortinet's FortiOS and FortiGate. short_description: Configure firewall application groups in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure application feature and group category. user to set and modify application feature and group category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,66 +41,85 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
application_group: application_group:
description: description:
- Configure firewall application groups. - Configure firewall application groups.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
application: application:
description: description:
- Application ID list. - Application ID list.
type: list
suboptions: suboptions:
id: id:
description: description:
- Application IDs. - Application IDs.
required: true required: true
type: int
category: category:
description: description:
- Application category ID list. - Application category ID list.
type: list
suboptions: suboptions:
id: id:
description: description:
- Category IDs. - Category IDs.
required: true required: true
type: int
comment: comment:
description: description:
- Comment - Comment
type: str
name: name:
description: description:
- Application group name. - Application group name.
required: true required: true
type: str
type: type:
description: description:
- Application group type. - Application group type.
type: str
choices: choices:
- application - application
- category - category
@ -116,6 +132,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure firewall application groups. - name: Configure firewall application groups.
fortios_application_group: fortios_application_group:
@ -123,8 +140,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
application_group: application_group:
state: "present"
application: application:
- -
id: "4" id: "4"
@ -196,14 +214,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -211,7 +231,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_application_group_data(json): def filter_application_group_data(json):
@ -226,48 +246,66 @@ def filter_application_group_data(json):
return dictionary 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 application_group(data, fos): def application_group(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
application_group_data = data['application_group'] application_group_data = data['application_group']
filtered_data = filter_application_group_data(application_group_data) filtered_data = underscore_to_hyphen(filter_application_group_data(application_group_data))
if application_group_data['state'] == "present":
if state == "present":
return fos.set('application', return fos.set('application',
'group', 'group',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif application_group_data['state'] == "absent": elif state == "absent":
return fos.delete('application', return fos.delete('application',
'group', 'group',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_application(data, fos): def fortios_application(data, fos):
login(data)
methodlist = ['application_group'] if data['application_group']:
for method in methodlist: resp = application_group(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"application_group": { "application_group": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"application": {"required": False, "type": "list", "application": {"required": False, "type": "list",
"options": { "options": {
"id": {"required": True, "type": "int"} "id": {"required": True, "type": "int"}
@ -287,15 +325,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_application(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_application(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_application(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -27,12 +24,12 @@ ANSIBLE_METADATA = {'status': ['preview'],
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: fortios_application_list module: fortios_application_list
short_description: Configure application control lists. short_description: Configure application control lists in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure application feature and list category. user to set and modify application feature and list category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,62 +41,79 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
application_list: application_list:
description: description:
- Configure application control lists. - Configure application control lists.
default: null default: null
type: dict
suboptions: suboptions:
state: app_replacemsg:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
app-replacemsg:
description: description:
- Enable/disable replacement messages for blocked applications. - Enable/disable replacement messages for blocked applications.
type: str
choices: choices:
- disable - disable
- enable - enable
comment: comment:
description: description:
- comments - comments
deep-app-inspection: type: str
deep_app_inspection:
description: description:
- Enable/disable deep application inspection. - Enable/disable deep application inspection.
type: str
choices: choices:
- disable - disable
- enable - enable
entries: entries:
description: description:
- Application list entries. - Application list entries.
type: list
suboptions: suboptions:
action: action:
description: description:
- Pass or block traffic, or reset connection for traffic from this application. - Pass or block traffic, or reset connection for traffic from this application.
type: str
choices: choices:
- pass - pass
- block - block
@ -107,55 +121,68 @@ options:
application: application:
description: description:
- ID of allowed applications. - ID of allowed applications.
type: list
suboptions: suboptions:
id: id:
description: description:
- Application IDs. - Application IDs.
required: true required: true
type: int
behavior: behavior:
description: description:
- Application behavior filter. - Application behavior filter.
type: str
category: category:
description: description:
- Category ID list. - Category ID list.
type: list
suboptions: suboptions:
id: id:
description: description:
- Application category ID. - Application category ID.
required: true required: true
type: int
id: id:
description: description:
- Entry ID. - Entry ID.
required: true required: true
type: int
log: log:
description: description:
- Enable/disable logging for this application list. - Enable/disable logging for this application list.
type: str
choices: choices:
- disable - disable
- enable - enable
log-packet: log_packet:
description: description:
- Enable/disable packet logging. - Enable/disable packet logging.
type: str
choices: choices:
- disable - disable
- enable - enable
parameters: parameters:
description: description:
- Application parameters. - Application parameters.
type: list
suboptions: suboptions:
id: id:
description: description:
- Parameter ID. - Parameter ID.
required: true required: true
type: int
value: value:
description: description:
- Parameter value. - Parameter value.
per-ip-shaper: type: str
per_ip_shaper:
description: description:
- Per-IP traffic shaper. Source firewall.shaper.per-ip-shaper.name. - Per-IP traffic shaper. Source firewall.shaper.per-ip-shaper.name.
type: str
popularity: popularity:
description: description:
- Application popularity filter (1 - 5, from least to most popular). - Application popularity filter (1 - 5, from least to most popular).
type: str
choices: choices:
- 1 - 1
- 2 - 2
@ -165,36 +192,44 @@ options:
protocols: protocols:
description: description:
- Application protocol filter. - Application protocol filter.
type: str
quarantine: quarantine:
description: description:
- Quarantine method. - Quarantine method.
type: str
choices: choices:
- none - none
- attacker - attacker
quarantine-expiry: quarantine_expiry:
description: description:
- Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m). Requires quarantine set to attacker. - Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m). Requires quarantine set to attacker.
quarantine-log: type: str
quarantine_log:
description: description:
- Enable/disable quarantine logging. - Enable/disable quarantine logging.
type: str
choices: choices:
- disable - disable
- enable - enable
rate-count: rate_count:
description: description:
- Count of the rate. - Count of the rate.
rate-duration: type: int
rate_duration:
description: description:
- Duration (sec) of the rate. - Duration (sec) of the rate.
rate-mode: type: int
rate_mode:
description: description:
- Rate limit mode. - Rate limit mode.
type: str
choices: choices:
- periodical - periodical
- continuous - continuous
rate-track: rate_track:
description: description:
- Track the packet protocol field. - Track the packet protocol field.
type: str
choices: choices:
- none - none
- src-ip - src-ip
@ -204,37 +239,47 @@ options:
risk: risk:
description: description:
- Risk, or impact, of allowing traffic from this application to occur (1 - 5; Low, Elevated, Medium, High, and Critical). - Risk, or impact, of allowing traffic from this application to occur (1 - 5; Low, Elevated, Medium, High, and Critical).
type: list
suboptions: suboptions:
level: level:
description: description:
- Risk, or impact, of allowing traffic from this application to occur (1 - 5; Low, Elevated, Medium, High, and Critical). - Risk, or impact, of allowing traffic from this application to occur (1 - 5; Low, Elevated, Medium, High, and Critical).
required: true required: true
session-ttl: type: int
session_ttl:
description: description:
- Session TTL (0 = default). - Session TTL (0 = default).
type: int
shaper: shaper:
description: description:
- Traffic shaper. Source firewall.shaper.traffic-shaper.name. - Traffic shaper. Source firewall.shaper.traffic-shaper.name.
shaper-reverse: type: str
shaper_reverse:
description: description:
- Reverse traffic shaper. Source firewall.shaper.traffic-shaper.name. - Reverse traffic shaper. Source firewall.shaper.traffic-shaper.name.
sub-category: type: str
sub_category:
description: description:
- Application Sub-category ID list. - Application Sub-category ID list.
type: list
suboptions: suboptions:
id: id:
description: description:
- Application sub-category ID. - Application sub-category ID.
required: true required: true
type: int
technology: technology:
description: description:
- Application technology filter. - Application technology filter.
type: str
vendor: vendor:
description: description:
- Application vendor filter. - Application vendor filter.
extended-log: type: str
extended_log:
description: description:
- Enable/disable extended logging. - Enable/disable extended logging.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -242,46 +287,54 @@ options:
description: description:
- List name. - List name.
required: true required: true
type: str
options: options:
description: description:
- Basic application protocol signatures allowed by default. - Basic application protocol signatures allowed by default.
type: str
choices: choices:
- allow-dns - allow-dns
- allow-icmp - allow-icmp
- allow-http - allow-http
- allow-ssl - allow-ssl
- allow-quic - allow-quic
other-application-action: other_application_action:
description: description:
- Action for other applications. - Action for other applications.
type: str
choices: choices:
- pass - pass
- block - block
other-application-log: other_application_log:
description: description:
- Enable/disable logging for other applications. - Enable/disable logging for other applications.
type: str
choices: choices:
- disable - disable
- enable - enable
p2p-black-list: p2p_black_list:
description: description:
- P2P applications to be black listed. - P2P applications to be black listed.
type: str
choices: choices:
- skype - skype
- edonkey - edonkey
- bittorrent - bittorrent
replacemsg-group: replacemsg_group:
description: description:
- Replacement message group. Source system.replacemsg-group.name. - Replacement message group. Source system.replacemsg-group.name.
unknown-application-action: type: str
unknown_application_action:
description: description:
- Pass or block traffic from unknown applications. - Pass or block traffic from unknown applications.
type: str
choices: choices:
- pass - pass
- block - block
unknown-application-log: unknown_application_log:
description: description:
- Enable/disable logging for unknown applications. - Enable/disable logging for unknown applications.
type: str
choices: choices:
- disable - disable
- enable - enable
@ -294,18 +347,20 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure application control lists. - name: Configure application control lists.
fortios_application_list: fortios_application_list:
host: "{{ host }}" host: "{{ host }}"
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
application_list: application_list:
state: "present" app_replacemsg: "disable"
app-replacemsg: "disable"
comment: "comments" comment: "comments"
deep-app-inspection: "disable" deep_app_inspection: "disable"
entries: entries:
- -
action: "pass" action: "pass"
@ -318,41 +373,41 @@ EXAMPLES = '''
id: "12" id: "12"
id: "13" id: "13"
log: "disable" log: "disable"
log-packet: "disable" log_packet: "disable"
parameters: parameters:
- -
id: "17" id: "17"
value: "<your_own_value>" value: "<your_own_value>"
per-ip-shaper: "<your_own_value> (source firewall.shaper.per-ip-shaper.name)" per_ip_shaper: "<your_own_value> (source firewall.shaper.per-ip-shaper.name)"
popularity: "1" popularity: "1"
protocols: "<your_own_value>" protocols: "<your_own_value>"
quarantine: "none" quarantine: "none"
quarantine-expiry: "<your_own_value>" quarantine_expiry: "<your_own_value>"
quarantine-log: "disable" quarantine_log: "disable"
rate-count: "25" rate_count: "25"
rate-duration: "26" rate_duration: "26"
rate-mode: "periodical" rate_mode: "periodical"
rate-track: "none" rate_track: "none"
risk: risk:
- -
level: "30" level: "30"
session-ttl: "31" session_ttl: "31"
shaper: "<your_own_value> (source firewall.shaper.traffic-shaper.name)" shaper: "<your_own_value> (source firewall.shaper.traffic-shaper.name)"
shaper-reverse: "<your_own_value> (source firewall.shaper.traffic-shaper.name)" shaper_reverse: "<your_own_value> (source firewall.shaper.traffic-shaper.name)"
sub-category: sub_category:
- -
id: "35" id: "35"
technology: "<your_own_value>" technology: "<your_own_value>"
vendor: "<your_own_value>" vendor: "<your_own_value>"
extended-log: "enable" extended_log: "enable"
name: "default_name_39" name: "default_name_39"
options: "allow-dns" options: "allow-dns"
other-application-action: "pass" other_application_action: "pass"
other-application-log: "disable" other_application_log: "disable"
p2p-black-list: "skype" p2p_black_list: "skype"
replacemsg-group: "<your_own_value> (source system.replacemsg-group.name)" replacemsg_group: "<your_own_value> (source system.replacemsg-group.name)"
unknown-application-action: "pass" unknown_application_action: "pass"
unknown-application-log: "disable" unknown_application_log: "disable"
''' '''
RETURN = ''' RETURN = '''
@ -375,7 +430,7 @@ mkey:
description: Master key (id) used in the last call to FortiGate description: Master key (id) used in the last call to FortiGate
returned: success returned: success
type: str type: str
sample: "key1" sample: "id"
name: name:
description: Name of the table used to fulfill the request description: Name of the table used to fulfill the request
returned: always returned: always
@ -415,14 +470,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -430,70 +487,88 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_application_list_data(json): def filter_application_list_data(json):
option_list = ['app-replacemsg', 'comment', 'deep-app-inspection', option_list = ['app_replacemsg', 'comment', 'deep_app_inspection',
'entries', 'extended-log', 'name', 'entries', 'extended_log', 'name',
'options', 'other-application-action', 'other-application-log', 'options', 'other_application_action', 'other_application_log',
'p2p-black-list', 'replacemsg-group', 'unknown-application-action', 'p2p_black_list', 'replacemsg_group', 'unknown_application_action',
'unknown-application-log'] 'unknown_application_log']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
if attribute in json: if attribute in json and json[attribute] is not None:
dictionary[attribute] = json[attribute] dictionary[attribute] = json[attribute]
return dictionary 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 application_list(data, fos): def application_list(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
application_list_data = data['application_list'] application_list_data = data['application_list']
filtered_data = filter_application_list_data(application_list_data) filtered_data = underscore_to_hyphen(filter_application_list_data(application_list_data))
if application_list_data['state'] == "present":
if state == "present":
return fos.set('application', return fos.set('application',
'list', 'list',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif application_list_data['state'] == "absent": elif state == "absent":
return fos.delete('application', return fos.delete('application',
'list', 'list',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_application(data, fos): def fortios_application(data, fos):
login(data)
methodlist = ['application_list'] if data['application_list']:
for method in methodlist: resp = application_list(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"application_list": { "application_list": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "app_replacemsg": {"required": False, "type": "str",
"choices": ["present", "absent"]},
"app-replacemsg": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
"deep-app-inspection": {"required": False, "type": "str", "deep_app_inspection": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"entries": {"required": False, "type": "list", "entries": {"required": False, "type": "list",
"options": { "options": {
@ -511,60 +586,60 @@ def main():
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"log-packet": {"required": False, "type": "str", "log_packet": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"parameters": {"required": False, "type": "list", "parameters": {"required": False, "type": "list",
"options": { "options": {
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"value": {"required": False, "type": "str"} "value": {"required": False, "type": "str"}
}}, }},
"per-ip-shaper": {"required": False, "type": "str"}, "per_ip_shaper": {"required": False, "type": "str"},
"popularity": {"required": False, "type": "str", "popularity": {"required": False, "type": "str",
"choices": ["1", "2", "3", "choices": ["1", "2", "3",
"4", "5"]}, "4", "5"]},
"protocols": {"required": False, "type": "str"}, "protocols": {"required": False, "type": "str"},
"quarantine": {"required": False, "type": "str", "quarantine": {"required": False, "type": "str",
"choices": ["none", "attacker"]}, "choices": ["none", "attacker"]},
"quarantine-expiry": {"required": False, "type": "str"}, "quarantine_expiry": {"required": False, "type": "str"},
"quarantine-log": {"required": False, "type": "str", "quarantine_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"rate-count": {"required": False, "type": "int"}, "rate_count": {"required": False, "type": "int"},
"rate-duration": {"required": False, "type": "int"}, "rate_duration": {"required": False, "type": "int"},
"rate-mode": {"required": False, "type": "str", "rate_mode": {"required": False, "type": "str",
"choices": ["periodical", "continuous"]}, "choices": ["periodical", "continuous"]},
"rate-track": {"required": False, "type": "str", "rate_track": {"required": False, "type": "str",
"choices": ["none", "src-ip", "dest-ip", "choices": ["none", "src-ip", "dest-ip",
"dhcp-client-mac", "dns-domain"]}, "dhcp-client-mac", "dns-domain"]},
"risk": {"required": False, "type": "list", "risk": {"required": False, "type": "list",
"options": { "options": {
"level": {"required": True, "type": "int"} "level": {"required": True, "type": "int"}
}}, }},
"session-ttl": {"required": False, "type": "int"}, "session_ttl": {"required": False, "type": "int"},
"shaper": {"required": False, "type": "str"}, "shaper": {"required": False, "type": "str"},
"shaper-reverse": {"required": False, "type": "str"}, "shaper_reverse": {"required": False, "type": "str"},
"sub-category": {"required": False, "type": "list", "sub_category": {"required": False, "type": "list",
"options": { "options": {
"id": {"required": True, "type": "int"} "id": {"required": True, "type": "int"}
}}, }},
"technology": {"required": False, "type": "str"}, "technology": {"required": False, "type": "str"},
"vendor": {"required": False, "type": "str"} "vendor": {"required": False, "type": "str"}
}}, }},
"extended-log": {"required": False, "type": "str", "extended_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"options": {"required": False, "type": "str", "options": {"required": False, "type": "str",
"choices": ["allow-dns", "allow-icmp", "allow-http", "choices": ["allow-dns", "allow-icmp", "allow-http",
"allow-ssl", "allow-quic"]}, "allow-ssl", "allow-quic"]},
"other-application-action": {"required": False, "type": "str", "other_application_action": {"required": False, "type": "str",
"choices": ["pass", "block"]}, "choices": ["pass", "block"]},
"other-application-log": {"required": False, "type": "str", "other_application_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"p2p-black-list": {"required": False, "type": "str", "p2p_black_list": {"required": False, "type": "str",
"choices": ["skype", "edonkey", "bittorrent"]}, "choices": ["skype", "edonkey", "bittorrent"]},
"replacemsg-group": {"required": False, "type": "str"}, "replacemsg_group": {"required": False, "type": "str"},
"unknown-application-action": {"required": False, "type": "str", "unknown_application_action": {"required": False, "type": "str",
"choices": ["pass", "block"]}, "choices": ["pass", "block"]},
"unknown-application-log": {"required": False, "type": "str", "unknown_application_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]} "choices": ["disable", "enable"]}
} }
@ -573,15 +648,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_application(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_application(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_application(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_application_name module: fortios_application_name
short_description: Configure application signatures in Fortinet's FortiOS and FortiGate. short_description: Configure application signatures in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure application feature and name category. user to set and modify application feature and name category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,91 +41,119 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
application_name: application_name:
description: description:
- Configure application signatures. - Configure application signatures.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
behavior: behavior:
description: description:
- Application behavior. - Application behavior.
type: str
category: category:
description: description:
- Application category ID. - Application category ID.
type: int
id: id:
description: description:
- Application ID. - Application ID.
type: int
metadata: metadata:
description: description:
- Meta data. - Meta data.
type: list
suboptions: suboptions:
id: id:
description: description:
- ID. - ID.
required: true required: true
type: int
metaid: metaid:
description: description:
- Meta ID. - Meta ID.
type: int
valueid: valueid:
description: description:
- Value ID. - Value ID.
type: int
name: name:
description: description:
- Application name. - Application name.
required: true required: true
type: str
parameter: parameter:
description: description:
- Application parameter name. - Application parameter name.
type: str
popularity: popularity:
description: description:
- Application popularity. - Application popularity.
type: int
protocol: protocol:
description: description:
- Application protocol. - Application protocol.
type: str
risk: risk:
description: description:
- Application risk. - Application risk.
sub-category: type: int
sub_category:
description: description:
- Application sub-category ID. - Application sub-category ID.
type: int
technology: technology:
description: description:
- Application technology. - Application technology.
type: str
vendor: vendor:
description: description:
- Application vendor. - Application vendor.
type: str
weight: weight:
description: description:
- Application weight. - Application weight.
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -138,6 +163,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure application signatures. - name: Configure application signatures.
fortios_application_name: fortios_application_name:
@ -145,8 +171,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
application_name: application_name:
state: "present"
behavior: "<your_own_value>" behavior: "<your_own_value>"
category: "4" category: "4"
id: "5" id: "5"
@ -160,7 +187,7 @@ EXAMPLES = '''
popularity: "12" popularity: "12"
protocol: "<your_own_value>" protocol: "<your_own_value>"
risk: "14" risk: "14"
sub-category: "15" sub_category: "15"
technology: "<your_own_value>" technology: "<your_own_value>"
vendor: "<your_own_value>" vendor: "<your_own_value>"
weight: "18" weight: "18"
@ -226,14 +253,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -241,14 +270,14 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_application_name_data(json): def filter_application_name_data(json):
option_list = ['behavior', 'category', 'id', option_list = ['behavior', 'category', 'id',
'metadata', 'name', 'parameter', 'metadata', 'name', 'parameter',
'popularity', 'protocol', 'risk', 'popularity', 'protocol', 'risk',
'sub-category', 'technology', 'vendor', 'sub_category', 'technology', 'vendor',
'weight'] 'weight']
dictionary = {} dictionary = {}
@ -259,48 +288,66 @@ def filter_application_name_data(json):
return dictionary 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 application_name(data, fos): def application_name(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
application_name_data = data['application_name'] application_name_data = data['application_name']
filtered_data = filter_application_name_data(application_name_data) filtered_data = underscore_to_hyphen(filter_application_name_data(application_name_data))
if application_name_data['state'] == "present":
if state == "present":
return fos.set('application', return fos.set('application',
'name', 'name',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif application_name_data['state'] == "absent": elif state == "absent":
return fos.delete('application', return fos.delete('application',
'name', 'name',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_application(data, fos): def fortios_application(data, fos):
login(data)
methodlist = ['application_name'] if data['application_name']:
for method in methodlist: resp = application_name(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"application_name": { "application_name": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"behavior": {"required": False, "type": "str"}, "behavior": {"required": False, "type": "str"},
"category": {"required": False, "type": "int"}, "category": {"required": False, "type": "int"},
"id": {"required": False, "type": "int"}, "id": {"required": False, "type": "int"},
@ -315,7 +362,7 @@ def main():
"popularity": {"required": False, "type": "int"}, "popularity": {"required": False, "type": "int"},
"protocol": {"required": False, "type": "str"}, "protocol": {"required": False, "type": "str"},
"risk": {"required": False, "type": "int"}, "risk": {"required": False, "type": "int"},
"sub-category": {"required": False, "type": "int"}, "sub_category": {"required": False, "type": "int"},
"technology": {"required": False, "type": "str"}, "technology": {"required": False, "type": "str"},
"vendor": {"required": False, "type": "str"}, "vendor": {"required": False, "type": "str"},
"weight": {"required": False, "type": "int"} "weight": {"required": False, "type": "int"}
@ -326,15 +373,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_application(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_application(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_application(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_application_rule_settings module: fortios_application_rule_settings
short_description: Configure application rule settings in Fortinet's FortiOS and FortiGate. short_description: Configure application rule settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure application feature and rule_settings category. user to set and modify application feature and rule_settings category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,44 +41,57 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
application_rule_settings: application_rule_settings:
description: description:
- Configure application rule settings. - Configure application rule settings.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
id: id:
description: description:
- Rule ID. - Rule ID.
required: true required: true
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -91,6 +101,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure application rule settings. - name: Configure application rule settings.
fortios_application_rule_settings: fortios_application_rule_settings:
@ -98,8 +109,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
application_rule_settings: application_rule_settings:
state: "present"
id: "3" id: "3"
''' '''
@ -163,14 +175,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -178,7 +192,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_application_rule_settings_data(json): def filter_application_rule_settings_data(json):
@ -192,48 +206,66 @@ def filter_application_rule_settings_data(json):
return dictionary 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 application_rule_settings(data, fos): def application_rule_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
application_rule_settings_data = data['application_rule_settings'] application_rule_settings_data = data['application_rule_settings']
filtered_data = filter_application_rule_settings_data(application_rule_settings_data) filtered_data = underscore_to_hyphen(filter_application_rule_settings_data(application_rule_settings_data))
if application_rule_settings_data['state'] == "present":
if state == "present":
return fos.set('application', return fos.set('application',
'rule-settings', 'rule-settings',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif application_rule_settings_data['state'] == "absent": elif state == "absent":
return fos.delete('application', return fos.delete('application',
'rule-settings', 'rule-settings',
mkey=filtered_data['id'], mkey=filtered_data['id'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_application(data, fos): def fortios_application(data, fos):
login(data)
methodlist = ['application_rule_settings'] if data['application_rule_settings']:
for method in methodlist: resp = application_rule_settings(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"application_rule_settings": { "application_rule_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"id": {"required": True, "type": "int"} "id": {"required": True, "type": "int"}
} }
@ -242,15 +274,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_application(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_application(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_application(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_authentication_rule module: fortios_authentication_rule
short_description: Configure Authentication Rules in Fortinet's FortiOS and FortiGate. short_description: Configure Authentication Rules in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure authentication feature and rule category. user to set and modify authentication feature and rule category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,49 +41,64 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
authentication_rule: authentication_rule:
description: description:
- Configure Authentication Rules. - Configure Authentication Rules.
default: null default: null
type: dict
suboptions: suboptions:
state: active_auth_method:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
active-auth-method:
description: description:
- Select an active authentication method. Source authentication.scheme.name. - Select an active authentication method. Source authentication.scheme.name.
type: str
comments: comments:
description: description:
- Comment. - Comment.
ip-based: type: str
ip_based:
description: description:
- Enable/disable IP-based authentication. Once a user authenticates all traffic from the IP address the user authenticated from is allowed. - Enable/disable IP-based authentication. Once a user authenticates all traffic from the IP address the user authenticated from is allowed.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -94,10 +106,12 @@ options:
description: description:
- Authentication rule name. - Authentication rule name.
required: true required: true
type: str
protocol: protocol:
description: description:
- Select the protocol to use for authentication (default = http). Users connect to the FortiGate using this protocol and are asked to - Select the protocol to use for authentication (default = http). Users connect to the FortiGate using this protocol and are asked to
authenticate. authenticate.
type: str
choices: choices:
- http - http
- ftp - ftp
@ -106,37 +120,45 @@ options:
srcaddr: srcaddr:
description: description:
- Select an IPv4 source address from available options. Required for web proxy authentication. - Select an IPv4 source address from available options. Required for web proxy authentication.
type: list
suboptions: suboptions:
name: name:
description: description:
- Address name. Source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name. - Address name. Source firewall.address.name firewall.addrgrp.name firewall.proxy-address.name firewall.proxy-addrgrp.name.
required: true required: true
type: str
srcaddr6: srcaddr6:
description: description:
- Select an IPv6 source address. Required for web proxy authentication. - Select an IPv6 source address. Required for web proxy authentication.
type: list
suboptions: suboptions:
name: name:
description: description:
- Address name. Source firewall.address6.name firewall.addrgrp6.name. - Address name. Source firewall.address6.name firewall.addrgrp6.name.
required: true required: true
sso-auth-method: type: str
sso_auth_method:
description: description:
- Select a single-sign on (SSO) authentication method. Source authentication.scheme.name. - Select a single-sign on (SSO) authentication method. Source authentication.scheme.name.
type: str
status: status:
description: description:
- Enable/disable this authentication rule. - Enable/disable this authentication rule.
type: str
choices: choices:
- enable - enable
- disable - disable
transaction-based: transaction_based:
description: description:
- Enable/disable transaction based authentication (default = disable). - Enable/disable transaction based authentication (default = disable).
type: str
choices: choices:
- enable - enable
- disable - disable
web-auth-cookie: web_auth_cookie:
description: description:
- Enable/disable Web authentication cookies (default = disable). - Enable/disable Web authentication cookies (default = disable).
type: str
choices: choices:
- enable - enable
- disable - disable
@ -149,6 +171,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure Authentication Rules. - name: Configure Authentication Rules.
fortios_authentication_rule: fortios_authentication_rule:
@ -156,11 +179,12 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
authentication_rule: authentication_rule:
state: "present" active_auth_method: "<your_own_value> (source authentication.scheme.name)"
active-auth-method: "<your_own_value> (source authentication.scheme.name)"
comments: "<your_own_value>" comments: "<your_own_value>"
ip-based: "enable" ip_based: "enable"
name: "default_name_6" name: "default_name_6"
protocol: "http" protocol: "http"
srcaddr: srcaddr:
@ -169,10 +193,10 @@ EXAMPLES = '''
srcaddr6: srcaddr6:
- -
name: "default_name_11 (source firewall.address6.name firewall.addrgrp6.name)" name: "default_name_11 (source firewall.address6.name firewall.addrgrp6.name)"
sso-auth-method: "<your_own_value> (source authentication.scheme.name)" sso_auth_method: "<your_own_value> (source authentication.scheme.name)"
status: "enable" status: "enable"
transaction-based: "enable" transaction_based: "enable"
web-auth-cookie: "enable" web_auth_cookie: "enable"
''' '''
RETURN = ''' RETURN = '''
@ -235,14 +259,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -250,14 +276,14 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_authentication_rule_data(json): def filter_authentication_rule_data(json):
option_list = ['active-auth-method', 'comments', 'ip-based', option_list = ['active_auth_method', 'comments', 'ip_based',
'name', 'protocol', 'srcaddr', 'name', 'protocol', 'srcaddr',
'srcaddr6', 'sso-auth-method', 'status', 'srcaddr6', 'sso_auth_method', 'status',
'transaction-based', 'web-auth-cookie'] 'transaction_based', 'web_auth_cookie']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -267,51 +293,69 @@ def filter_authentication_rule_data(json):
return dictionary 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 authentication_rule(data, fos): def authentication_rule(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
authentication_rule_data = data['authentication_rule'] authentication_rule_data = data['authentication_rule']
filtered_data = filter_authentication_rule_data(authentication_rule_data) filtered_data = underscore_to_hyphen(filter_authentication_rule_data(authentication_rule_data))
if authentication_rule_data['state'] == "present":
if state == "present":
return fos.set('authentication', return fos.set('authentication',
'rule', 'rule',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif authentication_rule_data['state'] == "absent": elif state == "absent":
return fos.delete('authentication', return fos.delete('authentication',
'rule', 'rule',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_authentication(data, fos): def fortios_authentication(data, fos):
login(data)
methodlist = ['authentication_rule'] if data['authentication_rule']:
for method in methodlist: resp = authentication_rule(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"authentication_rule": { "authentication_rule": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "active_auth_method": {"required": False, "type": "str"},
"choices": ["present", "absent"]},
"active-auth-method": {"required": False, "type": "str"},
"comments": {"required": False, "type": "str"}, "comments": {"required": False, "type": "str"},
"ip-based": {"required": False, "type": "str", "ip_based": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"protocol": {"required": False, "type": "str", "protocol": {"required": False, "type": "str",
@ -325,12 +369,12 @@ def main():
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"sso-auth-method": {"required": False, "type": "str"}, "sso_auth_method": {"required": False, "type": "str"},
"status": {"required": False, "type": "str", "status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"transaction-based": {"required": False, "type": "str", "transaction_based": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"web-auth-cookie": {"required": False, "type": "str", "web_auth_cookie": {"required": False, "type": "str",
"choices": ["enable", "disable"]} "choices": ["enable", "disable"]}
} }
@ -339,15 +383,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_authentication(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_authentication(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_authentication(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_authentication_scheme module: fortios_authentication_scheme
short_description: Configure Authentication Schemes in Fortinet's FortiOS and FortiGate. short_description: Configure Authentication Schemes in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure authentication feature and scheme category. user to set and modify authentication feature and scheme category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,58 +41,75 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
authentication_scheme: authentication_scheme:
description: description:
- Configure Authentication Schemes. - Configure Authentication Schemes.
default: null default: null
type: dict
suboptions: suboptions:
state: domain_controller:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
domain-controller:
description: description:
- Domain controller setting. Source user.domain-controller.name. - Domain controller setting. Source user.domain-controller.name.
fsso-agent-for-ntlm: type: str
fsso_agent_for_ntlm:
description: description:
- FSSO agent to use for NTLM authentication. Source user.fsso.name. - FSSO agent to use for NTLM authentication. Source user.fsso.name.
fsso-guest: type: str
fsso_guest:
description: description:
- Enable/disable user fsso-guest authentication (default = disable). - Enable/disable user fsso-guest authentication (default = disable).
type: str
choices: choices:
- enable - enable
- disable - disable
kerberos-keytab: kerberos_keytab:
description: description:
- Kerberos keytab setting. Source user.krb-keytab.name. - Kerberos keytab setting. Source user.krb-keytab.name.
type: str
method: method:
description: description:
- Authentication methods (default = basic). - Authentication methods (default = basic).
type: str
choices: choices:
- ntlm - ntlm
- basic - basic
@ -109,29 +123,35 @@ options:
description: description:
- Authentication scheme name. - Authentication scheme name.
required: true required: true
negotiate-ntlm: type: str
negotiate_ntlm:
description: description:
- Enable/disable negotiate authentication for NTLM (default = disable). - Enable/disable negotiate authentication for NTLM (default = disable).
type: str
choices: choices:
- enable - enable
- disable - disable
require-tfa: require_tfa:
description: description:
- Enable/disable two-factor authentication (default = disable). - Enable/disable two-factor authentication (default = disable).
type: str
choices: choices:
- enable - enable
- disable - disable
ssh-ca: ssh_ca:
description: description:
- SSH CA name. Source firewall.ssh.local-ca.name. - SSH CA name. Source firewall.ssh.local-ca.name.
user-database: type: str
user_database:
description: description:
- Authentication server to contain user information; "local" (default) or "123" (for LDAP). - Authentication server to contain user information; "local" (default) or "123" (for LDAP).
type: list
suboptions: suboptions:
name: name:
description: description:
- Authentication server name. Source system.datasource.name user.radius.name user.tacacs+.name user.ldap.name user.group.name. - Authentication server name. Source system.datasource.name user.radius.name user.tacacs+.name user.ldap.name user.group.name.
required: true required: true
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -141,6 +161,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure Authentication Schemes. - name: Configure Authentication Schemes.
fortios_authentication_scheme: fortios_authentication_scheme:
@ -148,18 +169,19 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
authentication_scheme: authentication_scheme:
state: "present" domain_controller: "<your_own_value> (source user.domain-controller.name)"
domain-controller: "<your_own_value> (source user.domain-controller.name)" fsso_agent_for_ntlm: "<your_own_value> (source user.fsso.name)"
fsso-agent-for-ntlm: "<your_own_value> (source user.fsso.name)" fsso_guest: "enable"
fsso-guest: "enable" kerberos_keytab: "<your_own_value> (source user.krb-keytab.name)"
kerberos-keytab: "<your_own_value> (source user.krb-keytab.name)"
method: "ntlm" method: "ntlm"
name: "default_name_8" name: "default_name_8"
negotiate-ntlm: "enable" negotiate_ntlm: "enable"
require-tfa: "enable" require_tfa: "enable"
ssh-ca: "<your_own_value> (source firewall.ssh.local-ca.name)" ssh_ca: "<your_own_value> (source firewall.ssh.local-ca.name)"
user-database: user_database:
- -
name: "default_name_13 (source system.datasource.name user.radius.name user.tacacs+.name user.ldap.name user.group.name)" name: "default_name_13 (source system.datasource.name user.radius.name user.tacacs+.name user.ldap.name user.group.name)"
''' '''
@ -224,14 +246,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -239,14 +263,14 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_authentication_scheme_data(json): def filter_authentication_scheme_data(json):
option_list = ['domain-controller', 'fsso-agent-for-ntlm', 'fsso-guest', option_list = ['domain_controller', 'fsso_agent_for_ntlm', 'fsso_guest',
'kerberos-keytab', 'method', 'name', 'kerberos_keytab', 'method', 'name',
'negotiate-ntlm', 'require-tfa', 'ssh-ca', 'negotiate_ntlm', 'require_tfa', 'ssh_ca',
'user-database'] 'user_database']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -256,64 +280,82 @@ def filter_authentication_scheme_data(json):
return dictionary 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 authentication_scheme(data, fos): def authentication_scheme(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
authentication_scheme_data = data['authentication_scheme'] authentication_scheme_data = data['authentication_scheme']
filtered_data = filter_authentication_scheme_data(authentication_scheme_data) filtered_data = underscore_to_hyphen(filter_authentication_scheme_data(authentication_scheme_data))
if authentication_scheme_data['state'] == "present":
if state == "present":
return fos.set('authentication', return fos.set('authentication',
'scheme', 'scheme',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif authentication_scheme_data['state'] == "absent": elif state == "absent":
return fos.delete('authentication', return fos.delete('authentication',
'scheme', 'scheme',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_authentication(data, fos): def fortios_authentication(data, fos):
login(data)
methodlist = ['authentication_scheme'] if data['authentication_scheme']:
for method in methodlist: resp = authentication_scheme(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"authentication_scheme": { "authentication_scheme": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "domain_controller": {"required": False, "type": "str"},
"choices": ["present", "absent"]}, "fsso_agent_for_ntlm": {"required": False, "type": "str"},
"domain-controller": {"required": False, "type": "str"}, "fsso_guest": {"required": False, "type": "str",
"fsso-agent-for-ntlm": {"required": False, "type": "str"},
"fsso-guest": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"kerberos-keytab": {"required": False, "type": "str"}, "kerberos_keytab": {"required": False, "type": "str"},
"method": {"required": False, "type": "str", "method": {"required": False, "type": "str",
"choices": ["ntlm", "basic", "digest", "choices": ["ntlm", "basic", "digest",
"form", "negotiate", "fsso", "form", "negotiate", "fsso",
"rsso", "ssh-publickey"]}, "rsso", "ssh-publickey"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"negotiate-ntlm": {"required": False, "type": "str", "negotiate_ntlm": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"require-tfa": {"required": False, "type": "str", "require_tfa": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"ssh-ca": {"required": False, "type": "str"}, "ssh_ca": {"required": False, "type": "str"},
"user-database": {"required": False, "type": "list", "user_database": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}} }}
@ -324,15 +366,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_authentication(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_authentication(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_authentication(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_authentication_setting module: fortios_authentication_setting
short_description: Configure authentication setting in Fortinet's FortiOS and FortiGate. short_description: Configure authentication setting in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure authentication feature and setting category. user to set and modify authentication feature and setting category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,61 +41,79 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: false default: true
version_added: 2.9
authentication_setting: authentication_setting:
description: description:
- Configure authentication setting. - Configure authentication setting.
default: null default: null
type: dict
suboptions: suboptions:
active-auth-scheme: active_auth_scheme:
description: description:
- Active authentication method (scheme name). Source authentication.scheme.name. - Active authentication method (scheme name). Source authentication.scheme.name.
captive-portal: type: str
captive_portal:
description: description:
- Captive portal host name. Source firewall.address.name. - Captive portal host name. Source firewall.address.name.
captive-portal-ip: type: str
captive_portal_ip:
description: description:
- Captive portal IP address. - Captive portal IP address.
captive-portal-ip6: type: str
captive_portal_ip6:
description: description:
- Captive portal IPv6 address. - Captive portal IPv6 address.
captive-portal-port: type: str
captive_portal_port:
description: description:
- Captive portal port number (1 - 65535, default = 0). - Captive portal port number (1 - 65535, default = 0).
captive-portal-type: type: int
captive_portal_type:
description: description:
- Captive portal type. - Captive portal type.
type: str
choices: choices:
- fqdn - fqdn
- ip - ip
captive-portal6: captive_portal6:
description: description:
- IPv6 captive portal host name. Source firewall.address6.name. - IPv6 captive portal host name. Source firewall.address6.name.
sso-auth-scheme: type: str
sso_auth_scheme:
description: description:
- Single-Sign-On authentication method (scheme name). Source authentication.scheme.name. - Single-Sign-On authentication method (scheme name). Source authentication.scheme.name.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -108,6 +123,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure authentication setting. - name: Configure authentication setting.
fortios_authentication_setting: fortios_authentication_setting:
@ -115,15 +131,16 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
authentication_setting: authentication_setting:
active-auth-scheme: "<your_own_value> (source authentication.scheme.name)" active_auth_scheme: "<your_own_value> (source authentication.scheme.name)"
captive-portal: "<your_own_value> (source firewall.address.name)" captive_portal: "<your_own_value> (source firewall.address.name)"
captive-portal-ip: "<your_own_value>" captive_portal_ip: "<your_own_value>"
captive-portal-ip6: "<your_own_value>" captive_portal_ip6: "<your_own_value>"
captive-portal-port: "7" captive_portal_port: "7"
captive-portal-type: "fqdn" captive_portal_type: "fqdn"
captive-portal6: "<your_own_value> (source firewall.address6.name)" captive_portal6: "<your_own_value> (source firewall.address6.name)"
sso-auth-scheme: "<your_own_value> (source authentication.scheme.name)" sso_auth_scheme: "<your_own_value> (source authentication.scheme.name)"
''' '''
RETURN = ''' RETURN = '''
@ -186,14 +203,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -201,13 +220,13 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_authentication_setting_data(json): def filter_authentication_setting_data(json):
option_list = ['active-auth-scheme', 'captive-portal', 'captive-portal-ip', option_list = ['active_auth_scheme', 'captive_portal', 'captive_portal_ip',
'captive-portal-ip6', 'captive-portal-port', 'captive-portal-type', 'captive_portal_ip6', 'captive_portal_port', 'captive_portal_type',
'captive-portal6', 'sso-auth-scheme'] 'captive_portal6', 'sso_auth_scheme']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -217,48 +236,65 @@ def filter_authentication_setting_data(json):
return dictionary 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 authentication_setting(data, fos): def authentication_setting(data, fos):
vdom = data['vdom'] vdom = data['vdom']
authentication_setting_data = data['authentication_setting'] authentication_setting_data = data['authentication_setting']
filtered_data = filter_authentication_setting_data(authentication_setting_data) filtered_data = underscore_to_hyphen(filter_authentication_setting_data(authentication_setting_data))
return fos.set('authentication', return fos.set('authentication',
'setting', 'setting',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_authentication(data, fos): def fortios_authentication(data, fos):
login(data)
methodlist = ['authentication_setting'] if data['authentication_setting']:
for method in methodlist: resp = authentication_setting(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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},
"authentication_setting": { "authentication_setting": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"active-auth-scheme": {"required": False, "type": "str"}, "active_auth_scheme": {"required": False, "type": "str"},
"captive-portal": {"required": False, "type": "str"}, "captive_portal": {"required": False, "type": "str"},
"captive-portal-ip": {"required": False, "type": "str"}, "captive_portal_ip": {"required": False, "type": "str"},
"captive-portal-ip6": {"required": False, "type": "str"}, "captive_portal_ip6": {"required": False, "type": "str"},
"captive-portal-port": {"required": False, "type": "int"}, "captive_portal_port": {"required": False, "type": "int"},
"captive-portal-type": {"required": False, "type": "str", "captive_portal_type": {"required": False, "type": "str",
"choices": ["fqdn", "ip"]}, "choices": ["fqdn", "ip"]},
"captive-portal6": {"required": False, "type": "str"}, "captive_portal6": {"required": False, "type": "str"},
"sso-auth-scheme": {"required": False, "type": "str"} "sso_auth_scheme": {"required": False, "type": "str"}
} }
} }
@ -266,15 +302,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_authentication(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_authentication(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_authentication(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_dlp_filepattern module: fortios_dlp_filepattern
short_description: Configure file patterns used by DLP blocking in Fortinet's FortiOS and FortiGate. short_description: Configure file patterns used by DLP blocking in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dlp feature and filepattern category. user to set and modify dlp feature and filepattern category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,50 +41,65 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dlp_filepattern: dlp_filepattern:
description: description:
- Configure file patterns used by DLP blocking. - Configure file patterns used by DLP blocking.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comment: comment:
description: description:
- Optional comments. - Optional comments.
type: str
entries: entries:
description: description:
- Configure file patterns used by DLP blocking. - Configure file patterns used by DLP blocking.
type: list
suboptions: suboptions:
file-type: file_type:
description: description:
- Select a file type. - Select a file type.
type: str
choices: choices:
- 7z - 7z
- arj - arj
@ -148,9 +160,10 @@ options:
- chm - chm
- iso - iso
- crx - crx
filter-type: filter_type:
description: description:
- Filter by file name pattern or by file type. - Filter by file name pattern or by file type.
type: str
choices: choices:
- pattern - pattern
- type - type
@ -158,13 +171,16 @@ options:
description: description:
- Add a file name pattern. - Add a file name pattern.
required: true required: true
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
type: int
name: name:
description: description:
- Name of table containing the file pattern list. - Name of table containing the file pattern list.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -174,6 +190,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure file patterns used by DLP blocking. - name: Configure file patterns used by DLP blocking.
fortios_dlp_filepattern: fortios_dlp_filepattern:
@ -181,13 +198,14 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dlp_filepattern: dlp_filepattern:
state: "present"
comment: "Optional comments." comment: "Optional comments."
entries: entries:
- -
file-type: "7z" file_type: "7z"
filter-type: "pattern" filter_type: "pattern"
pattern: "<your_own_value>" pattern: "<your_own_value>"
id: "8" id: "8"
name: "default_name_9" name: "default_name_9"
@ -253,14 +271,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -268,7 +288,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dlp_filepattern_data(json): def filter_dlp_filepattern_data(json):
@ -283,52 +303,70 @@ def filter_dlp_filepattern_data(json):
return dictionary 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 dlp_filepattern(data, fos): def dlp_filepattern(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dlp_filepattern_data = data['dlp_filepattern'] dlp_filepattern_data = data['dlp_filepattern']
filtered_data = filter_dlp_filepattern_data(dlp_filepattern_data) filtered_data = underscore_to_hyphen(filter_dlp_filepattern_data(dlp_filepattern_data))
if dlp_filepattern_data['state'] == "present":
if state == "present":
return fos.set('dlp', return fos.set('dlp',
'filepattern', 'filepattern',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dlp_filepattern_data['state'] == "absent": elif state == "absent":
return fos.delete('dlp', return fos.delete('dlp',
'filepattern', 'filepattern',
mkey=filtered_data['id'], mkey=filtered_data['id'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dlp(data, fos): def fortios_dlp(data, fos):
login(data)
methodlist = ['dlp_filepattern'] if data['dlp_filepattern']:
for method in methodlist: resp = dlp_filepattern(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dlp_filepattern": { "dlp_filepattern": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
"entries": {"required": False, "type": "list", "entries": {"required": False, "type": "list",
"options": { "options": {
"file-type": {"required": False, "type": "str", "file_type": {"required": False, "type": "str",
"choices": ["7z", "arj", "cab", "choices": ["7z", "arj", "cab",
"lzh", "rar", "tar", "lzh", "rar", "tar",
"zip", "bzip", "gzip", "zip", "bzip", "gzip",
@ -349,7 +387,7 @@ def main():
"msi", "mach-o", "dmg", "msi", "mach-o", "dmg",
".net", "xar", "chm", ".net", "xar", "chm",
"iso", "crx"]}, "iso", "crx"]},
"filter-type": {"required": False, "type": "str", "filter_type": {"required": False, "type": "str",
"choices": ["pattern", "type"]}, "choices": ["pattern", "type"]},
"pattern": {"required": True, "type": "str"} "pattern": {"required": True, "type": "str"}
}}, }},
@ -362,15 +400,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dlp(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_dlp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dlp(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -30,10 +27,10 @@ module: fortios_dlp_fp_doc_source
short_description: Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints in short_description: Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints in
Fortinet's FortiOS and FortiGate. Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dlp feature and fp_doc_source category. user to set and modify dlp feature and fp_doc_source category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -45,52 +42,68 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dlp_fp_doc_source: dlp_fp_doc_source:
description: description:
- Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints. - Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
date: date:
description: description:
- Day of the month on which to scan the server (1 - 31). - Day of the month on which to scan the server (1 - 31).
file-path: type: int
file_path:
description: description:
- Path on the server to the fingerprint files (max 119 characters). - Path on the server to the fingerprint files (max 119 characters).
file-pattern: type: str
file_pattern:
description: description:
- Files matching this pattern on the server are fingerprinted. Optionally use the * and ? wildcards. - Files matching this pattern on the server are fingerprinted. Optionally use the * and ? wildcards.
keep-modified: type: str
keep_modified:
description: description:
- Enable so that when a file is changed on the server the FortiGate keeps the old fingerprint and adds a new fingerprint to the database. - Enable so that when a file is changed on the server the FortiGate keeps the old fingerprint and adds a new fingerprint to the database.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -98,32 +111,38 @@ options:
description: description:
- Name of the DLP fingerprint database. - Name of the DLP fingerprint database.
required: true required: true
type: str
password: password:
description: description:
- Password required to log into the file server. - Password required to log into the file server.
type: str
period: period:
description: description:
- Frequency for which the FortiGate checks the server for new or changed files. - Frequency for which the FortiGate checks the server for new or changed files.
type: str
choices: choices:
- none - none
- daily - daily
- weekly - weekly
- monthly - monthly
remove-deleted: remove_deleted:
description: description:
- Enable to keep the fingerprint database up to date when a file is deleted from the server. - Enable to keep the fingerprint database up to date when a file is deleted from the server.
type: str
choices: choices:
- enable - enable
- disable - disable
scan-on-creation: scan_on_creation:
description: description:
- Enable to keep the fingerprint database up to date when a file is added or changed on the server. - Enable to keep the fingerprint database up to date when a file is added or changed on the server.
type: str
choices: choices:
- enable - enable
- disable - disable
scan-subdirectories: scan_subdirectories:
description: description:
- Enable/disable scanning subdirectories to find files to create fingerprints from. - Enable/disable scanning subdirectories to find files to create fingerprints from.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -131,32 +150,40 @@ options:
description: description:
- Select a sensitivity or threat level for matches with this fingerprint database. Add sensitivities using fp-sensitivity. Source dlp - Select a sensitivity or threat level for matches with this fingerprint database. Add sensitivities using fp-sensitivity. Source dlp
.fp-sensitivity.name. .fp-sensitivity.name.
type: str
server: server:
description: description:
- IPv4 or IPv6 address of the server. - IPv4 or IPv6 address of the server.
server-type: type: str
server_type:
description: description:
- Protocol used to communicate with the file server. Currently only Samba (SMB) servers are supported. - Protocol used to communicate with the file server. Currently only Samba (SMB) servers are supported.
type: str
choices: choices:
- samba - samba
tod-hour: tod_hour:
description: description:
- Hour of the day on which to scan the server (0 - 23, default = 1). - Hour of the day on which to scan the server (0 - 23, default = 1).
tod-min: type: int
tod_min:
description: description:
- Minute of the hour on which to scan the server (0 - 59). - Minute of the hour on which to scan the server (0 - 59).
type: int
username: username:
description: description:
- User name required to log into the file server. - User name required to log into the file server.
type: str
vdom: vdom:
description: description:
- Select the VDOM that can communicate with the file server. - Select the VDOM that can communicate with the file server.
type: str
choices: choices:
- mgmt - mgmt
- current - current
weekday: weekday:
description: description:
- Day of the week on which to scan the server. - Day of the week on which to scan the server.
type: str
choices: choices:
- sunday - sunday
- monday - monday
@ -174,6 +201,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints. - name: Create a DLP fingerprint database by allowing the FortiGate to access a file server containing files from which to create fingerprints.
fortios_dlp_fp_doc_source: fortios_dlp_fp_doc_source:
@ -181,23 +209,24 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dlp_fp_doc_source: dlp_fp_doc_source:
state: "present"
date: "3" date: "3"
file-path: "<your_own_value>" file_path: "<your_own_value>"
file-pattern: "<your_own_value>" file_pattern: "<your_own_value>"
keep-modified: "enable" keep_modified: "enable"
name: "default_name_7" name: "default_name_7"
password: "<your_own_value>" password: "<your_own_value>"
period: "none" period: "none"
remove-deleted: "enable" remove_deleted: "enable"
scan-on-creation: "enable" scan_on_creation: "enable"
scan-subdirectories: "enable" scan_subdirectories: "enable"
sensitivity: "<your_own_value> (source dlp.fp-sensitivity.name)" sensitivity: "<your_own_value> (source dlp.fp-sensitivity.name)"
server: "192.168.100.40" server: "192.168.100.40"
server-type: "samba" server_type: "samba"
tod-hour: "16" tod_hour: "16"
tod-min: "17" tod_min: "17"
username: "<your_own_value>" username: "<your_own_value>"
vdom: "mgmt" vdom: "mgmt"
weekday: "sunday" weekday: "sunday"
@ -263,14 +292,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -278,15 +309,15 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dlp_fp_doc_source_data(json): def filter_dlp_fp_doc_source_data(json):
option_list = ['date', 'file-path', 'file-pattern', option_list = ['date', 'file_path', 'file_pattern',
'keep-modified', 'name', 'password', 'keep_modified', 'name', 'password',
'period', 'remove-deleted', 'scan-on-creation', 'period', 'remove_deleted', 'scan_on_creation',
'scan-subdirectories', 'sensitivity', 'server', 'scan_subdirectories', 'sensitivity', 'server',
'server-type', 'tod-hour', 'tod-min', 'server_type', 'tod_hour', 'tod_min',
'username', 'vdom', 'weekday'] 'username', 'vdom', 'weekday']
dictionary = {} dictionary = {}
@ -297,70 +328,88 @@ def filter_dlp_fp_doc_source_data(json):
return dictionary 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 dlp_fp_doc_source(data, fos): def dlp_fp_doc_source(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dlp_fp_doc_source_data = data['dlp_fp_doc_source'] dlp_fp_doc_source_data = data['dlp_fp_doc_source']
filtered_data = filter_dlp_fp_doc_source_data(dlp_fp_doc_source_data) filtered_data = underscore_to_hyphen(filter_dlp_fp_doc_source_data(dlp_fp_doc_source_data))
if dlp_fp_doc_source_data['state'] == "present":
if state == "present":
return fos.set('dlp', return fos.set('dlp',
'fp-doc-source', 'fp-doc-source',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dlp_fp_doc_source_data['state'] == "absent": elif state == "absent":
return fos.delete('dlp', return fos.delete('dlp',
'fp-doc-source', 'fp-doc-source',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dlp(data, fos): def fortios_dlp(data, fos):
login(data)
methodlist = ['dlp_fp_doc_source'] if data['dlp_fp_doc_source']:
for method in methodlist: resp = dlp_fp_doc_source(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dlp_fp_doc_source": { "dlp_fp_doc_source": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"date": {"required": False, "type": "int"}, "date": {"required": False, "type": "int"},
"file-path": {"required": False, "type": "str"}, "file_path": {"required": False, "type": "str"},
"file-pattern": {"required": False, "type": "str"}, "file_pattern": {"required": False, "type": "str"},
"keep-modified": {"required": False, "type": "str", "keep_modified": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"password": {"required": False, "type": "str"}, "password": {"required": False, "type": "str"},
"period": {"required": False, "type": "str", "period": {"required": False, "type": "str",
"choices": ["none", "daily", "weekly", "choices": ["none", "daily", "weekly",
"monthly"]}, "monthly"]},
"remove-deleted": {"required": False, "type": "str", "remove_deleted": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"scan-on-creation": {"required": False, "type": "str", "scan_on_creation": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"scan-subdirectories": {"required": False, "type": "str", "scan_subdirectories": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"sensitivity": {"required": False, "type": "str"}, "sensitivity": {"required": False, "type": "str"},
"server": {"required": False, "type": "str"}, "server": {"required": False, "type": "str"},
"server-type": {"required": False, "type": "str", "server_type": {"required": False, "type": "str",
"choices": ["samba"]}, "choices": ["samba"]},
"tod-hour": {"required": False, "type": "int"}, "tod_hour": {"required": False, "type": "int"},
"tod-min": {"required": False, "type": "int"}, "tod_min": {"required": False, "type": "int"},
"username": {"required": False, "type": "str"}, "username": {"required": False, "type": "str"},
"vdom": {"required": False, "type": "str", "vdom": {"required": False, "type": "str",
"choices": ["mgmt", "current"]}, "choices": ["mgmt", "current"]},
@ -375,15 +424,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dlp(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_dlp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dlp(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -30,10 +27,10 @@ module: fortios_dlp_fp_sensitivity
short_description: Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source in Fortinet's FortiOS and short_description: Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source in Fortinet's FortiOS and
FortiGate. FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dlp feature and fp_sensitivity category. user to set and modify dlp feature and fp_sensitivity category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -45,44 +42,57 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dlp_fp_sensitivity: dlp_fp_sensitivity:
description: description:
- Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source. - Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
name: name:
description: description:
- DLP Sensitivity Levels. - DLP Sensitivity Levels.
required: true required: true
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -92,6 +102,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source. - name: Create self-explanatory DLP sensitivity levels to be used when setting sensitivity under config fp-doc-source.
fortios_dlp_fp_sensitivity: fortios_dlp_fp_sensitivity:
@ -99,8 +110,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dlp_fp_sensitivity: dlp_fp_sensitivity:
state: "present"
name: "default_name_3" name: "default_name_3"
''' '''
@ -164,14 +176,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -179,7 +193,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dlp_fp_sensitivity_data(json): def filter_dlp_fp_sensitivity_data(json):
@ -193,48 +207,66 @@ def filter_dlp_fp_sensitivity_data(json):
return dictionary 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 dlp_fp_sensitivity(data, fos): def dlp_fp_sensitivity(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dlp_fp_sensitivity_data = data['dlp_fp_sensitivity'] dlp_fp_sensitivity_data = data['dlp_fp_sensitivity']
filtered_data = filter_dlp_fp_sensitivity_data(dlp_fp_sensitivity_data) filtered_data = underscore_to_hyphen(filter_dlp_fp_sensitivity_data(dlp_fp_sensitivity_data))
if dlp_fp_sensitivity_data['state'] == "present":
if state == "present":
return fos.set('dlp', return fos.set('dlp',
'fp-sensitivity', 'fp-sensitivity',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dlp_fp_sensitivity_data['state'] == "absent": elif state == "absent":
return fos.delete('dlp', return fos.delete('dlp',
'fp-sensitivity', 'fp-sensitivity',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dlp(data, fos): def fortios_dlp(data, fos):
login(data)
methodlist = ['dlp_fp_sensitivity'] if data['dlp_fp_sensitivity']:
for method in methodlist: resp = dlp_fp_sensitivity(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dlp_fp_sensitivity": { "dlp_fp_sensitivity": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
} }
@ -243,15 +275,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dlp(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_dlp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dlp(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_dlp_sensor module: fortios_dlp_sensor
short_description: Configure DLP sensors in Fortinet's FortiOS and FortiGate. short_description: Configure DLP sensors in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dlp feature and sensor category. user to set and modify dlp feature and sensor category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,62 +41,79 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dlp_sensor: dlp_sensor:
description: description:
- Configure DLP sensors. - Configure DLP sensors.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comment: comment:
description: description:
- Comment. - Comment.
dlp-log: type: str
dlp_log:
description: description:
- Enable/disable DLP logging. - Enable/disable DLP logging.
type: str
choices: choices:
- enable - enable
- disable - disable
extended-log: extended_log:
description: description:
- Enable/disable extended logging for data leak prevention. - Enable/disable extended logging for data leak prevention.
type: str
choices: choices:
- enable - enable
- disable - disable
filter: filter:
description: description:
- Set up DLP filters for this sensor. - Set up DLP filters for this sensor.
type: list
suboptions: suboptions:
action: action:
description: description:
- Action to take with content that this DLP sensor matches. - Action to take with content that this DLP sensor matches.
type: str
choices: choices:
- allow - allow
- log-only - log-only
@ -108,24 +122,30 @@ options:
archive: archive:
description: description:
- Enable/disable DLP archiving. - Enable/disable DLP archiving.
type: str
choices: choices:
- disable - disable
- enable - enable
company-identifier: company_identifier:
description: description:
- Enter a company identifier watermark to match. Only watermarks that your company has placed on the files are matched. - Enter a company identifier watermark to match. Only watermarks that your company has placed on the files are matched.
type: str
expiry: expiry:
description: description:
- Quarantine duration in days, hours, minutes format (dddhhmm). - Quarantine duration in days, hours, minutes format (dddhhmm).
file-size: type: str
file_size:
description: description:
- Match files this size or larger (0 - 4294967295 kbytes). - Match files this size or larger (0 - 4294967295 kbytes).
file-type: type: int
file_type:
description: description:
- Select the number of a DLP file pattern table to match. Source dlp.filepattern.id. - Select the number of a DLP file pattern table to match. Source dlp.filepattern.id.
filter-by: type: int
filter_by:
description: description:
- Select the type of content to match. - Select the type of content to match.
type: str
choices: choices:
- credit-card - credit-card
- ssn - ssn
@ -135,27 +155,33 @@ options:
- fingerprint - fingerprint
- watermark - watermark
- encrypted - encrypted
fp-sensitivity: fp_sensitivity:
description: description:
- Select a DLP file pattern sensitivity to match. - Select a DLP file pattern sensitivity to match.
type: list
suboptions: suboptions:
name: name:
description: description:
- Select a DLP sensitivity. Source dlp.fp-sensitivity.name. - Select a DLP sensitivity. Source dlp.fp-sensitivity.name.
required: true required: true
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
match-percentage: type: int
match_percentage:
description: description:
- Percentage of fingerprints in the fingerprint databases designated with the selected fp-sensitivity to match. - Percentage of fingerprints in the fingerprint databases designated with the selected fp-sensitivity to match.
type: int
name: name:
description: description:
- Filter name. - Filter name.
type: str
proto: proto:
description: description:
- Check messages or files over one or more of these protocols. - Check messages or files over one or more of these protocols.
type: str
choices: choices:
- smtp - smtp
- pop3 - pop3
@ -172,9 +198,11 @@ options:
regexp: regexp:
description: description:
- Enter a regular expression to match (max. 255 characters). - Enter a regular expression to match (max. 255 characters).
type: str
severity: severity:
description: description:
- Select the severity or threat level that matches this filter. - Select the severity or threat level that matches this filter.
type: str
choices: choices:
- info - info
- low - low
@ -184,18 +212,21 @@ options:
type: type:
description: description:
- Select whether to check the content of messages (an email message) or files (downloaded files or email attachments). - Select whether to check the content of messages (an email message) or files (downloaded files or email attachments).
type: str
choices: choices:
- file - file
- message - message
flow-based: flow_based:
description: description:
- Enable/disable flow-based DLP. - Enable/disable flow-based DLP.
type: str
choices: choices:
- enable - enable
- disable - disable
full-archive-proto: full_archive_proto:
description: description:
- Protocols to always content archive. - Protocols to always content archive.
type: str
choices: choices:
- smtp - smtp
- pop3 - pop3
@ -209,9 +240,10 @@ options:
- mm3 - mm3
- mm4 - mm4
- mm7 - mm7
nac-quar-log: nac_quar_log:
description: description:
- Enable/disable NAC quarantine logging. - Enable/disable NAC quarantine logging.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -219,15 +251,19 @@ options:
description: description:
- Name of the DLP sensor. - Name of the DLP sensor.
required: true required: true
type: str
options: options:
description: description:
- Configure DLP options. - Configure DLP options.
replacemsg-group: type: str
replacemsg_group:
description: description:
- Replacement message group used by this DLP sensor. Source system.replacemsg-group.name. - Replacement message group used by this DLP sensor. Source system.replacemsg-group.name.
summary-proto: type: str
summary_proto:
description: description:
- Protocols to always log summary. - Protocols to always log summary.
type: str
choices: choices:
- smtp - smtp
- pop3 - pop3
@ -250,6 +286,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure DLP sensors. - name: Configure DLP sensors.
fortios_dlp_sensor: fortios_dlp_sensor:
@ -257,37 +294,38 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dlp_sensor: dlp_sensor:
state: "present"
comment: "Comment." comment: "Comment."
dlp-log: "enable" dlp_log: "enable"
extended-log: "enable" extended_log: "enable"
filter: filter:
- -
action: "allow" action: "allow"
archive: "disable" archive: "disable"
company-identifier: "myId_9" company_identifier: "myId_9"
expiry: "<your_own_value>" expiry: "<your_own_value>"
file-size: "11" file_size: "11"
file-type: "12 (source dlp.filepattern.id)" file_type: "12 (source dlp.filepattern.id)"
filter-by: "credit-card" filter_by: "credit-card"
fp-sensitivity: fp_sensitivity:
- -
name: "default_name_15 (source dlp.fp-sensitivity.name)" name: "default_name_15 (source dlp.fp-sensitivity.name)"
id: "16" id: "16"
match-percentage: "17" match_percentage: "17"
name: "default_name_18" name: "default_name_18"
proto: "smtp" proto: "smtp"
regexp: "<your_own_value>" regexp: "<your_own_value>"
severity: "info" severity: "info"
type: "file" type: "file"
flow-based: "enable" flow_based: "enable"
full-archive-proto: "smtp" full_archive_proto: "smtp"
nac-quar-log: "enable" nac_quar_log: "enable"
name: "default_name_26" name: "default_name_26"
options: "<your_own_value>" options: "<your_own_value>"
replacemsg-group: "<your_own_value> (source system.replacemsg-group.name)" replacemsg_group: "<your_own_value> (source system.replacemsg-group.name)"
summary-proto: "smtp" summary_proto: "smtp"
''' '''
RETURN = ''' RETURN = '''
@ -350,14 +388,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -365,14 +405,14 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dlp_sensor_data(json): def filter_dlp_sensor_data(json):
option_list = ['comment', 'dlp-log', 'extended-log', option_list = ['comment', 'dlp_log', 'extended_log',
'filter', 'flow-based', 'full-archive-proto', 'filter', 'flow_based', 'full_archive_proto',
'nac-quar-log', 'name', 'options', 'nac_quar_log', 'name', 'options',
'replacemsg-group', 'summary-proto'] 'replacemsg_group', 'summary_proto']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -382,52 +422,70 @@ def filter_dlp_sensor_data(json):
return dictionary 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 dlp_sensor(data, fos): def dlp_sensor(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dlp_sensor_data = data['dlp_sensor'] dlp_sensor_data = data['dlp_sensor']
filtered_data = filter_dlp_sensor_data(dlp_sensor_data) filtered_data = underscore_to_hyphen(filter_dlp_sensor_data(dlp_sensor_data))
if dlp_sensor_data['state'] == "present":
if state == "present":
return fos.set('dlp', return fos.set('dlp',
'sensor', 'sensor',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dlp_sensor_data['state'] == "absent": elif state == "absent":
return fos.delete('dlp', return fos.delete('dlp',
'sensor', 'sensor',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dlp(data, fos): def fortios_dlp(data, fos):
login(data)
methodlist = ['dlp_sensor'] if data['dlp_sensor']:
for method in methodlist: resp = dlp_sensor(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dlp_sensor": { "dlp_sensor": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
"dlp-log": {"required": False, "type": "str", "dlp_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"extended-log": {"required": False, "type": "str", "extended_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"filter": {"required": False, "type": "list", "filter": {"required": False, "type": "list",
"options": { "options": {
@ -436,20 +494,20 @@ def main():
"quarantine-ip"]}, "quarantine-ip"]},
"archive": {"required": False, "type": "str", "archive": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"company-identifier": {"required": False, "type": "str"}, "company_identifier": {"required": False, "type": "str"},
"expiry": {"required": False, "type": "str"}, "expiry": {"required": False, "type": "str"},
"file-size": {"required": False, "type": "int"}, "file_size": {"required": False, "type": "int"},
"file-type": {"required": False, "type": "int"}, "file_type": {"required": False, "type": "int"},
"filter-by": {"required": False, "type": "str", "filter_by": {"required": False, "type": "str",
"choices": ["credit-card", "ssn", "regexp", "choices": ["credit-card", "ssn", "regexp",
"file-type", "file-size", "fingerprint", "file-type", "file-size", "fingerprint",
"watermark", "encrypted"]}, "watermark", "encrypted"]},
"fp-sensitivity": {"required": False, "type": "list", "fp_sensitivity": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"match-percentage": {"required": False, "type": "int"}, "match_percentage": {"required": False, "type": "int"},
"name": {"required": False, "type": "str"}, "name": {"required": False, "type": "str"},
"proto": {"required": False, "type": "str", "proto": {"required": False, "type": "str",
"choices": ["smtp", "pop3", "imap", "choices": ["smtp", "pop3", "imap",
@ -463,20 +521,19 @@ def main():
"type": {"required": False, "type": "str", "type": {"required": False, "type": "str",
"choices": ["file", "message"]} "choices": ["file", "message"]}
}}, }},
"flow-based": {"required": False, "type": "str", "flow_based": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"full-archive-proto": {"required": False, "type": "str", "full_archive_proto": {"required": False, "type": "str",
"choices": ["smtp", "pop3", "imap", "choices": ["smtp", "pop3", "imap",
"http-get", "http-post", "ftp", "http-get", "http-post", "ftp",
"nntp", "mapi", "mm1", "nntp", "mapi", "mm1",
"mm3", "mm4", "mm7"]}, "mm3", "mm4", "mm7"]},
"nac-quar-log": {"required": False, "type": "str", "nac_quar_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"options": {"required": False, "type": "str", "options": {"required": False, "type": "str"},
"choices": []}, "replacemsg_group": {"required": False, "type": "str"},
"replacemsg-group": {"required": False, "type": "str"}, "summary_proto": {"required": False, "type": "str",
"summary-proto": {"required": False, "type": "str",
"choices": ["smtp", "pop3", "imap", "choices": ["smtp", "pop3", "imap",
"http-get", "http-post", "ftp", "http-get", "http-post", "ftp",
"nntp", "mapi", "mm1", "nntp", "mapi", "mm1",
@ -488,15 +545,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dlp(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_dlp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dlp(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import (absolute_import, division, print_function) 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_dlp_settings module: fortios_dlp_settings
short_description: Designate logical storage for DLP fingerprint database in Fortinet's FortiOS and FortiGate. short_description: Designate logical storage for DLP fingerprint database in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dlp feature and settings category. user to set and modify dlp feature and settings category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,43 +41,56 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: false default: true
version_added: 2.9
dlp_settings: dlp_settings:
description: description:
- Designate logical storage for DLP fingerprint database. - Designate logical storage for DLP fingerprint database.
default: null default: null
type: dict
suboptions: suboptions:
cache-mem-percent: cache_mem_percent:
description: description:
- Maximum percentage of available memory allocated to caching (1 - 15%). - Maximum percentage of available memory allocated to caching (1 - 15%).
chunk-size: type: int
chunk_size:
description: description:
- Maximum fingerprint chunk size. **Changing will flush the entire database**. - Maximum fingerprint chunk size. **Changing will flush the entire database**.
db-mode: type: int
db_mode:
description: description:
- Behaviour when the maximum size is reached. - Behaviour when the maximum size is reached.
type: str
choices: choices:
- stop-adding - stop-adding
- remove-modified-then-oldest - remove-modified-then-oldest
@ -88,9 +98,11 @@ options:
size: size:
description: description:
- Maximum total size of files within the storage (MB). - Maximum total size of files within the storage (MB).
storage-device: type: int
storage_device:
description: description:
- Storage device name. Source system.storage.name. - Storage device name. Source system.storage.name.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -100,6 +112,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Designate logical storage for DLP fingerprint database. - name: Designate logical storage for DLP fingerprint database.
fortios_dlp_settings: fortios_dlp_settings:
@ -107,12 +120,13 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
dlp_settings: dlp_settings:
cache-mem-percent: "3" cache_mem_percent: "3"
chunk-size: "4" chunk_size: "4"
db-mode: "stop-adding" db_mode: "stop-adding"
size: "6" size: "6"
storage-device: "<your_own_value> (source system.storage.name)" storage_device: "<your_own_value> (source system.storage.name)"
''' '''
RETURN = ''' RETURN = '''
@ -175,14 +189,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -190,12 +206,12 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dlp_settings_data(json): def filter_dlp_settings_data(json):
option_list = ['cache-mem-percent', 'chunk-size', 'db-mode', option_list = ['cache_mem_percent', 'chunk_size', 'db_mode',
'size', 'storage-device'] 'size', 'storage_device']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -205,45 +221,62 @@ def filter_dlp_settings_data(json):
return dictionary 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 dlp_settings(data, fos): def dlp_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
dlp_settings_data = data['dlp_settings'] dlp_settings_data = data['dlp_settings']
filtered_data = filter_dlp_settings_data(dlp_settings_data) filtered_data = underscore_to_hyphen(filter_dlp_settings_data(dlp_settings_data))
return fos.set('dlp', return fos.set('dlp',
'settings', 'settings',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dlp(data, fos): def fortios_dlp(data, fos):
login(data)
methodlist = ['dlp_settings'] if data['dlp_settings']:
for method in methodlist: resp = dlp_settings(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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},
"dlp_settings": { "dlp_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"cache-mem-percent": {"required": False, "type": "int"}, "cache_mem_percent": {"required": False, "type": "int"},
"chunk-size": {"required": False, "type": "int"}, "chunk_size": {"required": False, "type": "int"},
"db-mode": {"required": False, "type": "str", "db_mode": {"required": False, "type": "str",
"choices": ["stop-adding", "remove-modified-then-oldest", "remove-oldest"]}, "choices": ["stop-adding", "remove-modified-then-oldest", "remove-oldest"]},
"size": {"required": False, "type": "int"}, "size": {"required": False, "type": "int"},
"storage-device": {"required": False, "type": "str"} "storage_device": {"required": False, "type": "str"}
} }
} }
@ -251,15 +284,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dlp(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_dlp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dlp(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_dnsfilter_domain_filter module: fortios_dnsfilter_domain_filter
short_description: Configure DNS domain filters in Fortinet's FortiOS and FortiGate. short_description: Configure DNS domain filters in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dnsfilter feature and domain_filter category. user to set and modify dnsfilter feature and domain_filter category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,50 +41,65 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dnsfilter_domain_filter: dnsfilter_domain_filter:
description: description:
- Configure DNS domain filters. - Configure DNS domain filters.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comment: comment:
description: description:
- Optional comments. - Optional comments.
type: str
entries: entries:
description: description:
- DNS domain filter entries. - DNS domain filter entries.
type: list
suboptions: suboptions:
action: action:
description: description:
- Action to take for domain filter matches. - Action to take for domain filter matches.
type: str
choices: choices:
- block - block
- allow - allow
@ -95,19 +107,23 @@ options:
domain: domain:
description: description:
- Domain entries to be filtered. - Domain entries to be filtered.
type: str
id: id:
description: description:
- Id. - Id.
required: true required: true
type: int
status: status:
description: description:
- Enable/disable this domain filter. - Enable/disable this domain filter.
type: str
choices: choices:
- enable - enable
- disable - disable
type: type:
description: description:
- DNS domain filter type. - DNS domain filter type.
type: str
choices: choices:
- simple - simple
- regex - regex
@ -116,9 +132,11 @@ options:
description: description:
- ID. - ID.
required: true required: true
type: int
name: name:
description: description:
- Name of table. - Name of table.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -128,6 +146,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure DNS domain filters. - name: Configure DNS domain filters.
fortios_dnsfilter_domain_filter: fortios_dnsfilter_domain_filter:
@ -135,8 +154,9 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dnsfilter_domain_filter: dnsfilter_domain_filter:
state: "present"
comment: "Optional comments." comment: "Optional comments."
entries: entries:
- -
@ -209,14 +229,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -224,7 +246,7 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dnsfilter_domain_filter_data(json): def filter_dnsfilter_domain_filter_data(json):
@ -239,48 +261,66 @@ def filter_dnsfilter_domain_filter_data(json):
return dictionary 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 dnsfilter_domain_filter(data, fos): def dnsfilter_domain_filter(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dnsfilter_domain_filter_data = data['dnsfilter_domain_filter'] dnsfilter_domain_filter_data = data['dnsfilter_domain_filter']
filtered_data = filter_dnsfilter_domain_filter_data(dnsfilter_domain_filter_data) filtered_data = underscore_to_hyphen(filter_dnsfilter_domain_filter_data(dnsfilter_domain_filter_data))
if dnsfilter_domain_filter_data['state'] == "present":
if state == "present":
return fos.set('dnsfilter', return fos.set('dnsfilter',
'domain-filter', 'domain-filter',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dnsfilter_domain_filter_data['state'] == "absent": elif state == "absent":
return fos.delete('dnsfilter', return fos.delete('dnsfilter',
'domain-filter', 'domain-filter',
mkey=filtered_data['id'], mkey=filtered_data['id'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dnsfilter(data, fos): def fortios_dnsfilter(data, fos):
login(data)
methodlist = ['dnsfilter_domain_filter'] if data['dnsfilter_domain_filter']:
for method in methodlist: resp = dnsfilter_domain_filter(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dnsfilter_domain_filter": { "dnsfilter_domain_filter": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
"entries": {"required": False, "type": "list", "entries": {"required": False, "type": "list",
"options": { "options": {
@ -302,15 +342,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dnsfilter(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_dnsfilter(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dnsfilter(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_dnsfilter_profile module: fortios_dnsfilter_profile
short_description: Configure DNS domain filter profiles in Fortinet's FortiOS and FortiGate. short_description: Configure DNS domain filter profiles in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure dnsfilter feature and profile category. user to set and modify dnsfilter feature and profile category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,106 +41,133 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
dnsfilter_profile: dnsfilter_profile:
description: description:
- Configure DNS domain filter profiles. - Configure DNS domain filter profiles.
default: null default: null
type: dict
suboptions: suboptions:
state: block_action:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
block-action:
description: description:
- Action to take for blocked domains. - Action to take for blocked domains.
type: str
choices: choices:
- block - block
- redirect - redirect
block-botnet: block_botnet:
description: description:
- Enable/disable blocking botnet C&C DNS lookups. - Enable/disable blocking botnet C&C DNS lookups.
type: str
choices: choices:
- disable - disable
- enable - enable
comment: comment:
description: description:
- Comment. - Comment.
domain-filter: type: str
domain_filter:
description: description:
- Domain filter settings. - Domain filter settings.
type: dict
suboptions: suboptions:
domain-filter-table: domain_filter_table:
description: description:
- DNS domain filter table ID. Source dnsfilter.domain-filter.id. - DNS domain filter table ID. Source dnsfilter.domain-filter.id.
external-ip-blocklist: type: int
external_ip_blocklist:
description: description:
- One or more external IP block lists. - One or more external IP block lists.
type: list
suboptions: suboptions:
name: name:
description: description:
- External domain block list name. Source system.external-resource.name. - External domain block list name. Source system.external-resource.name.
required: true required: true
ftgd-dns: type: str
ftgd_dns:
description: description:
- FortiGuard DNS Filter settings. - FortiGuard DNS Filter settings.
type: dict
suboptions: suboptions:
filters: filters:
description: description:
- FortiGuard DNS domain filters. - FortiGuard DNS domain filters.
type: list
suboptions: suboptions:
action: action:
description: description:
- Action to take for DNS requests matching the category. - Action to take for DNS requests matching the category.
type: str
choices: choices:
- block - block
- monitor - monitor
category: category:
description: description:
- Category number. - Category number.
type: int
id: id:
description: description:
- ID number. - ID number.
required: true required: true
type: int
log: log:
description: description:
- Enable/disable DNS filter logging for this DNS profile. - Enable/disable DNS filter logging for this DNS profile.
type: str
choices: choices:
- enable - enable
- disable - disable
options: options:
description: description:
- FortiGuard DNS filter options. - FortiGuard DNS filter options.
type: str
choices: choices:
- error-allow - error-allow
- ftgd-disable - ftgd-disable
log-all-domain: log_all_domain:
description: description:
- Enable/disable logging of all domains visited (detailed DNS logging). - Enable/disable logging of all domains visited (detailed DNS logging).
type: str
choices: choices:
- enable - enable
- disable - disable
@ -151,30 +175,36 @@ options:
description: description:
- Profile name. - Profile name.
required: true required: true
redirect-portal: type: str
redirect_portal:
description: description:
- IP address of the SDNS redirect portal. - IP address of the SDNS redirect portal.
safe-search: type: str
safe_search:
description: description:
- Enable/disable Google, Bing, and YouTube safe search. - Enable/disable Google, Bing, and YouTube safe search.
type: str
choices: choices:
- disable - disable
- enable - enable
sdns-domain-log: sdns_domain_log:
description: description:
- Enable/disable domain filtering and botnet domain logging. - Enable/disable domain filtering and botnet domain logging.
type: str
choices: choices:
- enable - enable
- disable - disable
sdns-ftgd-err-log: sdns_ftgd_err_log:
description: description:
- Enable/disable FortiGuard SDNS rating error logging. - Enable/disable FortiGuard SDNS rating error logging.
type: str
choices: choices:
- enable - enable
- disable - disable
youtube-restrict: youtube_restrict:
description: description:
- Set safe search for YouTube restriction level. - Set safe search for YouTube restriction level.
type: str
choices: choices:
- strict - strict
- moderate - moderate
@ -187,6 +217,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure DNS domain filter profiles. - name: Configure DNS domain filter profiles.
fortios_dnsfilter_profile: fortios_dnsfilter_profile:
@ -194,17 +225,18 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
dnsfilter_profile: dnsfilter_profile:
state: "present" block_action: "block"
block-action: "block" block_botnet: "disable"
block-botnet: "disable"
comment: "Comment." comment: "Comment."
domain-filter: domain_filter:
domain-filter-table: "7 (source dnsfilter.domain-filter.id)" domain_filter_table: "7 (source dnsfilter.domain-filter.id)"
external-ip-blocklist: external_ip_blocklist:
- -
name: "default_name_9 (source system.external-resource.name)" name: "default_name_9 (source system.external-resource.name)"
ftgd-dns: ftgd_dns:
filters: filters:
- -
action: "block" action: "block"
@ -212,13 +244,13 @@ EXAMPLES = '''
id: "14" id: "14"
log: "enable" log: "enable"
options: "error-allow" options: "error-allow"
log-all-domain: "enable" log_all_domain: "enable"
name: "default_name_18" name: "default_name_18"
redirect-portal: "<your_own_value>" redirect_portal: "<your_own_value>"
safe-search: "disable" safe_search: "disable"
sdns-domain-log: "enable" sdns_domain_log: "enable"
sdns-ftgd-err-log: "enable" sdns_ftgd_err_log: "enable"
youtube-restrict: "strict" youtube_restrict: "strict"
''' '''
RETURN = ''' RETURN = '''
@ -281,14 +313,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule 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, fos):
def login(data):
host = data['host'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -296,15 +330,15 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_dnsfilter_profile_data(json): def filter_dnsfilter_profile_data(json):
option_list = ['block-action', 'block-botnet', 'comment', option_list = ['block_action', 'block_botnet', 'comment',
'domain-filter', 'external-ip-blocklist', 'ftgd-dns', 'domain_filter', 'external_ip_blocklist', 'ftgd_dns',
'log-all-domain', 'name', 'redirect-portal', 'log_all_domain', 'name', 'redirect_portal',
'safe-search', 'sdns-domain-log', 'sdns-ftgd-err-log', 'safe_search', 'sdns_domain_log', 'sdns_ftgd_err_log',
'youtube-restrict'] 'youtube_restrict']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -314,62 +348,80 @@ def filter_dnsfilter_profile_data(json):
return dictionary 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 dnsfilter_profile(data, fos): def dnsfilter_profile(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
dnsfilter_profile_data = data['dnsfilter_profile'] dnsfilter_profile_data = data['dnsfilter_profile']
filtered_data = filter_dnsfilter_profile_data(dnsfilter_profile_data) filtered_data = underscore_to_hyphen(filter_dnsfilter_profile_data(dnsfilter_profile_data))
if dnsfilter_profile_data['state'] == "present":
if state == "present":
return fos.set('dnsfilter', return fos.set('dnsfilter',
'profile', 'profile',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif dnsfilter_profile_data['state'] == "absent": elif state == "absent":
return fos.delete('dnsfilter', return fos.delete('dnsfilter',
'profile', 'profile',
mkey=filtered_data['name'], mkey=filtered_data['name'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_dnsfilter(data, fos): def fortios_dnsfilter(data, fos):
login(data)
methodlist = ['dnsfilter_profile'] if data['dnsfilter_profile']:
for method in methodlist: resp = dnsfilter_profile(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "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"]},
"dnsfilter_profile": { "dnsfilter_profile": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "block_action": {"required": False, "type": "str",
"choices": ["present", "absent"]},
"block-action": {"required": False, "type": "str",
"choices": ["block", "redirect"]}, "choices": ["block", "redirect"]},
"block-botnet": {"required": False, "type": "str", "block_botnet": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"comment": {"required": False, "type": "str"}, "comment": {"required": False, "type": "str"},
"domain-filter": {"required": False, "type": "dict", "domain_filter": {"required": False, "type": "dict",
"options": { "options": {
"domain-filter-table": {"required": False, "type": "int"} "domain_filter_table": {"required": False, "type": "int"}
}}, }},
"external-ip-blocklist": {"required": False, "type": "list", "external_ip_blocklist": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"ftgd-dns": {"required": False, "type": "dict", "ftgd_dns": {"required": False, "type": "dict",
"options": { "options": {
"filters": {"required": False, "type": "list", "filters": {"required": False, "type": "list",
"options": { "options": {
@ -383,17 +435,17 @@ def main():
"options": {"required": False, "type": "str", "options": {"required": False, "type": "str",
"choices": ["error-allow", "ftgd-disable"]} "choices": ["error-allow", "ftgd-disable"]}
}}, }},
"log-all-domain": {"required": False, "type": "str", "log_all_domain": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"redirect-portal": {"required": False, "type": "str"}, "redirect_portal": {"required": False, "type": "str"},
"safe-search": {"required": False, "type": "str", "safe_search": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"sdns-domain-log": {"required": False, "type": "str", "sdns_domain_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"sdns-ftgd-err-log": {"required": False, "type": "str", "sdns_ftgd_err_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"youtube-restrict": {"required": False, "type": "str", "youtube_restrict": {"required": False, "type": "str",
"choices": ["strict", "moderate"]} "choices": ["strict", "moderate"]}
} }
@ -402,15 +454,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() '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_dnsfilter(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_dnsfilter(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_dnsfilter(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type __metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_endpoint_control_client module: fortios_endpoint_control_client
short_description: Configure endpoint control client lists in Fortinet's FortiOS and FortiGate. short_description: Configure endpoint control client lists in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS device by allowing the
allowing the user to configure endpoint_control feature and client category. user to set and modify endpoint_control feature and client category.
Examples includes all options and need to be adjusted to datasources before usage. Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2 Tested with FOS v6.0.5
version_added: "2.8" version_added: "2.8"
author: author:
- Miguel Angel Munoz (@mamunozgonzalez) - Miguel Angel Munoz (@mamunozgonzalez)
@ -44,59 +41,77 @@ requirements:
- fortiosapi>=0.9.8 - fortiosapi>=0.9.8
options: options:
host: host:
description: description:
- FortiOS or FortiGate ip address. - FortiOS or FortiGate IP address.
required: true type: str
required: false
username: username:
description: description:
- FortiOS or FortiGate username. - FortiOS or FortiGate username.
required: true type: str
required: false
password: password:
description: description:
- FortiOS or FortiGate password. - FortiOS or FortiGate password.
type: str
default: "" default: ""
vdom: vdom:
description: description:
- Virtual domain, among those defined previously. A vdom is a - Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and virtual instance of the FortiGate that can be configured and
used as a different unit. used as a different unit.
type: str
default: root default: root
https: https:
description: description:
- Indicates if the requests towards FortiGate must use HTTPS - Indicates if the requests towards FortiGate must use HTTPS protocol.
protocol
type: bool type: bool
default: false default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
choices:
- present
- absent
version_added: 2.9
endpoint_control_client: endpoint_control_client:
description: description:
- Configure endpoint control client lists. - Configure endpoint control client lists.
default: null default: null
type: dict
suboptions: suboptions:
state: ad_groups:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
ad-groups:
description: description:
- Endpoint client AD logon groups. - Endpoint client AD logon groups.
ftcl-uid: type: str
ftcl_uid:
description: description:
- Endpoint FortiClient UID. - Endpoint FortiClient UID.
type: str
id: id:
description: description:
- Endpoint client ID. - Endpoint client ID.
required: true required: true
type: int
info: info:
description: description:
- Endpoint client information. - Endpoint client information.
src-ip: type: str
src_ip:
description: description:
- Endpoint client IP address. - Endpoint client IP address.
src-mac: type: str
src_mac:
description: description:
- Endpoint client MAC address. - Endpoint client MAC address.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -106,6 +121,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure endpoint control client lists. - name: Configure endpoint control client lists.
fortios_endpoint_control_client: fortios_endpoint_control_client:
@ -113,14 +129,15 @@ EXAMPLES = '''
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
endpoint_control_client: endpoint_control_client:
state: "present" ad_groups: "<your_own_value>"
ad-groups: "<your_own_value>" ftcl_uid: "<your_own_value>"
ftcl-uid: "<your_own_value>"
id: "5" id: "5"
info: "<your_own_value>" info: "<your_own_value>"
src-ip: "<your_own_value>" src_ip: "<your_own_value>"
src-mac: "<your_own_value>" src_mac: "<your_own_value>"
''' '''
RETURN = ''' RETURN = '''
@ -183,14 +200,16 @@ version:
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
fos = None 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'] host = data['host']
username = data['username'] username = data['username']
password = data['password'] password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on') fos.debug('on')
if 'https' in data and not data['https']: if 'https' in data and not data['https']:
@ -198,12 +217,12 @@ def login(data):
else: else:
fos.https('on') fos.https('on')
fos.login(host, username, password) fos.login(host, username, password, verify=ssl_verify)
def filter_endpoint_control_client_data(json): def filter_endpoint_control_client_data(json):
option_list = ['ad-groups', 'ftcl-uid', 'id', option_list = ['ad_groups', 'ftcl_uid', 'id',
'info', 'src-ip', 'src-mac'] 'info', 'src_ip', 'src_mac']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -213,54 +232,72 @@ def filter_endpoint_control_client_data(json):
return dictionary return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def endpoint_control_client(data, fos): def endpoint_control_client(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
endpoint_control_client_data = data['endpoint_control_client'] endpoint_control_client_data = data['endpoint_control_client']
filtered_data = filter_endpoint_control_client_data(endpoint_control_client_data) filtered_data = underscore_to_hyphen(filter_endpoint_control_client_data(endpoint_control_client_data))
if endpoint_control_client_data['state'] == "present":
if state == "present":
return fos.set('endpoint-control', return fos.set('endpoint-control',
'client', 'client',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif endpoint_control_client_data['state'] == "absent": elif state == "absent":
return fos.delete('endpoint-control', return fos.delete('endpoint-control',
'client', 'client',
mkey=filtered_data['id'], mkey=filtered_data['id'],
vdom=vdom) vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_endpoint_control(data, fos): def fortios_endpoint_control(data, fos):
login(data)
methodlist = ['endpoint_control_client'] if data['endpoint_control_client']:
for method in methodlist: resp = endpoint_control_client(data, fos)
if data[method]:
resp = eval(method)(data, fos)
break
fos.logout() return not is_successful_status(resp), \
return not resp['status'] == "success", resp['status'] == "success", resp resp['status'] == "success", \
resp
def main(): def main():
fields = { fields = {
"host": {"required": True, "type": "str"}, "host": {"required": False, "type": "str"},
"username": {"required": True, "type": "str"}, "username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True}, "password": {"required": False, "type": "str", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": "False"}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"endpoint_control_client": { "endpoint_control_client": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "ad_groups": {"required": False, "type": "str"},
"choices": ["present", "absent"]}, "ftcl_uid": {"required": False, "type": "str"},
"ad-groups": {"required": False, "type": "str"},
"ftcl-uid": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"info": {"required": False, "type": "str"}, "info": {"required": False, "type": "str"},
"src-ip": {"required": False, "type": "str"}, "src_ip": {"required": False, "type": "str"},
"src-mac": {"required": False, "type": "str"} "src_mac": {"required": False, "type": "str"}
} }
} }
@ -268,15 +305,30 @@ def main():
module = AnsibleModule(argument_spec=fields, module = AnsibleModule(argument_spec=fields,
supports_check_mode=False) supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos legacy_mode = 'host' in module.params and module.params['host'] is not None and \
fos = FortiOSAPI() 'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_endpoint_control(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_endpoint_control(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_endpoint_control(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -3691,42 +3691,8 @@ lib/ansible/modules/network/fortimanager/fmgr_secprof_wanopt.py validate-modules
lib/ansible/modules/network/fortimanager/fmgr_secprof_web.py validate-modules:E337 lib/ansible/modules/network/fortimanager/fmgr_secprof_web.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E324 lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E324
lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E338 lib/ansible/modules/network/fortios/fortios_address.py validate-modules:E338
lib/ansible/modules/network/fortios/fortios_antivirus_heuristic.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_antivirus_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_antivirus_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_antivirus_quarantine.py validate-modules:E326 lib/ansible/modules/network/fortios/fortios_antivirus_quarantine.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_antivirus_quarantine.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_antivirus_quarantine.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_antivirus_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_antivirus_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_application_custom.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_application_group.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_application_list.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_application_list.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_application_name.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_application_name.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_application_rule_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_authentication_rule.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_authentication_rule.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_authentication_scheme.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_authentication_scheme.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_authentication_setting.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_authentication_setting.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_config.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_config.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dlp_filepattern.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_dlp_filepattern.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dlp_fp_doc_source.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_dlp_fp_doc_source.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dlp_fp_sensitivity.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dlp_sensor.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_dlp_sensor.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dlp_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_dlp_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dnsfilter_domain_filter.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_dnsfilter_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_dnsfilter_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_endpoint_control_client.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_endpoint_control_client.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_ems.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_endpoint_control_forticlient_registration_sync.py validate-modules:E336

@ -0,0 +1,151 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_antivirus_heuristic
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_antivirus_heuristic.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_antivirus_heuristic_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',
'antivirus_heuristic': {
'mode': 'pass'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_heuristic.fortios_antivirus(input_data, fos_instance)
expected_data = {
'mode': 'pass'
}
set_method_mock.assert_called_with('antivirus', 'heuristic', 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_antivirus_heuristic_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',
'antivirus_heuristic': {
'mode': 'pass'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_heuristic.fortios_antivirus(input_data, fos_instance)
expected_data = {
'mode': 'pass'
}
set_method_mock.assert_called_with('antivirus', 'heuristic', 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_antivirus_heuristic_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',
'antivirus_heuristic': {
'mode': 'pass'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_heuristic.fortios_antivirus(input_data, fos_instance)
expected_data = {
'mode': 'pass'
}
set_method_mock.assert_called_with('antivirus', 'heuristic', 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_antivirus_heuristic_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',
'antivirus_heuristic': {
'random_attribute_not_valid': 'tag',
'mode': 'pass'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_heuristic.fortios_antivirus(input_data, fos_instance)
expected_data = {
'mode': 'pass'
}
set_method_mock.assert_called_with('antivirus', 'heuristic', 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

@ -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 <https://www.gnu.org/licenses/>.
# 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_antivirus_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_antivirus_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_antivirus_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',
'antivirus_profile': {
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
expected_data = {
'analytics-bl-filetype': '3',
'analytics-db': 'disable',
'analytics-max-upload': '5',
'analytics-wl-filetype': '6',
'av-block-log': 'enable',
'av-virus-log': 'enable',
'comment': 'Comment.',
'extended-log': 'enable',
'ftgd-analytics': 'disable',
'inspection-mode': 'proxy',
'mobile-malware-db': 'disable',
'name': 'default_name_14',
'replacemsg-group': 'test_value_15',
'scan-mode': 'quick',
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_profile': {
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
expected_data = {
'analytics-bl-filetype': '3',
'analytics-db': 'disable',
'analytics-max-upload': '5',
'analytics-wl-filetype': '6',
'av-block-log': 'enable',
'av-virus-log': 'enable',
'comment': 'Comment.',
'extended-log': 'enable',
'ftgd-analytics': 'disable',
'inspection-mode': 'proxy',
'mobile-malware-db': 'disable',
'name': 'default_name_14',
'replacemsg-group': 'test_value_15',
'scan-mode': 'quick',
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_profile': {
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
delete_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_profile': {
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
delete_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_profile': {
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
expected_data = {
'analytics-bl-filetype': '3',
'analytics-db': 'disable',
'analytics-max-upload': '5',
'analytics-wl-filetype': '6',
'av-block-log': 'enable',
'av-virus-log': 'enable',
'comment': 'Comment.',
'extended-log': 'enable',
'ftgd-analytics': 'disable',
'inspection-mode': 'proxy',
'mobile-malware-db': 'disable',
'name': 'default_name_14',
'replacemsg-group': 'test_value_15',
'scan-mode': 'quick',
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_profile': {
'random_attribute_not_valid': 'tag',
'analytics_bl_filetype': '3',
'analytics_db': 'disable',
'analytics_max_upload': '5',
'analytics_wl_filetype': '6',
'av_block_log': 'enable',
'av_virus_log': 'enable',
'comment': 'Comment.',
'extended_log': 'enable',
'ftgd_analytics': 'disable',
'inspection_mode': 'proxy',
'mobile_malware_db': 'disable',
'name': 'default_name_14',
'replacemsg_group': 'test_value_15',
'scan_mode': 'quick',
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_profile.fortios_antivirus(input_data, fos_instance)
expected_data = {
'analytics-bl-filetype': '3',
'analytics-db': 'disable',
'analytics-max-upload': '5',
'analytics-wl-filetype': '6',
'av-block-log': 'enable',
'av-virus-log': 'enable',
'comment': 'Comment.',
'extended-log': 'enable',
'ftgd-analytics': 'disable',
'inspection-mode': 'proxy',
'mobile-malware-db': 'disable',
'name': 'default_name_14',
'replacemsg-group': 'test_value_15',
'scan-mode': 'quick',
}
set_method_mock.assert_called_with('antivirus', '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

@ -0,0 +1,231 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_antivirus_quarantine
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_antivirus_quarantine.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_antivirus_quarantine_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',
'antivirus_quarantine': {
'agelimit': '3',
'destination': 'NULL',
'drop_blocked': 'imap',
'drop_heuristic': 'imap',
'drop_infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine_quota': '10',
'store_blocked': 'imap',
'store_heuristic': 'imap',
'store_infected': 'imap'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_quarantine.fortios_antivirus(input_data, fos_instance)
expected_data = {
'agelimit': '3',
'destination': 'NULL',
'drop-blocked': 'imap',
'drop-heuristic': 'imap',
'drop-infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine-quota': '10',
'store-blocked': 'imap',
'store-heuristic': 'imap',
'store-infected': 'imap'
}
set_method_mock.assert_called_with('antivirus', 'quarantine', 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_antivirus_quarantine_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',
'antivirus_quarantine': {
'agelimit': '3',
'destination': 'NULL',
'drop_blocked': 'imap',
'drop_heuristic': 'imap',
'drop_infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine_quota': '10',
'store_blocked': 'imap',
'store_heuristic': 'imap',
'store_infected': 'imap'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_quarantine.fortios_antivirus(input_data, fos_instance)
expected_data = {
'agelimit': '3',
'destination': 'NULL',
'drop-blocked': 'imap',
'drop-heuristic': 'imap',
'drop-infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine-quota': '10',
'store-blocked': 'imap',
'store-heuristic': 'imap',
'store-infected': 'imap'
}
set_method_mock.assert_called_with('antivirus', 'quarantine', 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_antivirus_quarantine_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',
'antivirus_quarantine': {
'agelimit': '3',
'destination': 'NULL',
'drop_blocked': 'imap',
'drop_heuristic': 'imap',
'drop_infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine_quota': '10',
'store_blocked': 'imap',
'store_heuristic': 'imap',
'store_infected': 'imap'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_quarantine.fortios_antivirus(input_data, fos_instance)
expected_data = {
'agelimit': '3',
'destination': 'NULL',
'drop-blocked': 'imap',
'drop-heuristic': 'imap',
'drop-infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine-quota': '10',
'store-blocked': 'imap',
'store-heuristic': 'imap',
'store-infected': 'imap'
}
set_method_mock.assert_called_with('antivirus', 'quarantine', 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_antivirus_quarantine_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',
'antivirus_quarantine': {
'random_attribute_not_valid': 'tag',
'agelimit': '3',
'destination': 'NULL',
'drop_blocked': 'imap',
'drop_heuristic': 'imap',
'drop_infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine_quota': '10',
'store_blocked': 'imap',
'store_heuristic': 'imap',
'store_infected': 'imap'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_quarantine.fortios_antivirus(input_data, fos_instance)
expected_data = {
'agelimit': '3',
'destination': 'NULL',
'drop-blocked': 'imap',
'drop-heuristic': 'imap',
'drop-infected': 'imap',
'lowspace': 'drop-new',
'maxfilesize': '9',
'quarantine-quota': '10',
'store-blocked': 'imap',
'store-heuristic': 'imap',
'store-infected': 'imap'
}
set_method_mock.assert_called_with('antivirus', 'quarantine', 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

@ -0,0 +1,167 @@
# 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 <https://www.gnu.org/licenses/>.
# 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_antivirus_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_antivirus_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_antivirus_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',
'antivirus_settings': {
'default_db': 'normal',
'grayware': 'enable',
'override_timeout': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_settings.fortios_antivirus(input_data, fos_instance)
expected_data = {
'default-db': 'normal',
'grayware': 'enable',
'override-timeout': '5'
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_settings': {
'default_db': 'normal',
'grayware': 'enable',
'override_timeout': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_settings.fortios_antivirus(input_data, fos_instance)
expected_data = {
'default-db': 'normal',
'grayware': 'enable',
'override-timeout': '5'
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_settings': {
'default_db': 'normal',
'grayware': 'enable',
'override_timeout': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_settings.fortios_antivirus(input_data, fos_instance)
expected_data = {
'default-db': 'normal',
'grayware': 'enable',
'override-timeout': '5'
}
set_method_mock.assert_called_with('antivirus', '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_antivirus_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',
'antivirus_settings': {
'random_attribute_not_valid': 'tag',
'default_db': 'normal',
'grayware': 'enable',
'override_timeout': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_antivirus_settings.fortios_antivirus(input_data, fos_instance)
expected_data = {
'default-db': 'normal',
'grayware': 'enable',
'override-timeout': '5'
}
set_method_mock.assert_called_with('antivirus', '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

@ -0,0 +1,289 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_application_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_application_custom.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_application_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',
'application_custom': {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_custom': {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_custom': {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_custom': {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_custom': {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_custom': {
'random_attribute_not_valid': 'tag',
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_custom.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'comment': 'Comment.',
'id': '6',
'name': 'default_name_7',
'protocol': 'test_value_8',
'signature': 'test_value_9',
'tag': 'test_value_10',
'technology': 'test_value_11',
'vendor': 'test_value_12'
}
set_method_mock.assert_called_with('application', '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

@ -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 <https://www.gnu.org/licenses/>.
# 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_application_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_application_group.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_application_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',
'application_group': {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
expected_data = {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_group': {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
expected_data = {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_group': {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_group': {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_group': {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
expected_data = {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_group': {
'random_attribute_not_valid': 'tag', 'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_group.fortios_application(input_data, fos_instance)
expected_data = {'comment': 'Comment',
'name': 'default_name_4',
'type': 'application'
}
set_method_mock.assert_called_with('application', '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

@ -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 <https://www.gnu.org/licenses/>.
# 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_application_list
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_application_list.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_application_list_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',
'application_list': {
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
expected_data = {
'app-replacemsg': 'disable',
'comment': 'comments',
'deep-app-inspection': 'disable',
'extended-log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other-application-action': 'pass',
'other-application-log': 'disable',
'p2p-black-list': 'skype',
'replacemsg-group': 'test_value_12',
'unknown-application-action': 'pass',
'unknown-application-log': 'disable'
}
set_method_mock.assert_called_with('application', 'list', 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_application_list_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',
'application_list': {
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
expected_data = {
'app-replacemsg': 'disable',
'comment': 'comments',
'deep-app-inspection': 'disable',
'extended-log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other-application-action': 'pass',
'other-application-log': 'disable',
'p2p-black-list': 'skype',
'replacemsg-group': 'test_value_12',
'unknown-application-action': 'pass',
'unknown-application-log': 'disable'
}
set_method_mock.assert_called_with('application', 'list', 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_application_list_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',
'application_list': {
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', 'list', 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_application_list_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',
'application_list': {
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', 'list', 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_application_list_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',
'application_list': {
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
expected_data = {
'app-replacemsg': 'disable',
'comment': 'comments',
'deep-app-inspection': 'disable',
'extended-log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other-application-action': 'pass',
'other-application-log': 'disable',
'p2p-black-list': 'skype',
'replacemsg-group': 'test_value_12',
'unknown-application-action': 'pass',
'unknown-application-log': 'disable'
}
set_method_mock.assert_called_with('application', 'list', 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_application_list_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',
'application_list': {
'random_attribute_not_valid': 'tag',
'app_replacemsg': 'disable',
'comment': 'comments',
'deep_app_inspection': 'disable',
'extended_log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other_application_action': 'pass',
'other_application_log': 'disable',
'p2p_black_list': 'skype',
'replacemsg_group': 'test_value_12',
'unknown_application_action': 'pass',
'unknown_application_log': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_list.fortios_application(input_data, fos_instance)
expected_data = {
'app-replacemsg': 'disable',
'comment': 'comments',
'deep-app-inspection': 'disable',
'extended-log': 'enable',
'name': 'default_name_7',
'options': 'allow-dns',
'other-application-action': 'pass',
'other-application-log': 'disable',
'p2p-black-list': 'skype',
'replacemsg-group': 'test_value_12',
'unknown-application-action': 'pass',
'unknown-application-log': 'disable'
}
set_method_mock.assert_called_with('application', 'list', 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

@ -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 <https://www.gnu.org/licenses/>.
# 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_application_name
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_application_name.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_application_name_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',
'application_name': {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub-category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
}
set_method_mock.assert_called_with('application', 'name', 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_application_name_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',
'application_name': {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub-category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
}
set_method_mock.assert_called_with('application', 'name', 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_application_name_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',
'application_name': {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', 'name', 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_application_name_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',
'application_name': {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', 'name', 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_application_name_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',
'application_name': {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub-category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
}
set_method_mock.assert_called_with('application', 'name', 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_application_name_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',
'application_name': {
'random_attribute_not_valid': 'tag',
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub_category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_name.fortios_application(input_data, fos_instance)
expected_data = {
'behavior': 'test_value_3',
'category': '4',
'id': '5',
'name': 'default_name_6',
'parameter': 'test_value_7',
'popularity': '8',
'protocol': 'test_value_9',
'risk': '10',
'sub-category': '11',
'technology': 'test_value_12',
'vendor': 'test_value_13',
'weight': '14'
}
set_method_mock.assert_called_with('application', 'name', 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

@ -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 <https://www.gnu.org/licenses/>.
# 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_application_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_application_rule_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_application_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',
'application_rule_settings': {
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
expected_data = {
'id': '3'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_rule_settings': {
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
expected_data = {
'id': '3'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_rule_settings': {
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_rule_settings': {
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
delete_method_mock.assert_called_with('application', '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_application_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',
'application_rule_settings': {
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
expected_data = {
'id': '3'
}
set_method_mock.assert_called_with('application', '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_application_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',
'application_rule_settings': {
'random_attribute_not_valid': 'tag',
'id': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_application_rule_settings.fortios_application(input_data, fos_instance)
expected_data = {
'id': '3'
}
set_method_mock.assert_called_with('application', '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

@ -0,0 +1,279 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_authentication_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_authentication_rule.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_authentication_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',
'authentication_rule': {
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-method': 'test_value_3',
'comments': 'test_value_4',
'ip-based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso-auth-method': 'test_value_8',
'status': 'enable',
'transaction-based': 'enable',
'web-auth-cookie': 'enable'
}
set_method_mock.assert_called_with('authentication', '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_authentication_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',
'authentication_rule': {
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-method': 'test_value_3',
'comments': 'test_value_4',
'ip-based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso-auth-method': 'test_value_8',
'status': 'enable',
'transaction-based': 'enable',
'web-auth-cookie': 'enable'
}
set_method_mock.assert_called_with('authentication', '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_authentication_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',
'authentication_rule': {
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
delete_method_mock.assert_called_with('authentication', '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_authentication_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',
'authentication_rule': {
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
delete_method_mock.assert_called_with('authentication', '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_authentication_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',
'authentication_rule': {
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-method': 'test_value_3',
'comments': 'test_value_4',
'ip-based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso-auth-method': 'test_value_8',
'status': 'enable',
'transaction-based': 'enable',
'web-auth-cookie': 'enable'
}
set_method_mock.assert_called_with('authentication', '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_authentication_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',
'authentication_rule': {
'random_attribute_not_valid': 'tag',
'active_auth_method': 'test_value_3',
'comments': 'test_value_4',
'ip_based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso_auth_method': 'test_value_8',
'status': 'enable',
'transaction_based': 'enable',
'web_auth_cookie': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_rule.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-method': 'test_value_3',
'comments': 'test_value_4',
'ip-based': 'enable',
'name': 'default_name_6',
'protocol': 'http',
'sso-auth-method': 'test_value_8',
'status': 'enable',
'transaction-based': 'enable',
'web-auth-cookie': 'enable'
}
set_method_mock.assert_called_with('authentication', '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

@ -0,0 +1,289 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_authentication_scheme
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_authentication_scheme.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_authentication_scheme_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',
'authentication_scheme': {
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
expected_data = {
'domain-controller': 'test_value_3',
'fsso-agent-for-ntlm': 'test_value_4',
'fsso-guest': 'enable',
'kerberos-keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate-ntlm': 'enable',
'require-tfa': 'enable',
'ssh-ca': 'test_value_11',
}
set_method_mock.assert_called_with('authentication', 'scheme', 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_authentication_scheme_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',
'authentication_scheme': {
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
expected_data = {
'domain-controller': 'test_value_3',
'fsso-agent-for-ntlm': 'test_value_4',
'fsso-guest': 'enable',
'kerberos-keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate-ntlm': 'enable',
'require-tfa': 'enable',
'ssh-ca': 'test_value_11',
}
set_method_mock.assert_called_with('authentication', 'scheme', 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_authentication_scheme_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',
'authentication_scheme': {
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
delete_method_mock.assert_called_with('authentication', 'scheme', 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_authentication_scheme_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',
'authentication_scheme': {
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
delete_method_mock.assert_called_with('authentication', 'scheme', 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_authentication_scheme_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',
'authentication_scheme': {
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
expected_data = {
'domain-controller': 'test_value_3',
'fsso-agent-for-ntlm': 'test_value_4',
'fsso-guest': 'enable',
'kerberos-keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate-ntlm': 'enable',
'require-tfa': 'enable',
'ssh-ca': 'test_value_11',
}
set_method_mock.assert_called_with('authentication', 'scheme', 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_authentication_scheme_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',
'authentication_scheme': {
'random_attribute_not_valid': 'tag',
'domain_controller': 'test_value_3',
'fsso_agent_for_ntlm': 'test_value_4',
'fsso_guest': 'enable',
'kerberos_keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate_ntlm': 'enable',
'require_tfa': 'enable',
'ssh_ca': 'test_value_11',
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_scheme.fortios_authentication(input_data, fos_instance)
expected_data = {
'domain-controller': 'test_value_3',
'fsso-agent-for-ntlm': 'test_value_4',
'fsso-guest': 'enable',
'kerberos-keytab': 'test_value_6',
'method': 'ntlm',
'name': 'default_name_8',
'negotiate-ntlm': 'enable',
'require-tfa': 'enable',
'ssh-ca': 'test_value_11',
}
set_method_mock.assert_called_with('authentication', 'scheme', 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

@ -0,0 +1,207 @@
# 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 <https://www.gnu.org/licenses/>.
# 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_authentication_setting
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_authentication_setting.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_authentication_setting_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'authentication_setting': {
'active_auth_scheme': 'test_value_3',
'captive_portal': 'test_value_4',
'captive_portal_ip': 'test_value_5',
'captive_portal_ip6': 'test_value_6',
'captive_portal_port': '7',
'captive_portal_type': 'fqdn',
'captive_portal6': 'test_value_9',
'sso_auth_scheme': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_setting.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-scheme': 'test_value_3',
'captive-portal': 'test_value_4',
'captive-portal-ip': 'test_value_5',
'captive-portal-ip6': 'test_value_6',
'captive-portal-port': '7',
'captive-portal-type': 'fqdn',
'captive-portal6': 'test_value_9',
'sso-auth-scheme': 'test_value_10'
}
set_method_mock.assert_called_with('authentication', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_authentication_setting_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'authentication_setting': {
'active_auth_scheme': 'test_value_3',
'captive_portal': 'test_value_4',
'captive_portal_ip': 'test_value_5',
'captive_portal_ip6': 'test_value_6',
'captive_portal_port': '7',
'captive_portal_type': 'fqdn',
'captive_portal6': 'test_value_9',
'sso_auth_scheme': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_setting.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-scheme': 'test_value_3',
'captive-portal': 'test_value_4',
'captive-portal-ip': 'test_value_5',
'captive-portal-ip6': 'test_value_6',
'captive-portal-port': '7',
'captive-portal-type': 'fqdn',
'captive-portal6': 'test_value_9',
'sso-auth-scheme': 'test_value_10'
}
set_method_mock.assert_called_with('authentication', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_authentication_setting_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'authentication_setting': {
'active_auth_scheme': 'test_value_3',
'captive_portal': 'test_value_4',
'captive_portal_ip': 'test_value_5',
'captive_portal_ip6': 'test_value_6',
'captive_portal_port': '7',
'captive_portal_type': 'fqdn',
'captive_portal6': 'test_value_9',
'sso_auth_scheme': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_setting.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-scheme': 'test_value_3',
'captive-portal': 'test_value_4',
'captive-portal-ip': 'test_value_5',
'captive-portal-ip6': 'test_value_6',
'captive-portal-port': '7',
'captive-portal-type': 'fqdn',
'captive-portal6': 'test_value_9',
'sso-auth-scheme': 'test_value_10'
}
set_method_mock.assert_called_with('authentication', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_authentication_setting_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'authentication_setting': {
'random_attribute_not_valid': 'tag',
'active_auth_scheme': 'test_value_3',
'captive_portal': 'test_value_4',
'captive_portal_ip': 'test_value_5',
'captive_portal_ip6': 'test_value_6',
'captive_portal_port': '7',
'captive_portal_type': 'fqdn',
'captive_portal6': 'test_value_9',
'sso_auth_scheme': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_authentication_setting.fortios_authentication(input_data, fos_instance)
expected_data = {
'active-auth-scheme': 'test_value_3',
'captive-portal': 'test_value_4',
'captive-portal-ip': 'test_value_5',
'captive-portal-ip6': 'test_value_6',
'captive-portal-port': '7',
'captive-portal-type': 'fqdn',
'captive-portal6': 'test_value_9',
'sso-auth-scheme': 'test_value_10'
}
set_method_mock.assert_called_with('authentication', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_dlp_filepattern
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_dlp_filepattern.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dlp_filepattern_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',
'dlp_filepattern': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dlp', 'filepattern', 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_dlp_filepattern_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',
'dlp_filepattern': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dlp', 'filepattern', 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_dlp_filepattern_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',
'dlp_filepattern': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'filepattern', 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_dlp_filepattern_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',
'dlp_filepattern': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'filepattern', 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_dlp_filepattern_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',
'dlp_filepattern': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dlp', 'filepattern', 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_dlp_filepattern_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',
'dlp_filepattern': {
'random_attribute_not_valid': 'tag',
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_filepattern.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dlp', 'filepattern', 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

@ -0,0 +1,369 @@
# 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 <https://www.gnu.org/licenses/>.
# 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_dlp_fp_doc_source
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_dlp_fp_doc_source.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
expected_data = {
'date': '3',
'file-path': 'test_value_4',
'file-pattern': 'test_value_5',
'keep-modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove-deleted': 'enable',
'scan-on-creation': 'enable',
'scan-subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server-type': 'samba',
'tod-hour': '16',
'tod-min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
}
set_method_mock.assert_called_with('dlp', 'fp-doc-source', 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_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
expected_data = {
'date': '3',
'file-path': 'test_value_4',
'file-pattern': 'test_value_5',
'keep-modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove-deleted': 'enable',
'scan-on-creation': 'enable',
'scan-subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server-type': 'samba',
'tod-hour': '16',
'tod-min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
}
set_method_mock.assert_called_with('dlp', 'fp-doc-source', 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_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'fp-doc-source', 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_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'fp-doc-source', 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_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
expected_data = {
'date': '3',
'file-path': 'test_value_4',
'file-pattern': 'test_value_5',
'keep-modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove-deleted': 'enable',
'scan-on-creation': 'enable',
'scan-subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server-type': 'samba',
'tod-hour': '16',
'tod-min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
}
set_method_mock.assert_called_with('dlp', 'fp-doc-source', 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_dlp_fp_doc_source_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',
'dlp_fp_doc_source': {
'random_attribute_not_valid': 'tag',
'date': '3',
'file_path': 'test_value_4',
'file_pattern': 'test_value_5',
'keep_modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove_deleted': 'enable',
'scan_on_creation': 'enable',
'scan_subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server_type': 'samba',
'tod_hour': '16',
'tod_min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_doc_source.fortios_dlp(input_data, fos_instance)
expected_data = {
'date': '3',
'file-path': 'test_value_4',
'file-pattern': 'test_value_5',
'keep-modified': 'enable',
'name': 'default_name_7',
'password': 'test_value_8',
'period': 'none',
'remove-deleted': 'enable',
'scan-on-creation': 'enable',
'scan-subdirectories': 'enable',
'sensitivity': 'test_value_13',
'server': '192.168.100.14',
'server-type': 'samba',
'tod-hour': '16',
'tod-min': '17',
'username': 'test_value_18',
'vdom': 'mgmt',
'weekday': 'sunday'
}
set_method_mock.assert_called_with('dlp', 'fp-doc-source', 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

@ -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 <https://www.gnu.org/licenses/>.
# 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_dlp_fp_sensitivity
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_dlp_fp_sensitivity.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
expected_data = {
'name': 'default_name_3'
}
set_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
expected_data = {
'name': 'default_name_3'
}
set_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
expected_data = {
'name': 'default_name_3'
}
set_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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_dlp_fp_sensitivity_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',
'dlp_fp_sensitivity': {
'random_attribute_not_valid': 'tag',
'name': 'default_name_3'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_fp_sensitivity.fortios_dlp(input_data, fos_instance)
expected_data = {
'name': 'default_name_3'
}
set_method_mock.assert_called_with('dlp', 'fp-sensitivity', 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

@ -0,0 +1,289 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_dlp_sensor
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_dlp_sensor.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dlp_sensor_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',
'dlp_sensor': {
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'dlp-log': 'enable',
'extended-log': 'enable',
'flow-based': 'enable',
'full-archive-proto': 'smtp',
'nac-quar-log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg-group': 'test_value_11',
'summary-proto': 'smtp'
}
set_method_mock.assert_called_with('dlp', 'sensor', 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_dlp_sensor_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',
'dlp_sensor': {
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'dlp-log': 'enable',
'extended-log': 'enable',
'flow-based': 'enable',
'full-archive-proto': 'smtp',
'nac-quar-log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg-group': 'test_value_11',
'summary-proto': 'smtp'
}
set_method_mock.assert_called_with('dlp', 'sensor', 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_dlp_sensor_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',
'dlp_sensor': {
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'sensor', 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_dlp_sensor_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',
'dlp_sensor': {
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
delete_method_mock.assert_called_with('dlp', 'sensor', 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_dlp_sensor_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',
'dlp_sensor': {
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'dlp-log': 'enable',
'extended-log': 'enable',
'flow-based': 'enable',
'full-archive-proto': 'smtp',
'nac-quar-log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg-group': 'test_value_11',
'summary-proto': 'smtp'
}
set_method_mock.assert_called_with('dlp', 'sensor', 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_dlp_sensor_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',
'dlp_sensor': {
'random_attribute_not_valid': 'tag',
'comment': 'Comment.',
'dlp_log': 'enable',
'extended_log': 'enable',
'flow_based': 'enable',
'full_archive_proto': 'smtp',
'nac_quar_log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg_group': 'test_value_11',
'summary_proto': 'smtp'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_sensor.fortios_dlp(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'dlp-log': 'enable',
'extended-log': 'enable',
'flow-based': 'enable',
'full-archive-proto': 'smtp',
'nac-quar-log': 'enable',
'name': 'default_name_9',
'options': 'test_value_10,',
'replacemsg-group': 'test_value_11',
'summary-proto': 'smtp'
}
set_method_mock.assert_called_with('dlp', 'sensor', 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

@ -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 <https://www.gnu.org/licenses/>.
# 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_dlp_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_dlp_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dlp_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',
'dlp_settings': {
'cache_mem_percent': '3',
'chunk_size': '4',
'db_mode': 'stop-adding',
'size': '6',
'storage_device': 'test_value_7'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_settings.fortios_dlp(input_data, fos_instance)
expected_data = {
'cache-mem-percent': '3',
'chunk-size': '4',
'db-mode': 'stop-adding',
'size': '6',
'storage-device': 'test_value_7'
}
set_method_mock.assert_called_with('dlp', '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_dlp_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',
'dlp_settings': {
'cache_mem_percent': '3',
'chunk_size': '4',
'db_mode': 'stop-adding',
'size': '6',
'storage_device': 'test_value_7'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_settings.fortios_dlp(input_data, fos_instance)
expected_data = {
'cache-mem-percent': '3',
'chunk-size': '4',
'db-mode': 'stop-adding',
'size': '6',
'storage-device': 'test_value_7'
}
set_method_mock.assert_called_with('dlp', '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_dlp_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',
'dlp_settings': {
'cache_mem_percent': '3',
'chunk_size': '4',
'db_mode': 'stop-adding',
'size': '6',
'storage_device': 'test_value_7'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_settings.fortios_dlp(input_data, fos_instance)
expected_data = {
'cache-mem-percent': '3',
'chunk-size': '4',
'db-mode': 'stop-adding',
'size': '6',
'storage-device': 'test_value_7'
}
set_method_mock.assert_called_with('dlp', '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_dlp_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',
'dlp_settings': {
'random_attribute_not_valid': 'tag',
'cache_mem_percent': '3',
'chunk_size': '4',
'db_mode': 'stop-adding',
'size': '6',
'storage_device': 'test_value_7'
},
'vdom': 'root'}
is_error, changed, response = fortios_dlp_settings.fortios_dlp(input_data, fos_instance)
expected_data = {
'cache-mem-percent': '3',
'chunk-size': '4',
'db-mode': 'stop-adding',
'size': '6',
'storage-device': 'test_value_7'
}
set_method_mock.assert_called_with('dlp', '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

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_dnsfilter_domain_filter
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_dnsfilter_domain_filter.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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_dnsfilter_domain_filter_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',
'dnsfilter_domain_filter': {
'random_attribute_not_valid': 'tag',
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_domain_filter.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('dnsfilter', 'domain-filter', 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

@ -0,0 +1,289 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# 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_dnsfilter_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_dnsfilter_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_dnsfilter_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',
'dnsfilter_profile': {
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'block-action': 'block',
'block-botnet': 'disable',
'comment': 'Comment.',
'log-all-domain': 'enable',
'name': 'default_name_7',
'redirect-portal': 'test_value_8',
'safe-search': 'disable',
'sdns-domain-log': 'enable',
'sdns-ftgd-err-log': 'enable',
'youtube-restrict': 'strict'
}
set_method_mock.assert_called_with('dnsfilter', '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_dnsfilter_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',
'dnsfilter_profile': {
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'block-action': 'block',
'block-botnet': 'disable',
'comment': 'Comment.',
'log-all-domain': 'enable',
'name': 'default_name_7',
'redirect-portal': 'test_value_8',
'safe-search': 'disable',
'sdns-domain-log': 'enable',
'sdns-ftgd-err-log': 'enable',
'youtube-restrict': 'strict'
}
set_method_mock.assert_called_with('dnsfilter', '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_dnsfilter_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',
'dnsfilter_profile': {
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('dnsfilter', '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_dnsfilter_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',
'dnsfilter_profile': {
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('dnsfilter', '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_dnsfilter_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',
'dnsfilter_profile': {
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'block-action': 'block',
'block-botnet': 'disable',
'comment': 'Comment.',
'log-all-domain': 'enable',
'name': 'default_name_7',
'redirect-portal': 'test_value_8',
'safe-search': 'disable',
'sdns-domain-log': 'enable',
'sdns-ftgd-err-log': 'enable',
'youtube-restrict': 'strict'
}
set_method_mock.assert_called_with('dnsfilter', '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_dnsfilter_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',
'dnsfilter_profile': {
'random_attribute_not_valid': 'tag',
'block_action': 'block',
'block_botnet': 'disable',
'comment': 'Comment.',
'log_all_domain': 'enable',
'name': 'default_name_7',
'redirect_portal': 'test_value_8',
'safe_search': 'disable',
'sdns_domain_log': 'enable',
'sdns_ftgd_err_log': 'enable',
'youtube_restrict': 'strict'
},
'vdom': 'root'}
is_error, changed, response = fortios_dnsfilter_profile.fortios_dnsfilter(input_data, fos_instance)
expected_data = {
'block-action': 'block',
'block-botnet': 'disable',
'comment': 'Comment.',
'log-all-domain': 'enable',
'name': 'default_name_7',
'redirect-portal': 'test_value_8',
'safe-search': 'disable',
'sdns-domain-log': 'enable',
'sdns-ftgd-err-log': 'enable',
'youtube-restrict': 'strict'
}
set_method_mock.assert_called_with('dnsfilter', '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

@ -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 <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_endpoint_control_client
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_endpoint_control_client.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_endpoint_control_client_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'endpoint_control_client': {
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
expected_data = {
'ad-groups': 'test_value_3',
'ftcl-uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src-ip': 'test_value_7',
'src-mac': 'test_value_8'
}
set_method_mock.assert_called_with('endpoint-control', 'client', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_endpoint_control_client_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'endpoint_control_client': {
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
expected_data = {
'ad-groups': 'test_value_3',
'ftcl-uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src-ip': 'test_value_7',
'src-mac': 'test_value_8'
}
set_method_mock.assert_called_with('endpoint-control', 'client', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_endpoint_control_client_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'endpoint_control_client': {
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
delete_method_mock.assert_called_with('endpoint-control', 'client', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_endpoint_control_client_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'endpoint_control_client': {
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
delete_method_mock.assert_called_with('endpoint-control', 'client', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_endpoint_control_client_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'endpoint_control_client': {
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
expected_data = {
'ad-groups': 'test_value_3',
'ftcl-uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src-ip': 'test_value_7',
'src-mac': 'test_value_8'
}
set_method_mock.assert_called_with('endpoint-control', 'client', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_endpoint_control_client_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'endpoint_control_client': {
'random_attribute_not_valid': 'tag',
'ad_groups': 'test_value_3',
'ftcl_uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src_ip': 'test_value_7',
'src_mac': 'test_value_8'
},
'vdom': 'root'}
is_error, changed, response = fortios_endpoint_control_client.fortios_endpoint_control(input_data, fos_instance)
expected_data = {
'ad-groups': 'test_value_3',
'ftcl-uid': 'test_value_4',
'id': '5',
'info': 'test_value_6',
'src-ip': 'test_value_7',
'src-mac': 'test_value_8'
}
set_method_mock.assert_called_with('endpoint-control', 'client', 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
Loading…
Cancel
Save