FortiOS modules for 2.9 - 9 (#61320)

* FortiOS modules for 2.9 - 9

* Undo ignore file

* Remove non valid identifiers

* Leave fortios_switch_controller_lldp_profile and fortios_switch_controller_managed_switch out of this PR

* Updated fortios_switch_controller_lldp_profile and fortios_switch_controller_managed_switch
pull/61368/head
Miguel Angel Muñoz González 5 years ago committed by Nilashish Chakraborty
parent 0074fa5672
commit e62fb1e2f9

@ -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_spamfilter_profile module: fortios_spamfilter_profile
short_description: Configure AntiSpam profiles in Fortinet's FortiOS and FortiGate. short_description: Configure AntiSpam profiles in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify spamfilter feature and profile category. user to set and modify spamfilter feature and profile category.
Examples include all parameters and values 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,87 +41,110 @@ 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: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
spamfilter_profile: spamfilter_profile:
description: description:
- Configure AntiSpam profiles. - Configure AntiSpam profiles.
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.
type: str
external: external:
description: description:
- Enable/disable external Email inspection. - Enable/disable external Email inspection.
type: str
choices: choices:
- enable - enable
- disable - disable
flow-based: flow_based:
description: description:
- Enable/disable flow-based spam filtering. - Enable/disable flow-based spam filtering.
type: str
choices: choices:
- enable - enable
- disable - disable
gmail: gmail:
description: description:
- Gmail. - Gmail.
type: dict
suboptions: suboptions:
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
imap: imap:
description: description:
- IMAP. - IMAP.
type: dict
suboptions: suboptions:
action: action:
description: description:
- Action for spam email. - Action for spam email.
type: str
choices: choices:
- pass - pass
- tag - tag
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
tag-msg: tag_msg:
description: description:
- Subject text or header added to spam email. - Subject text or header added to spam email.
tag-type: type: str
tag_type:
description: description:
- Tag subject or header for spam email. - Tag subject or header for spam email.
type: list
choices: choices:
- subject - subject
- header - header
@ -132,26 +152,31 @@ options:
mapi: mapi:
description: description:
- MAPI. - MAPI.
type: dict
suboptions: suboptions:
action: action:
description: description:
- Action for spam email. - Action for spam email.
type: str
choices: choices:
- pass - pass
- discard - discard
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
msn-hotmail: msn_hotmail:
description: description:
- MSN Hotmail. - MSN Hotmail.
type: dict
suboptions: suboptions:
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -159,9 +184,11 @@ options:
description: description:
- Profile name. - Profile name.
required: true required: true
type: str
options: options:
description: description:
- Options. - Options.
type: list
choices: choices:
- bannedword - bannedword
- spambwl - spambwl
@ -177,39 +204,47 @@ options:
pop3: pop3:
description: description:
- POP3. - POP3.
type: dict
suboptions: suboptions:
action: action:
description: description:
- Action for spam email. - Action for spam email.
type: str
choices: choices:
- pass - pass
- tag - tag
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
tag-msg: tag_msg:
description: description:
- Subject text or header added to spam email. - Subject text or header added to spam email.
tag-type: type: str
tag_type:
description: description:
- Tag subject or header for spam email. - Tag subject or header for spam email.
type: list
choices: choices:
- subject - subject
- header - header
- spaminfo - spaminfo
replacemsg-group: replacemsg_group:
description: description:
- Replacement message group. Source system.replacemsg-group.name. - Replacement message group. Source system.replacemsg-group.name.
type: str
smtp: smtp:
description: description:
- SMTP. - SMTP.
type: dict
suboptions: suboptions:
action: action:
description: description:
- Action for spam email. - Action for spam email.
type: str
choices: choices:
- pass - pass
- tag - tag
@ -217,74 +252,90 @@ options:
hdrip: hdrip:
description: description:
- Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters. - Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters.
type: str
choices: choices:
- disable - disable
- enable - enable
local-override: local_override:
description: description:
- Enable/disable local filter to override SMTP remote check result. - Enable/disable local filter to override SMTP remote check result.
type: str
choices: choices:
- disable - disable
- enable - enable
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
tag-msg: tag_msg:
description: description:
- Subject text or header added to spam email. - Subject text or header added to spam email.
tag-type: type: str
tag_type:
description: description:
- Tag subject or header for spam email. - Tag subject or header for spam email.
type: list
choices: choices:
- subject - subject
- header - header
- spaminfo - spaminfo
spam-bwl-table: spam_bwl_table:
description: description:
- Anti-spam black/white list table ID. Source spamfilter.bwl.id. - Anti-spam black/white list table ID. Source spamfilter.bwl.id.
spam-bword-table: type: int
spam_bword_table:
description: description:
- Anti-spam banned word table ID. Source spamfilter.bword.id. - Anti-spam banned word table ID. Source spamfilter.bword.id.
spam-bword-threshold: type: int
spam_bword_threshold:
description: description:
- Spam banned word threshold. - Spam banned word threshold.
spam-filtering: type: int
spam_filtering:
description: description:
- Enable/disable spam filtering. - Enable/disable spam filtering.
type: str
choices: choices:
- enable - enable
- disable - disable
spam-iptrust-table: spam_iptrust_table:
description: description:
- Anti-spam IP trust table ID. Source spamfilter.iptrust.id. - Anti-spam IP trust table ID. Source spamfilter.iptrust.id.
spam-log: type: int
spam_log:
description: description:
- Enable/disable spam logging for email filtering. - Enable/disable spam logging for email filtering.
type: str
choices: choices:
- disable - disable
- enable - enable
spam-log-fortiguard-response: spam_log_fortiguard_response:
description: description:
- Enable/disable logging FortiGuard spam response. - Enable/disable logging FortiGuard spam response.
type: str
choices: choices:
- disable - disable
- enable - enable
spam-mheader-table: spam_mheader_table:
description: description:
- Anti-spam MIME header table ID. Source spamfilter.mheader.id. - Anti-spam MIME header table ID. Source spamfilter.mheader.id.
spam-rbl-table: type: int
spam_rbl_table:
description: description:
- Anti-spam DNSBL table ID. Source spamfilter.dnsbl.id. - Anti-spam DNSBL table ID. Source spamfilter.dnsbl.id.
yahoo-mail: type: int
yahoo_mail:
description: description:
- Yahoo! Mail. - Yahoo! Mail.
type: dict
suboptions: suboptions:
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -297,6 +348,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure AntiSpam profiles. - name: Configure AntiSpam profiles.
fortios_spamfilter_profile: fortios_spamfilter_profile:
@ -305,48 +357,48 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
spamfilter_profile: spamfilter_profile:
state: "present"
comment: "Comment." comment: "Comment."
external: "enable" external: "enable"
flow-based: "enable" flow_based: "enable"
gmail: gmail:
log: "enable" log: "enable"
imap: imap:
action: "pass" action: "pass"
log: "enable" log: "enable"
tag-msg: "<your_own_value>" tag_msg: "<your_own_value>"
tag-type: "subject" tag_type: "subject"
mapi: mapi:
action: "pass" action: "pass"
log: "enable" log: "enable"
msn-hotmail: msn_hotmail:
log: "enable" log: "enable"
name: "default_name_18" name: "default_name_18"
options: "bannedword" options: "bannedword"
pop3: pop3:
action: "pass" action: "pass"
log: "enable" log: "enable"
tag-msg: "<your_own_value>" tag_msg: "<your_own_value>"
tag-type: "subject" tag_type: "subject"
replacemsg-group: "<your_own_value> (source system.replacemsg-group.name)" replacemsg_group: "<your_own_value> (source system.replacemsg-group.name)"
smtp: smtp:
action: "pass" action: "pass"
hdrip: "disable" hdrip: "disable"
local-override: "disable" local_override: "disable"
log: "enable" log: "enable"
tag-msg: "<your_own_value>" tag_msg: "<your_own_value>"
tag-type: "subject" tag_type: "subject"
spam-bwl-table: "33 (source spamfilter.bwl.id)" spam_bwl_table: "33 (source spamfilter.bwl.id)"
spam-bword-table: "34 (source spamfilter.bword.id)" spam_bword_table: "34 (source spamfilter.bword.id)"
spam-bword-threshold: "35" spam_bword_threshold: "35"
spam-filtering: "enable" spam_filtering: "enable"
spam-iptrust-table: "37 (source spamfilter.iptrust.id)" spam_iptrust_table: "37 (source spamfilter.iptrust.id)"
spam-log: "disable" spam_log: "disable"
spam-log-fortiguard-response: "disable" spam_log_fortiguard_response: "disable"
spam-mheader-table: "40 (source spamfilter.mheader.id)" spam_mheader_table: "40 (source spamfilter.mheader.id)"
spam-rbl-table: "41 (source spamfilter.dnsbl.id)" spam_rbl_table: "41 (source spamfilter.dnsbl.id)"
yahoo-mail: yahoo_mail:
log: "enable" log: "enable"
''' '''
@ -410,14 +462,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']:
@ -425,18 +479,18 @@ 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_spamfilter_profile_data(json): def filter_spamfilter_profile_data(json):
option_list = ['comment', 'external', 'flow-based', option_list = ['comment', 'external', 'flow_based',
'gmail', 'imap', 'mapi', 'gmail', 'imap', 'mapi',
'msn-hotmail', 'name', 'options', 'msn_hotmail', 'name', 'options',
'pop3', 'replacemsg-group', 'smtp', 'pop3', 'replacemsg_group', 'smtp',
'spam-bwl-table', 'spam-bword-table', 'spam-bword-threshold', 'spam_bwl_table', 'spam_bword_table', 'spam_bword_threshold',
'spam-filtering', 'spam-iptrust-table', 'spam-log', 'spam_filtering', 'spam_iptrust_table', 'spam_log',
'spam-log-fortiguard-response', 'spam-mheader-table', 'spam-rbl-table', 'spam_log_fortiguard_response', 'spam_mheader_table', 'spam_rbl_table',
'yahoo-mail'] 'yahoo_mail']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -447,7 +501,7 @@ def filter_spamfilter_profile_data(json):
def flatten_multilists_attributes(data): def flatten_multilists_attributes(data):
multilist_attrs = [[u'options'], [u'imap', u'tag-type'], [u'pop3', u'tag-type'], [u'smtp', u'tag-type']] multilist_attrs = [[u'options'], [u'imap', u'tag_type'], [u'pop3', u'tag_type'], [u'smtp', u'tag_type']]
for attr in multilist_attrs: for attr in multilist_attrs:
try: try:
@ -461,50 +515,71 @@ def flatten_multilists_attributes(data):
return data return data
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def spamfilter_profile(data, fos): def spamfilter_profile(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
spamfilter_profile_data = data['spamfilter_profile'] spamfilter_profile_data = data['spamfilter_profile']
flattened_data = flatten_multilists_attributes(spamfilter_profile_data) spamfilter_profile_data = flatten_multilists_attributes(spamfilter_profile_data)
filtered_data = filter_spamfilter_profile_data(flattened_data) filtered_data = underscore_to_hyphen(filter_spamfilter_profile_data(spamfilter_profile_data))
if spamfilter_profile_data['state'] == "present":
if state == "present":
return fos.set('spamfilter', return fos.set('spamfilter',
'profile', 'profile',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif spamfilter_profile_data['state'] == "absent": elif state == "absent":
return fos.delete('spamfilter', return fos.delete('spamfilter',
'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_spamfilter(data, fos): def fortios_spamfilter(data, fos):
login(data)
if data['spamfilter_profile']: if data['spamfilter_profile']:
resp = spamfilter_profile(data, fos) resp = spamfilter_profile(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"spamfilter_profile": { "spamfilter_profile": {
"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"},
"external": {"required": False, "type": "str", "external": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"flow-based": {"required": False, "type": "str", "flow_based": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"gmail": {"required": False, "type": "dict", "gmail": {"required": False, "type": "dict",
"options": { "options": {
@ -517,8 +592,8 @@ def main():
"choices": ["pass", "tag"]}, "choices": ["pass", "tag"]},
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"tag-msg": {"required": False, "type": "str"}, "tag_msg": {"required": False, "type": "str"},
"tag-type": {"required": False, "type": "list", "tag_type": {"required": False, "type": "list",
"choices": ["subject", "header", "spaminfo"]} "choices": ["subject", "header", "spaminfo"]}
}}, }},
"mapi": {"required": False, "type": "dict", "mapi": {"required": False, "type": "dict",
@ -528,7 +603,7 @@ def main():
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]} "choices": ["enable", "disable"]}
}}, }},
"msn-hotmail": {"required": False, "type": "dict", "msn_hotmail": {"required": False, "type": "dict",
"options": { "options": {
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]} "choices": ["enable", "disable"]}
@ -545,38 +620,38 @@ def main():
"choices": ["pass", "tag"]}, "choices": ["pass", "tag"]},
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"tag-msg": {"required": False, "type": "str"}, "tag_msg": {"required": False, "type": "str"},
"tag-type": {"required": False, "type": "list", "tag_type": {"required": False, "type": "list",
"choices": ["subject", "header", "spaminfo"]} "choices": ["subject", "header", "spaminfo"]}
}}, }},
"replacemsg-group": {"required": False, "type": "str"}, "replacemsg_group": {"required": False, "type": "str"},
"smtp": {"required": False, "type": "dict", "smtp": {"required": False, "type": "dict",
"options": { "options": {
"action": {"required": False, "type": "str", "action": {"required": False, "type": "str",
"choices": ["pass", "tag", "discard"]}, "choices": ["pass", "tag", "discard"]},
"hdrip": {"required": False, "type": "str", "hdrip": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"local-override": {"required": False, "type": "str", "local_override": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"tag-msg": {"required": False, "type": "str"}, "tag_msg": {"required": False, "type": "str"},
"tag-type": {"required": False, "type": "list", "tag_type": {"required": False, "type": "list",
"choices": ["subject", "header", "spaminfo"]} "choices": ["subject", "header", "spaminfo"]}
}}, }},
"spam-bwl-table": {"required": False, "type": "int"}, "spam_bwl_table": {"required": False, "type": "int"},
"spam-bword-table": {"required": False, "type": "int"}, "spam_bword_table": {"required": False, "type": "int"},
"spam-bword-threshold": {"required": False, "type": "int"}, "spam_bword_threshold": {"required": False, "type": "int"},
"spam-filtering": {"required": False, "type": "str", "spam_filtering": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"spam-iptrust-table": {"required": False, "type": "int"}, "spam_iptrust_table": {"required": False, "type": "int"},
"spam-log": {"required": False, "type": "str", "spam_log": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"spam-log-fortiguard-response": {"required": False, "type": "str", "spam_log_fortiguard_response": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"spam-mheader-table": {"required": False, "type": "int"}, "spam_mheader_table": {"required": False, "type": "int"},
"spam-rbl-table": {"required": False, "type": "int"}, "spam_rbl_table": {"required": False, "type": "int"},
"yahoo-mail": {"required": False, "type": "dict", "yahoo_mail": {"required": False, "type": "dict",
"options": { "options": {
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["enable", "disable"]} "choices": ["enable", "disable"]}
@ -588,15 +663,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_spamfilter(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_spamfilter(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_spamfilter(module.params, fos)
fos.logout()
if not is_error: 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_ssh_filter_profile module: fortios_ssh_filter_profile
short_description: SSH filter profile in Fortinet's FortiOS and FortiGate. short_description: SSH filter profile in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify ssh_filter feature and profile category. user to set and modify ssh_filter feature and profile category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,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
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
ssh_filter_profile: ssh_filter_profile:
description: description:
- SSH filter profile. - SSH filter profile.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
block: block:
description: description:
- SSH blocking options. - SSH blocking options.
type: str
choices: choices:
- x11 - x11
- shell - shell
@ -89,15 +100,17 @@ options:
- tun-forward - tun-forward
- sftp - sftp
- unknown - unknown
default-command-log: default_command_log:
description: description:
- Enable/disable logging unmatched shell commands. - Enable/disable logging unmatched shell commands.
type: str
choices: choices:
- enable - enable
- disable - disable
log: log:
description: description:
- SSH logging options. - SSH logging options.
type: str
choices: choices:
- x11 - x11
- shell - shell
@ -110,19 +123,23 @@ options:
description: description:
- SSH filter profile name. - SSH filter profile name.
required: true required: true
shell-commands: type: str
shell_commands:
description: description:
- SSH command filter. - SSH command filter.
type: list
suboptions: suboptions:
action: action:
description: description:
- Action to take for URL filter matches. - Action to take for URL filter matches.
type: str
choices: choices:
- block - block
- allow - allow
alert: alert:
description: description:
- Enable/disable alert. - Enable/disable alert.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -130,18 +147,22 @@ options:
description: description:
- Id. - Id.
required: true required: true
type: int
log: log:
description: description:
- Enable/disable logging. - Enable/disable logging.
type: str
choices: choices:
- enable - enable
- disable - disable
pattern: pattern:
description: description:
- SSH shell command pattern. - SSH shell command pattern.
type: str
severity: severity:
description: description:
- Log severity. - Log severity.
type: str
choices: choices:
- low - low
- medium - medium
@ -150,6 +171,7 @@ options:
type: type:
description: description:
- Matching type. - Matching type.
type: str
choices: choices:
- simple - simple
- regex - regex
@ -162,6 +184,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: SSH filter profile. - name: SSH filter profile.
fortios_ssh_filter_profile: fortios_ssh_filter_profile:
@ -170,13 +193,13 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
ssh_filter_profile: ssh_filter_profile:
state: "present"
block: "x11" block: "x11"
default-command-log: "enable" default_command_log: "enable"
log: "x11" log: "x11"
name: "default_name_6" name: "default_name_6"
shell-commands: shell_commands:
- -
action: "block" action: "block"
alert: "enable" alert: "enable"
@ -247,14 +270,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']:
@ -262,12 +287,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_ssh_filter_profile_data(json): def filter_ssh_filter_profile_data(json):
option_list = ['block', 'default-command-log', 'log', option_list = ['block', 'default_command_log', 'log',
'name', 'shell-commands'] 'name', 'shell_commands']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -277,73 +302,78 @@ def filter_ssh_filter_profile_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def ssh_filter_profile(data, fos): def ssh_filter_profile(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
ssh_filter_profile_data = data['ssh_filter_profile'] ssh_filter_profile_data = data['ssh_filter_profile']
flattened_data = flatten_multilists_attributes(ssh_filter_profile_data) filtered_data = underscore_to_hyphen(filter_ssh_filter_profile_data(ssh_filter_profile_data))
filtered_data = filter_ssh_filter_profile_data(flattened_data)
if ssh_filter_profile_data['state'] == "present": if state == "present":
return fos.set('ssh-filter', return fos.set('ssh-filter',
'profile', 'profile',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif ssh_filter_profile_data['state'] == "absent": elif state == "absent":
return fos.delete('ssh-filter', return fos.delete('ssh-filter',
'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_ssh_filter(data, fos): def fortios_ssh_filter(data, fos):
login(data)
if data['ssh_filter_profile']: if data['ssh_filter_profile']:
resp = ssh_filter_profile(data, fos) resp = ssh_filter_profile(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"ssh_filter_profile": { "ssh_filter_profile": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"block": {"required": False, "type": "str", "block": {"required": False, "type": "str",
"choices": ["x11", "shell", "exec", "choices": ["x11", "shell", "exec",
"port-forward", "tun-forward", "sftp", "port-forward", "tun-forward", "sftp",
"unknown"]}, "unknown"]},
"default-command-log": {"required": False, "type": "str", "default_command_log": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"log": {"required": False, "type": "str", "log": {"required": False, "type": "str",
"choices": ["x11", "shell", "exec", "choices": ["x11", "shell", "exec",
"port-forward", "tun-forward", "sftp", "port-forward", "tun-forward", "sftp",
"unknown"]}, "unknown"]},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"shell-commands": {"required": False, "type": "list", "shell_commands": {"required": False, "type": "list",
"options": { "options": {
"action": {"required": False, "type": "str", "action": {"required": False, "type": "str",
"choices": ["block", "allow"]}, "choices": ["block", "allow"]},
@ -366,15 +396,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_ssh_filter(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_ssh_filter(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_ssh_filter(module.params, fos)
fos.logout()
if not is_error: 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_switch_controller_global module: fortios_switch_controller_global
short_description: Configure FortiSwitch global settings in Fortinet's FortiOS and FortiGate. short_description: Configure FortiSwitch global settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify switch_controller feature and global category. user to set and modify switch_controller feature and global category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,72 +41,91 @@ 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: true default: true
version_added: 2.9
switch_controller_global: switch_controller_global:
description: description:
- Configure FortiSwitch global settings. - Configure FortiSwitch global settings.
default: null default: null
type: dict
suboptions: suboptions:
allow-multiple-interfaces: allow_multiple_interfaces:
description: description:
- Enable/disable multiple FortiLink interfaces for redundant connections between a managed FortiSwitch and FortiGate. - Enable/disable multiple FortiLink interfaces for redundant connections between a managed FortiSwitch and FortiGate.
type: str
choices: choices:
- enable - enable
- disable - disable
default-virtual-switch-vlan: default_virtual_switch_vlan:
description: description:
- Default VLAN for ports when added to the virtual-switch. Source system.interface.name. - Default VLAN for ports when added to the virtual-switch. Source system.interface.name.
disable-discovery: type: str
disable_discovery:
description: description:
- Prevent this FortiSwitch from discovering. - Prevent this FortiSwitch from discovering.
type: list
suboptions: suboptions:
name: name:
description: description:
- Managed device ID. - Managed device ID.
required: true required: true
https-image-push: type: str
https_image_push:
description: description:
- Enable/disable image push to FortiSwitch using HTTPS. - Enable/disable image push to FortiSwitch using HTTPS.
type: str
choices: choices:
- enable - enable
- disable - disable
log-mac-limit-violations: log_mac_limit_violations:
description: description:
- Enable/disable logs for Learning Limit Violations. - Enable/disable logs for Learning Limit Violations.
type: str
choices: choices:
- enable - enable
- disable - disable
mac-aging-interval: mac_aging_interval:
description: description:
- Time after which an inactive MAC is aged out (10 - 1000000 sec, default = 300, 0 = disable). - Time after which an inactive MAC is aged out (10 - 1000000 sec).
mac-retention-period: type: int
mac_retention_period:
description: description:
- Time in hours after which an inactive MAC is removed from client DB. - Time in hours after which an inactive MAC is removed from client DB.
mac-violation-timer: type: int
mac_violation_timer:
description: description:
- Set timeout for Learning Limit Violations (0 = disabled). - Set timeout for Learning Limit Violations (0 = disabled).
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -119,6 +135,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure FortiSwitch global settings. - name: Configure FortiSwitch global settings.
fortios_switch_controller_global: fortios_switch_controller_global:
@ -128,16 +145,16 @@ EXAMPLES = '''
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
switch_controller_global: switch_controller_global:
allow-multiple-interfaces: "enable" allow_multiple_interfaces: "enable"
default-virtual-switch-vlan: "<your_own_value> (source system.interface.name)" default_virtual_switch_vlan: "<your_own_value> (source system.interface.name)"
disable-discovery: disable_discovery:
- -
name: "default_name_6" name: "default_name_6"
https-image-push: "enable" https_image_push: "enable"
log-mac-limit-violations: "enable" log_mac_limit_violations: "enable"
mac-aging-interval: "9" mac_aging_interval: "9"
mac-retention-period: "10" mac_retention_period: "10"
mac-violation-timer: "11" mac_violation_timer: "11"
''' '''
RETURN = ''' RETURN = '''
@ -200,14 +217,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']:
@ -215,13 +234,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_switch_controller_global_data(json): def filter_switch_controller_global_data(json):
option_list = ['allow-multiple-interfaces', 'default-virtual-switch-vlan', 'disable-discovery', option_list = ['allow_multiple_interfaces', 'default_virtual_switch_vlan', 'disable_discovery',
'https-image-push', 'log-mac-limit-violations', 'mac-aging-interval', 'https_image_push', 'log_mac_limit_violations', 'mac_aging_interval',
'mac-retention-period', 'mac-violation-timer'] 'mac_retention_period', 'mac_violation_timer']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -231,17 +250,15 @@ def filter_switch_controller_global_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
@ -249,48 +266,54 @@ def flatten_multilists_attributes(data):
def switch_controller_global(data, fos): def switch_controller_global(data, fos):
vdom = data['vdom'] vdom = data['vdom']
switch_controller_global_data = data['switch_controller_global'] switch_controller_global_data = data['switch_controller_global']
flattened_data = flatten_multilists_attributes(switch_controller_global_data) filtered_data = underscore_to_hyphen(filter_switch_controller_global_data(switch_controller_global_data))
filtered_data = filter_switch_controller_global_data(flattened_data)
return fos.set('switch-controller', return fos.set('switch-controller',
'global', 'global',
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_switch_controller(data, fos): def fortios_switch_controller(data, fos):
login(data)
if data['switch_controller_global']: if data['switch_controller_global']:
resp = switch_controller_global(data, fos) resp = switch_controller_global(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"switch_controller_global": { "switch_controller_global": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"allow-multiple-interfaces": {"required": False, "type": "str", "allow_multiple_interfaces": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"default-virtual-switch-vlan": {"required": False, "type": "str"}, "default_virtual_switch_vlan": {"required": False, "type": "str"},
"disable-discovery": {"required": False, "type": "list", "disable_discovery": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"https-image-push": {"required": False, "type": "str", "https_image_push": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"log-mac-limit-violations": {"required": False, "type": "str", "log_mac_limit_violations": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"mac-aging-interval": {"required": False, "type": "int"}, "mac_aging_interval": {"required": False, "type": "int"},
"mac-retention-period": {"required": False, "type": "int"}, "mac_retention_period": {"required": False, "type": "int"},
"mac-violation-timer": {"required": False, "type": "int"} "mac_violation_timer": {"required": False, "type": "int"}
} }
} }
@ -298,15 +321,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_switch_controller(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
fos.logout()
if not is_error: 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_switch_controller_lldp_profile module: fortios_switch_controller_lldp_profile
short_description: Configure FortiSwitch LLDP profiles in Fortinet's FortiOS and FortiGate. short_description: Configure FortiSwitch LLDP profiles in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify switch_controller feature and lldp_profile category. user to set and modify switch_controller feature and lldp_profile category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,109 +41,140 @@ 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: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
switch_controller_lldp_profile: switch_controller_lldp_profile:
description: description:
- Configure FortiSwitch LLDP profiles. - Configure FortiSwitch LLDP profiles.
default: null default: null
type: dict
suboptions: suboptions:
state: 802.1_tlvs:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
802.1-tlvs:
description: description:
- Transmitted IEEE 802.1 TLVs. - Transmitted IEEE 802.1 TLVs.
type: str
choices: choices:
- port-vlan-id - port-vlan-id
802.3-tlvs: 802.3_tlvs:
description: description:
- Transmitted IEEE 802.3 TLVs. - Transmitted IEEE 802.3 TLVs.
type: str
choices: choices:
- max-frame-size - max-frame-size
auto-isl: auto_isl:
description: description:
- Enable/disable auto inter-switch LAG. - Enable/disable auto inter-switch LAG.
type: str
choices: choices:
- disable - disable
- enable - enable
auto-isl-hello-timer: auto_isl_hello_timer:
description: description:
- Auto inter-switch LAG hello timer duration (1 - 30 sec, default = 3). - Auto inter-switch LAG hello timer duration (1 - 30 sec).
auto-isl-port-group: type: int
auto_isl_port_group:
description: description:
- Auto inter-switch LAG port group ID (0 - 9). - Auto inter-switch LAG port group ID (0 - 9).
auto-isl-receive-timeout: type: int
auto_isl_receive_timeout:
description: description:
- Auto inter-switch LAG timeout if no response is received (3 - 90 sec, default = 9). - Auto inter-switch LAG timeout if no response is received (3 - 90 sec).
custom-tlvs: type: int
custom_tlvs:
description: description:
- Configuration method to edit custom TLV entries. - Configuration method to edit custom TLV entries.
type: list
suboptions: suboptions:
information-string: information_string:
description: description:
- Organizationally defined information string (0 - 507 hexadecimal bytes). - Organizationally defined information string (0 - 507 hexadecimal bytes).
type: str
name: name:
description: description:
- TLV name (not sent). - TLV name (not sent).
required: true required: true
type: str
oui: oui:
description: description:
- Organizationally unique identifier (OUI), a 3-byte hexadecimal number, for this TLV. - Organizationally unique identifier (OUI), a 3-byte hexadecimal number, for this TLV.
type: str
subtype: subtype:
description: description:
- Organizationally defined subtype (0 - 255). - Organizationally defined subtype (0 - 255).
med-network-policy: type: int
med_network_policy:
description: description:
- Configuration method to edit Media Endpoint Discovery (MED) network policy type-length-value (TLV) categories. - Configuration method to edit Media Endpoint Discovery (MED) network policy type-length-value (TLV) categories.
type: list
suboptions: suboptions:
dscp: dscp:
description: description:
- Advertised Differentiated Services Code Point (DSCP) value, a packet header value indicating the level of service requested for - Advertised Differentiated Services Code Point (DSCP) value, a packet header value indicating the level of service requested for
traffic, such as high priority or best effort delivery. traffic, such as high priority or best effort delivery.
type: int
name: name:
description: description:
- Policy type name. - Policy type name.
required: true required: true
type: str
priority: priority:
description: description:
- Advertised Layer 2 priority (0 - 7; from lowest to highest priority). - Advertised Layer 2 priority (0 - 7; from lowest to highest priority).
type: int
status: status:
description: description:
- Enable or disable this TLV. - Enable or disable this TLV.
type: str
choices: choices:
- disable - disable
- enable - enable
vlan: vlan:
description: description:
- ID of VLAN to advertise, if configured on port (0 - 4094, 0 = priority tag). - ID of VLAN to advertise, if configured on port (0 - 4094, 0 = priority tag).
med-tlvs: type: int
med_tlvs:
description: description:
- "Transmitted LLDP-MED TLVs (type-length-value descriptions): inventory management TLV and/or network policy TLV." - "Transmitted LLDP-MED TLVs (type-length-value descriptions): inventory management TLV and/or network policy TLV."
type: str
choices: choices:
- inventory-management - inventory-management
- network-policy - network-policy
@ -154,6 +182,7 @@ options:
description: description:
- Profile name. - Profile name.
required: true required: true
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -163,6 +192,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure FortiSwitch LLDP profiles. - name: Configure FortiSwitch LLDP profiles.
fortios_switch_controller_lldp_profile: fortios_switch_controller_lldp_profile:
@ -171,28 +201,28 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
switch_controller_lldp_profile: switch_controller_lldp_profile:
state: "present" 802.1_tlvs: "port-vlan-id"
802.1-tlvs: "port-vlan-id" 802.3_tlvs: "max-frame-size"
802.3-tlvs: "max-frame-size" auto_isl: "disable"
auto-isl: "disable" auto_isl_hello_timer: "6"
auto-isl-hello-timer: "6" auto_isl_port_group: "7"
auto-isl-port-group: "7" auto_isl_receive_timeout: "8"
auto-isl-receive-timeout: "8" custom_tlvs:
custom-tlvs:
- -
information-string: "<your_own_value>" information_string: "<your_own_value>"
name: "default_name_11" name: "default_name_11"
oui: "<your_own_value>" oui: "<your_own_value>"
subtype: "13" subtype: "13"
med-network-policy: med_network_policy:
- -
dscp: "15" dscp: "15"
name: "default_name_16" name: "default_name_16"
priority: "17" priority: "17"
status: "disable" status: "disable"
vlan: "19" vlan: "19"
med-tlvs: "inventory-management" med_tlvs: "inventory-management"
name: "default_name_21" name: "default_name_21"
''' '''
@ -256,14 +286,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']:
@ -271,13 +303,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_switch_controller_lldp_profile_data(json): def filter_switch_controller_lldp_profile_data(json):
option_list = ['802.1-tlvs', '802.3-tlvs', 'auto-isl', option_list = ['802.1_tlvs', '802.3_tlvs', 'auto_isl',
'auto-isl-hello-timer', 'auto-isl-port-group', 'auto-isl-receive-timeout', 'auto_isl_hello_timer', 'auto_isl_port_group', 'auto_isl_receive_timeout',
'custom-tlvs', 'med-network-policy', 'med-tlvs', 'custom_tlvs', 'med_network_policy', 'med_tlvs',
'name'] 'name']
dictionary = {} dictionary = {}
@ -288,78 +320,83 @@ def filter_switch_controller_lldp_profile_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def switch_controller_lldp_profile(data, fos): def switch_controller_lldp_profile(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
switch_controller_lldp_profile_data = data['switch_controller_lldp_profile'] switch_controller_lldp_profile_data = data['switch_controller_lldp_profile']
flattened_data = flatten_multilists_attributes(switch_controller_lldp_profile_data) filtered_data = underscore_to_hyphen(filter_switch_controller_lldp_profile_data(switch_controller_lldp_profile_data))
filtered_data = filter_switch_controller_lldp_profile_data(flattened_data)
if switch_controller_lldp_profile_data['state'] == "present": if state == "present":
return fos.set('switch-controller', return fos.set('switch-controller',
'lldp-profile', 'lldp-profile',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif switch_controller_lldp_profile_data['state'] == "absent": elif state == "absent":
return fos.delete('switch-controller', return fos.delete('switch-controller',
'lldp-profile', 'lldp-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_switch_controller(data, fos): def fortios_switch_controller(data, fos):
login(data)
if data['switch_controller_lldp_profile']: if data['switch_controller_lldp_profile']:
resp = switch_controller_lldp_profile(data, fos) resp = switch_controller_lldp_profile(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"switch_controller_lldp_profile": { "switch_controller_lldp_profile": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "802.1_tlvs": {"required": False, "type": "str",
"choices": ["present", "absent"]},
"802.1-tlvs": {"required": False, "type": "str",
"choices": ["port-vlan-id"]}, "choices": ["port-vlan-id"]},
"802.3-tlvs": {"required": False, "type": "str", "802.3_tlvs": {"required": False, "type": "str",
"choices": ["max-frame-size"]}, "choices": ["max-frame-size"]},
"auto-isl": {"required": False, "type": "str", "auto_isl": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"auto-isl-hello-timer": {"required": False, "type": "int"}, "auto_isl_hello_timer": {"required": False, "type": "int"},
"auto-isl-port-group": {"required": False, "type": "int"}, "auto_isl_port_group": {"required": False, "type": "int"},
"auto-isl-receive-timeout": {"required": False, "type": "int"}, "auto_isl_receive_timeout": {"required": False, "type": "int"},
"custom-tlvs": {"required": False, "type": "list", "custom_tlvs": {"required": False, "type": "list",
"options": { "options": {
"information-string": {"required": False, "type": "str"}, "information_string": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"oui": {"required": False, "type": "str"}, "oui": {"required": False, "type": "str"},
"subtype": {"required": False, "type": "int"} "subtype": {"required": False, "type": "int"}
}}, }},
"med-network-policy": {"required": False, "type": "list", "med_network_policy": {"required": False, "type": "list",
"options": { "options": {
"dscp": {"required": False, "type": "int"}, "dscp": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
@ -368,7 +405,7 @@ def main():
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"vlan": {"required": False, "type": "int"} "vlan": {"required": False, "type": "int"}
}}, }},
"med-tlvs": {"required": False, "type": "str", "med_tlvs": {"required": False, "type": "str",
"choices": ["inventory-management", "network-policy"]}, "choices": ["inventory-management", "network-policy"]},
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
@ -378,15 +415,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_switch_controller(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
fos.logout()
if not is_error: 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_switch_controller_lldp_settings module: fortios_switch_controller_lldp_settings
short_description: Configure FortiSwitch LLDP settings in Fortinet's FortiOS and FortiGate. short_description: Configure FortiSwitch LLDP settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify switch_controller feature and lldp_settings category. user to set and modify switch_controller feature and lldp_settings category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,56 +41,70 @@ 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: true default: true
version_added: 2.9
switch_controller_lldp_settings: switch_controller_lldp_settings:
description: description:
- Configure FortiSwitch LLDP settings. - Configure FortiSwitch LLDP settings.
default: null default: null
type: dict
suboptions: suboptions:
fast-start-interval: fast_start_interval:
description: description:
- Frequency of LLDP PDU transmission from FortiSwitch for the first 4 packets when the link is up (2 - 5 sec, default = 2, 0 = disable - Frequency of LLDP PDU transmission from FortiSwitch for the first 4 packets when the link is up (2 - 5 sec).
fast start). type: int
management-interface: management_interface:
description: description:
- Primary management interface to be advertised in LLDP and CDP PDUs. - Primary management interface to be advertised in LLDP and CDP PDUs.
type: str
choices: choices:
- internal - internal
- mgmt - mgmt
status: status:
description: description:
- Enable/disable LLDP global settings. - Enable/disable LLDP global settings.
type: str
choices: choices:
- enable - enable
- disable - disable
tx-hold: tx_hold:
description: description:
- Number of tx-intervals before local LLDP data expires (1 - 16, default = 4). Packet TTL is tx-hold * tx-interval. - Number of tx-intervals before local LLDP data expires (1 - 16). Packet TTL is tx-hold * tx-interval.
tx-interval: type: int
tx_interval:
description: description:
- Frequency of LLDP PDU transmission from FortiSwitch (5 - 4095 sec, default = 30). Packet TTL is tx-hold * tx-interval. - Frequency of LLDP PDU transmission from FortiSwitch (5 - 4095 sec). Packet TTL is tx-hold * tx-interval.
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -103,6 +114,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure FortiSwitch LLDP settings. - name: Configure FortiSwitch LLDP settings.
fortios_switch_controller_lldp_settings: fortios_switch_controller_lldp_settings:
@ -112,11 +124,11 @@ EXAMPLES = '''
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
switch_controller_lldp_settings: switch_controller_lldp_settings:
fast-start-interval: "3" fast_start_interval: "3"
management-interface: "internal" management_interface: "internal"
status: "enable" status: "enable"
tx-hold: "6" tx_hold: "6"
tx-interval: "7" tx_interval: "7"
''' '''
RETURN = ''' RETURN = '''
@ -179,14 +191,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']:
@ -194,12 +208,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_switch_controller_lldp_settings_data(json): def filter_switch_controller_lldp_settings_data(json):
option_list = ['fast-start-interval', 'management-interface', 'status', option_list = ['fast_start_interval', 'management_interface', 'status',
'tx-hold', 'tx-interval'] 'tx_hold', 'tx_interval']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -209,17 +223,15 @@ def filter_switch_controller_lldp_settings_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
@ -227,41 +239,47 @@ def flatten_multilists_attributes(data):
def switch_controller_lldp_settings(data, fos): def switch_controller_lldp_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
switch_controller_lldp_settings_data = data['switch_controller_lldp_settings'] switch_controller_lldp_settings_data = data['switch_controller_lldp_settings']
flattened_data = flatten_multilists_attributes(switch_controller_lldp_settings_data) filtered_data = underscore_to_hyphen(filter_switch_controller_lldp_settings_data(switch_controller_lldp_settings_data))
filtered_data = filter_switch_controller_lldp_settings_data(flattened_data)
return fos.set('switch-controller', return fos.set('switch-controller',
'lldp-settings', 'lldp-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_switch_controller(data, fos): def fortios_switch_controller(data, fos):
login(data)
if data['switch_controller_lldp_settings']: if data['switch_controller_lldp_settings']:
resp = switch_controller_lldp_settings(data, fos) resp = switch_controller_lldp_settings(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"switch_controller_lldp_settings": { "switch_controller_lldp_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"fast-start-interval": {"required": False, "type": "int"}, "fast_start_interval": {"required": False, "type": "int"},
"management-interface": {"required": False, "type": "str", "management_interface": {"required": False, "type": "str",
"choices": ["internal", "mgmt"]}, "choices": ["internal", "mgmt"]},
"status": {"required": False, "type": "str", "status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"tx-hold": {"required": False, "type": "int"}, "tx_hold": {"required": False, "type": "int"},
"tx-interval": {"required": False, "type": "int"} "tx_interval": {"required": False, "type": "int"}
} }
} }
@ -269,15 +287,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_switch_controller(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -26,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_switch_controller_mac_sync_settings module: fortios_switch_controller_mac_sync_settings
short_description: Configure global MAC synchronization settings in Fortinet's FortiOS and FortiGate. short_description: Configure global MAC synchronization settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify switch_controller feature and mac_sync_settings category. user to set and modify switch_controller feature and mac_sync_settings category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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)
@ -41,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: true default: true
version_added: 2.9
switch_controller_mac_sync_settings: switch_controller_mac_sync_settings:
description: description:
- Configure global MAC synchronization settings. - Configure global MAC synchronization settings.
default: null default: null
type: dict
suboptions: suboptions:
mac-sync-interval: mac_sync_interval:
description: description:
- Time interval between MAC synchronizations (30 - 1800 sec, default = 60, 0 = disable MAC synchronization). - Time interval between MAC synchronizations (30 - 1800 sec).
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -81,6 +92,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure global MAC synchronization settings. - name: Configure global MAC synchronization settings.
fortios_switch_controller_mac_sync_settings: fortios_switch_controller_mac_sync_settings:
@ -90,7 +102,7 @@ EXAMPLES = '''
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
switch_controller_mac_sync_settings: switch_controller_mac_sync_settings:
mac-sync-interval: "3" mac_sync_interval: "3"
''' '''
RETURN = ''' RETURN = '''
@ -153,14 +165,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']:
@ -168,11 +182,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_switch_controller_mac_sync_settings_data(json): def filter_switch_controller_mac_sync_settings_data(json):
option_list = ['mac-sync-interval'] option_list = ['mac_sync_interval']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -182,17 +196,15 @@ def filter_switch_controller_mac_sync_settings_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
@ -200,35 +212,41 @@ def flatten_multilists_attributes(data):
def switch_controller_mac_sync_settings(data, fos): def switch_controller_mac_sync_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
switch_controller_mac_sync_settings_data = data['switch_controller_mac_sync_settings'] switch_controller_mac_sync_settings_data = data['switch_controller_mac_sync_settings']
flattened_data = flatten_multilists_attributes(switch_controller_mac_sync_settings_data) filtered_data = underscore_to_hyphen(filter_switch_controller_mac_sync_settings_data(switch_controller_mac_sync_settings_data))
filtered_data = filter_switch_controller_mac_sync_settings_data(flattened_data)
return fos.set('switch-controller', return fos.set('switch-controller',
'mac-sync-settings', 'mac-sync-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_switch_controller(data, fos): def fortios_switch_controller(data, fos):
login(data)
if data['switch_controller_mac_sync_settings']: if data['switch_controller_mac_sync_settings']:
resp = switch_controller_mac_sync_settings(data, fos) resp = switch_controller_mac_sync_settings(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"switch_controller_mac_sync_settings": { "switch_controller_mac_sync_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"mac-sync-interval": {"required": False, "type": "int"} "mac_sync_interval": {"required": False, "type": "int"}
} }
} }
@ -236,15 +254,31 @@ def main():
module = AnsibleModule(argument_spec=fields, 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_switch_controller(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
fos.logout()
if not is_error: 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_switch_controller_network_monitor_settings module: fortios_switch_controller_network_monitor_settings
short_description: Configure network monitor settings in Fortinet's FortiOS and FortiGate. short_description: Configure network monitor settings in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify switch_controller feature and network_monitor_settings category. user to set and modify switch_controller feature and network_monitor_settings category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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: true default: true
version_added: 2.9
switch_controller_network_monitor_settings: switch_controller_network_monitor_settings:
description: description:
- Configure network monitor settings. - Configure network monitor settings.
default: null default: null
type: dict
suboptions: suboptions:
network-monitoring: network_monitoring:
description: description:
- Enable/disable passive gathering of information by FortiSwitch units concerning other network devices. - Enable/disable passive gathering of information by FortiSwitch units concerning other network devices.
type: str
choices: choices:
- enable - enable
- disable - disable
@ -87,6 +95,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure network monitor settings. - name: Configure network monitor settings.
fortios_switch_controller_network_monitor_settings: fortios_switch_controller_network_monitor_settings:
@ -96,7 +105,7 @@ EXAMPLES = '''
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
switch_controller_network_monitor_settings: switch_controller_network_monitor_settings:
network-monitoring: "enable" network_monitoring: "enable"
''' '''
RETURN = ''' RETURN = '''
@ -159,14 +168,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']:
@ -174,11 +185,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_switch_controller_network_monitor_settings_data(json): def filter_switch_controller_network_monitor_settings_data(json):
option_list = ['network-monitoring'] option_list = ['network_monitoring']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -188,17 +199,15 @@ def filter_switch_controller_network_monitor_settings_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
@ -206,35 +215,41 @@ def flatten_multilists_attributes(data):
def switch_controller_network_monitor_settings(data, fos): def switch_controller_network_monitor_settings(data, fos):
vdom = data['vdom'] vdom = data['vdom']
switch_controller_network_monitor_settings_data = data['switch_controller_network_monitor_settings'] switch_controller_network_monitor_settings_data = data['switch_controller_network_monitor_settings']
flattened_data = flatten_multilists_attributes(switch_controller_network_monitor_settings_data) filtered_data = underscore_to_hyphen(filter_switch_controller_network_monitor_settings_data(switch_controller_network_monitor_settings_data))
filtered_data = filter_switch_controller_network_monitor_settings_data(flattened_data)
return fos.set('switch-controller', return fos.set('switch-controller',
'network-monitor-settings', 'network-monitor-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_switch_controller(data, fos): def fortios_switch_controller(data, fos):
login(data)
if data['switch_controller_network_monitor_settings']: if data['switch_controller_network_monitor_settings']:
resp = switch_controller_network_monitor_settings(data, fos) resp = switch_controller_network_monitor_settings(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"switch_controller_network_monitor_settings": { "switch_controller_network_monitor_settings": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"network-monitoring": {"required": False, "type": "str", "network_monitoring": {"required": False, "type": "str",
"choices": ["enable", "disable"]} "choices": ["enable", "disable"]}
} }
@ -243,15 +258,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_switch_controller(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_switch_controller(module.params, fos)
fos.logout()
if not is_error: 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_system_accprofile module: fortios_system_accprofile
short_description: Configure access profiles for system administrators in Fortinet's FortiOS and FortiGate. short_description: Configure access profiles for system administrators in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify system feature and accprofile category. user to set and modify system feature and accprofile category.
Examples include all parameters and values 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,52 +41,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
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool type: bool
default: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
system_accprofile: system_accprofile:
description: description:
- Configure access profiles for system administrators. - Configure access profiles for system administrators.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
admintimeout: admintimeout:
description: description:
- Administrator timeout for this access profile (0 - 480 min, default = 10, 0 means never timeout). - Administrator timeout for this access profile (0 - 480 min).
admintimeout-override: type: int
admintimeout_override:
description: description:
- Enable/disable overriding the global administrator idle timeout. - Enable/disable overriding the global administrator idle timeout.
type: str
choices: choices:
- enable - enable
- disable - disable
authgrp: authgrp:
description: description:
- Administrator access to Users and Devices. - Administrator access to Users and Devices.
type: str
choices: choices:
- none - none
- read - read
@ -97,9 +110,11 @@ options:
comments: comments:
description: description:
- Comment. - Comment.
type: str
ftviewgrp: ftviewgrp:
description: description:
- FortiView. - FortiView.
type: str
choices: choices:
- none - none
- read - read
@ -107,18 +122,21 @@ options:
fwgrp: fwgrp:
description: description:
- Administrator access to the Firewall configuration. - Administrator access to the Firewall configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
- custom - custom
fwgrp-permission: fwgrp_permission:
description: description:
- Custom firewall permission. - Custom firewall permission.
type: dict
suboptions: suboptions:
address: address:
description: description:
- Address Configuration. - Address Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -126,6 +144,7 @@ options:
policy: policy:
description: description:
- Policy Configuration. - Policy Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -133,6 +152,7 @@ options:
schedule: schedule:
description: description:
- Schedule Configuration. - Schedule Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -140,6 +160,7 @@ options:
service: service:
description: description:
- Service Configuration. - Service Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -147,39 +168,45 @@ options:
loggrp: loggrp:
description: description:
- Administrator access to Logging and Reporting including viewing log messages. - Administrator access to Logging and Reporting including viewing log messages.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
- custom - custom
loggrp-permission: loggrp_permission:
description: description:
- Custom Log & Report permission. - Custom Log & Report permission.
type: dict
suboptions: suboptions:
config: config:
description: description:
- Log & Report configuration. - Log & Report configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
data-access: data_access:
description: description:
- Log & Report Data Access. - Log & Report Data Access.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
report-access: report_access:
description: description:
- Log & Report Report Access. - Log & Report Report Access.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
threat-weight: threat_weight:
description: description:
- Log & Report Threat Weight. - Log & Report Threat Weight.
type: str
choices: choices:
- none - none
- read - read
@ -188,35 +215,41 @@ options:
description: description:
- Profile name. - Profile name.
required: true required: true
type: str
netgrp: netgrp:
description: description:
- Network Configuration. - Network Configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
- custom - custom
netgrp-permission: netgrp_permission:
description: description:
- Custom network permission. - Custom network permission.
type: dict
suboptions: suboptions:
cfg: cfg:
description: description:
- Network Configuration. - Network Configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
packet-capture: packet_capture:
description: description:
- Packet Capture Configuration. - Packet Capture Configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
route-cfg: route_cfg:
description: description:
- Router Configuration. - Router Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -224,12 +257,14 @@ options:
scope: scope:
description: description:
- "Scope of admin access: global or specific VDOM(s)." - "Scope of admin access: global or specific VDOM(s)."
type: str
choices: choices:
- vdom - vdom
- global - global
secfabgrp: secfabgrp:
description: description:
- Security Fabric. - Security Fabric.
type: str
choices: choices:
- none - none
- read - read
@ -237,18 +272,21 @@ options:
sysgrp: sysgrp:
description: description:
- System Configuration. - System Configuration.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
- custom - custom
sysgrp-permission: sysgrp_permission:
description: description:
- Custom system permission. - Custom system permission.
type: dict
suboptions: suboptions:
admin: admin:
description: description:
- Administrator Users. - Administrator Users.
type: str
choices: choices:
- none - none
- read - read
@ -256,6 +294,7 @@ options:
cfg: cfg:
description: description:
- System Configuration. - System Configuration.
type: str
choices: choices:
- none - none
- read - read
@ -263,6 +302,7 @@ options:
mnt: mnt:
description: description:
- Maintenance. - Maintenance.
type: str
choices: choices:
- none - none
- read - read
@ -270,6 +310,7 @@ options:
upd: upd:
description: description:
- FortiGuard Updates. - FortiGuard Updates.
type: str
choices: choices:
- none - none
- read - read
@ -277,32 +318,37 @@ options:
utmgrp: utmgrp:
description: description:
- Administrator access to Security Profiles. - Administrator access to Security Profiles.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
- custom - custom
utmgrp-permission: utmgrp_permission:
description: description:
- Custom Security Profile permissions. - Custom Security Profile permissions.
type: dict
suboptions: suboptions:
antivirus: antivirus:
description: description:
- Antivirus profiles and settings. - Antivirus profiles and settings.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
application-control: application_control:
description: description:
- Application Control profiles and settings. - Application Control profiles and settings.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
data-loss-prevention: data_loss_prevention:
description: description:
- DLP profiles and settings. - DLP profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -310,13 +356,15 @@ options:
dnsfilter: dnsfilter:
description: description:
- DNS Filter profiles and settings. - DNS Filter profiles and settings.
type: str
choices: choices:
- none - none
- read - read
- read-write - read-write
endpoint-control: endpoint_control:
description: description:
- FortiClient Profiles. - FortiClient Profiles.
type: str
choices: choices:
- none - none
- read - read
@ -324,6 +372,7 @@ options:
icap: icap:
description: description:
- ICAP profiles and settings. - ICAP profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -331,6 +380,7 @@ options:
ips: ips:
description: description:
- IPS profiles and settings. - IPS profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -338,6 +388,7 @@ options:
spamfilter: spamfilter:
description: description:
- AntiSpam filter and settings. - AntiSpam filter and settings.
type: str
choices: choices:
- none - none
- read - read
@ -345,6 +396,7 @@ options:
voip: voip:
description: description:
- VoIP profiles and settings. - VoIP profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -352,6 +404,7 @@ options:
waf: waf:
description: description:
- Web Application Firewall profiles and settings. - Web Application Firewall profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -359,6 +412,7 @@ options:
webfilter: webfilter:
description: description:
- Web Filter profiles and settings. - Web Filter profiles and settings.
type: str
choices: choices:
- none - none
- read - read
@ -366,6 +420,7 @@ options:
vpngrp: vpngrp:
description: description:
- Administrator access to IPsec, SSL, PPTP, and L2TP VPN. - Administrator access to IPsec, SSL, PPTP, and L2TP VPN.
type: str
choices: choices:
- none - none
- read - read
@ -373,6 +428,7 @@ options:
wanoptgrp: wanoptgrp:
description: description:
- Administrator access to WAN Opt & Cache. - Administrator access to WAN Opt & Cache.
type: str
choices: choices:
- none - none
- read - read
@ -380,6 +436,7 @@ options:
wifi: wifi:
description: description:
- Administrator access to the WiFi controller and Switch controller. - Administrator access to the WiFi controller and Switch controller.
type: str
choices: choices:
- none - none
- read - read
@ -393,6 +450,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure access profiles for system administrators. - name: Configure access profiles for system administrators.
fortios_system_accprofile: fortios_system_accprofile:
@ -401,46 +459,46 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
system_accprofile: system_accprofile:
state: "present"
admintimeout: "3" admintimeout: "3"
admintimeout-override: "enable" admintimeout_override: "enable"
authgrp: "none" authgrp: "none"
comments: "<your_own_value>" comments: "<your_own_value>"
ftviewgrp: "none" ftviewgrp: "none"
fwgrp: "none" fwgrp: "none"
fwgrp-permission: fwgrp_permission:
address: "none" address: "none"
policy: "none" policy: "none"
schedule: "none" schedule: "none"
service: "none" service: "none"
loggrp: "none" loggrp: "none"
loggrp-permission: loggrp_permission:
config: "none" config: "none"
data-access: "none" data_access: "none"
report-access: "none" report_access: "none"
threat-weight: "none" threat_weight: "none"
name: "default_name_20" name: "default_name_20"
netgrp: "none" netgrp: "none"
netgrp-permission: netgrp_permission:
cfg: "none" cfg: "none"
packet-capture: "none" packet_capture: "none"
route-cfg: "none" route_cfg: "none"
scope: "vdom" scope: "vdom"
secfabgrp: "none" secfabgrp: "none"
sysgrp: "none" sysgrp: "none"
sysgrp-permission: sysgrp_permission:
admin: "none" admin: "none"
cfg: "none" cfg: "none"
mnt: "none" mnt: "none"
upd: "none" upd: "none"
utmgrp: "none" utmgrp: "none"
utmgrp-permission: utmgrp_permission:
antivirus: "none" antivirus: "none"
application-control: "none" application_control: "none"
data-loss-prevention: "none" data_loss_prevention: "none"
dnsfilter: "none" dnsfilter: "none"
endpoint-control: "none" endpoint_control: "none"
icap: "none" icap: "none"
ips: "none" ips: "none"
spamfilter: "none" spamfilter: "none"
@ -512,14 +570,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']:
@ -527,16 +587,16 @@ 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_system_accprofile_data(json): def filter_system_accprofile_data(json):
option_list = ['admintimeout', 'admintimeout-override', 'authgrp', option_list = ['admintimeout', 'admintimeout_override', 'authgrp',
'comments', 'ftviewgrp', 'fwgrp', 'comments', 'ftviewgrp', 'fwgrp',
'fwgrp-permission', 'loggrp', 'loggrp-permission', 'fwgrp_permission', 'loggrp', 'loggrp_permission',
'name', 'netgrp', 'netgrp-permission', 'name', 'netgrp', 'netgrp_permission',
'scope', 'secfabgrp', 'sysgrp', 'scope', 'secfabgrp', 'sysgrp',
'sysgrp-permission', 'utmgrp', 'utmgrp-permission', 'sysgrp_permission', 'utmgrp', 'utmgrp_permission',
'vpngrp', 'wanoptgrp', 'wifi'] 'vpngrp', 'wanoptgrp', 'wifi']
dictionary = {} dictionary = {}
@ -547,63 +607,68 @@ def filter_system_accprofile_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def system_accprofile(data, fos): def system_accprofile(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
system_accprofile_data = data['system_accprofile'] system_accprofile_data = data['system_accprofile']
flattened_data = flatten_multilists_attributes(system_accprofile_data) filtered_data = underscore_to_hyphen(filter_system_accprofile_data(system_accprofile_data))
filtered_data = filter_system_accprofile_data(flattened_data)
if system_accprofile_data['state'] == "present": if state == "present":
return fos.set('system', return fos.set('system',
'accprofile', 'accprofile',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif system_accprofile_data['state'] == "absent": elif state == "absent":
return fos.delete('system', return fos.delete('system',
'accprofile', 'accprofile',
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_system(data, fos): def fortios_system(data, fos):
login(data)
if data['system_accprofile']: if data['system_accprofile']:
resp = system_accprofile(data, fos) resp = system_accprofile(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"system_accprofile": { "system_accprofile": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"admintimeout": {"required": False, "type": "int"}, "admintimeout": {"required": False, "type": "int"},
"admintimeout-override": {"required": False, "type": "str", "admintimeout_override": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"authgrp": {"required": False, "type": "str", "authgrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
@ -613,7 +678,7 @@ def main():
"fwgrp": {"required": False, "type": "str", "fwgrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write", "choices": ["none", "read", "read-write",
"custom"]}, "custom"]},
"fwgrp-permission": {"required": False, "type": "dict", "fwgrp_permission": {"required": False, "type": "dict",
"options": { "options": {
"address": {"required": False, "type": "str", "address": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
@ -627,28 +692,28 @@ def main():
"loggrp": {"required": False, "type": "str", "loggrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write", "choices": ["none", "read", "read-write",
"custom"]}, "custom"]},
"loggrp-permission": {"required": False, "type": "dict", "loggrp_permission": {"required": False, "type": "dict",
"options": { "options": {
"config": {"required": False, "type": "str", "config": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"data-access": {"required": False, "type": "str", "data_access": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"report-access": {"required": False, "type": "str", "report_access": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"threat-weight": {"required": False, "type": "str", "threat_weight": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]} "choices": ["none", "read", "read-write"]}
}}, }},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"netgrp": {"required": False, "type": "str", "netgrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write", "choices": ["none", "read", "read-write",
"custom"]}, "custom"]},
"netgrp-permission": {"required": False, "type": "dict", "netgrp_permission": {"required": False, "type": "dict",
"options": { "options": {
"cfg": {"required": False, "type": "str", "cfg": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"packet-capture": {"required": False, "type": "str", "packet_capture": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"route-cfg": {"required": False, "type": "str", "route_cfg": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]} "choices": ["none", "read", "read-write"]}
}}, }},
"scope": {"required": False, "type": "str", "scope": {"required": False, "type": "str",
@ -658,7 +723,7 @@ def main():
"sysgrp": {"required": False, "type": "str", "sysgrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write", "choices": ["none", "read", "read-write",
"custom"]}, "custom"]},
"sysgrp-permission": {"required": False, "type": "dict", "sysgrp_permission": {"required": False, "type": "dict",
"options": { "options": {
"admin": {"required": False, "type": "str", "admin": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
@ -672,17 +737,17 @@ def main():
"utmgrp": {"required": False, "type": "str", "utmgrp": {"required": False, "type": "str",
"choices": ["none", "read", "read-write", "choices": ["none", "read", "read-write",
"custom"]}, "custom"]},
"utmgrp-permission": {"required": False, "type": "dict", "utmgrp_permission": {"required": False, "type": "dict",
"options": { "options": {
"antivirus": {"required": False, "type": "str", "antivirus": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"application-control": {"required": False, "type": "str", "application_control": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"data-loss-prevention": {"required": False, "type": "str", "data_loss_prevention": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"dnsfilter": {"required": False, "type": "str", "dnsfilter": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"endpoint-control": {"required": False, "type": "str", "endpoint_control": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
"icap": {"required": False, "type": "str", "icap": {"required": False, "type": "str",
"choices": ["none", "read", "read-write"]}, "choices": ["none", "read", "read-write"]},
@ -710,15 +775,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

File diff suppressed because it is too large Load Diff

@ -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_system_api_user module: fortios_system_api_user
short_description: Configure API users in Fortinet's FortiOS and FortiGate. short_description: Configure API users in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify system feature and api_user category. user to set and modify system feature and api_user category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,96 +41,124 @@ 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: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
system_api_user: system_api_user:
description: description:
- Configure API users. - Configure API users.
default: null default: null
type: dict
suboptions: suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
accprofile: accprofile:
description: description:
- Admin user access profile. Source system.accprofile.name. - Admin user access profile. Source system.accprofile.name.
api-key: type: str
api_key:
description: description:
- Admin user password. - Admin user password.
type: str
comments: comments:
description: description:
- Comment. - Comment.
cors-allow-origin: type: str
cors_allow_origin:
description: description:
- Value for Access-Control-Allow-Origin on API responses. Avoid using '*' if possible. - Value for Access-Control-Allow-Origin on API responses. Avoid using '*' if possible.
type: str
name: name:
description: description:
- User name. - User name.
required: true required: true
peer-auth: type: str
peer_auth:
description: description:
- Enable/disable peer authentication. - Enable/disable peer authentication.
type: str
choices: choices:
- enable - enable
- disable - disable
peer-group: peer_group:
description: description:
- Peer group name. - Peer group name.
type: str
schedule: schedule:
description: description:
- Schedule name. - Schedule name.
type: str
trusthost: trusthost:
description: description:
- Trusthost. - Trusthost.
type: list
suboptions: suboptions:
id: id:
description: description:
- Table ID. - Table ID.
required: true required: true
ipv4-trusthost: type: int
ipv4_trusthost:
description: description:
- IPv4 trusted host address. - IPv4 trusted host address.
ipv6-trusthost: type: str
ipv6_trusthost:
description: description:
- IPv6 trusted host address. - IPv6 trusted host address.
type: str
type: type:
description: description:
- Trusthost type. - Trusthost type.
type: str
choices: choices:
- ipv4-trusthost - ipv4-trusthost
- ipv6-trusthost - ipv6-trusthost
vdom: vdom:
description: description:
- Virtual domains. - Virtual domains.
type: list
suboptions: suboptions:
name: name:
description: description:
- Virtual domain name. Source system.vdom.name. - Virtual domain name. Source system.vdom.name.
required: true required: true
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -143,6 +168,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure API users. - name: Configure API users.
fortios_system_api_user: fortios_system_api_user:
@ -151,21 +177,21 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
system_api_user: system_api_user:
state: "present"
accprofile: "<your_own_value> (source system.accprofile.name)" accprofile: "<your_own_value> (source system.accprofile.name)"
api-key: "<your_own_value>" api_key: "<your_own_value>"
comments: "<your_own_value>" comments: "<your_own_value>"
cors-allow-origin: "<your_own_value>" cors_allow_origin: "<your_own_value>"
name: "default_name_7" name: "default_name_7"
peer-auth: "enable" peer_auth: "enable"
peer-group: "<your_own_value>" peer_group: "<your_own_value>"
schedule: "<your_own_value>" schedule: "<your_own_value>"
trusthost: trusthost:
- -
id: "12" id: "12"
ipv4-trusthost: "<your_own_value>" ipv4_trusthost: "<your_own_value>"
ipv6-trusthost: "<your_own_value>" ipv6_trusthost: "<your_own_value>"
type: "ipv4-trusthost" type: "ipv4-trusthost"
vdom: vdom:
- -
@ -232,14 +258,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']:
@ -247,13 +275,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_system_api_user_data(json): def filter_system_api_user_data(json):
option_list = ['accprofile', 'api-key', 'comments', option_list = ['accprofile', 'api_key', 'comments',
'cors-allow-origin', 'name', 'peer-auth', 'cors_allow_origin', 'name', 'peer_auth',
'peer-group', 'schedule', 'trusthost', 'peer_group', 'schedule', 'trusthost',
'vdom'] 'vdom']
dictionary = {} dictionary = {}
@ -264,75 +292,80 @@ def filter_system_api_user_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def system_api_user(data, fos): def system_api_user(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
system_api_user_data = data['system_api_user'] system_api_user_data = data['system_api_user']
flattened_data = flatten_multilists_attributes(system_api_user_data) filtered_data = underscore_to_hyphen(filter_system_api_user_data(system_api_user_data))
filtered_data = filter_system_api_user_data(flattened_data)
if system_api_user_data['state'] == "present": if state == "present":
return fos.set('system', return fos.set('system',
'api-user', 'api-user',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif system_api_user_data['state'] == "absent": elif state == "absent":
return fos.delete('system', return fos.delete('system',
'api-user', 'api-user',
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_system(data, fos): def fortios_system(data, fos):
login(data)
if data['system_api_user']: if data['system_api_user']:
resp = system_api_user(data, fos) resp = system_api_user(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"system_api_user": { "system_api_user": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"accprofile": {"required": False, "type": "str"}, "accprofile": {"required": False, "type": "str"},
"api-key": {"required": False, "type": "str"}, "api_key": {"required": False, "type": "str"},
"comments": {"required": False, "type": "str"}, "comments": {"required": False, "type": "str"},
"cors-allow-origin": {"required": False, "type": "str"}, "cors_allow_origin": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"peer-auth": {"required": False, "type": "str", "peer_auth": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"peer-group": {"required": False, "type": "str"}, "peer_group": {"required": False, "type": "str"},
"schedule": {"required": False, "type": "str"}, "schedule": {"required": False, "type": "str"},
"trusthost": {"required": False, "type": "list", "trusthost": {"required": False, "type": "list",
"options": { "options": {
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"ipv4-trusthost": {"required": False, "type": "str"}, "ipv4_trusthost": {"required": False, "type": "str"},
"ipv6-trusthost": {"required": False, "type": "str"}, "ipv6_trusthost": {"required": False, "type": "str"},
"type": {"required": False, "type": "str", "type": {"required": False, "type": "str",
"choices": ["ipv4-trusthost", "ipv6-trusthost"]} "choices": ["ipv4-trusthost", "ipv6-trusthost"]}
}}, }},
@ -347,15 +380,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: 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_system_central_management module: fortios_system_central_management
short_description: Configure central management. short_description: Configure central management 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 (FOS) device by allowing the
allowing the user to configure system feature and central_management category. user to set and modify system feature and central_management 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,76 @@ 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
system_central_management: system_central_management:
description: description:
- Configure central management. - Configure central management.
default: null default: null
type: dict
suboptions: suboptions:
allow-monitor: allow_monitor:
description: description:
- Enable/disable allowing the central management server to remotely monitor this FortiGate - Enable/disable allowing the central management server to remotely monitor this FortiGate
type: str
choices: choices:
- enable - enable
- disable - disable
allow-push-configuration: allow_push_configuration:
description: description:
- Enable/disable allowing the central management server to push configuration changes to this FortiGate. - Enable/disable allowing the central management server to push configuration changes to this FortiGate.
type: str
choices: choices:
- enable - enable
- disable - disable
allow-push-firmware: allow_push_firmware:
description: description:
- Enable/disable allowing the central management server to push firmware updates to this FortiGate. - Enable/disable allowing the central management server to push firmware updates to this FortiGate.
type: str
choices: choices:
- enable - enable
- disable - disable
allow-remote-firmware-upgrade: allow_remote_firmware_upgrade:
description: description:
- Enable/disable remotely upgrading the firmware on this FortiGate from the central management server. - Enable/disable remotely upgrading the firmware on this FortiGate from the central management server.
type: str
choices: choices:
- enable - enable
- disable - disable
enc-algorithm: enc_algorithm:
description: description:
- Encryption strength for communications between the FortiGate and central management. - Encryption strength for communications between the FortiGate and central management.
type: str
choices: choices:
- default - default
- high - high
@ -106,47 +118,57 @@ options:
fmg: fmg:
description: description:
- IP address or FQDN of the FortiManager. - IP address or FQDN of the FortiManager.
fmg-source-ip: type: str
fmg_source_ip:
description: description:
- IPv4 source address that this FortiGate uses when communicating with FortiManager. - IPv4 source address that this FortiGate uses when communicating with FortiManager.
fmg-source-ip6: type: str
fmg_source_ip6:
description: description:
- IPv6 source address that this FortiGate uses when communicating with FortiManager. - IPv6 source address that this FortiGate uses when communicating with FortiManager.
include-default-servers: type: str
include_default_servers:
description: description:
- Enable/disable inclusion of public FortiGuard servers in the override server list. - Enable/disable inclusion of public FortiGuard servers in the override server list.
type: str
choices: choices:
- enable - enable
- disable - disable
mode: mode:
description: description:
- Central management mode. - Central management mode.
type: str
choices: choices:
- normal - normal
- backup - backup
schedule-config-restore: schedule_config_restore:
description: description:
- Enable/disable allowing the central management server to restore the configuration of this FortiGate. - Enable/disable allowing the central management server to restore the configuration of this FortiGate.
type: str
choices: choices:
- enable - enable
- disable - disable
schedule-script-restore: schedule_script_restore:
description: description:
- Enable/disable allowing the central management server to restore the scripts stored on this FortiGate. - Enable/disable allowing the central management server to restore the scripts stored on this FortiGate.
type: str
choices: choices:
- enable - enable
- disable - disable
serial-number: serial_number:
description: description:
- Serial number. - Serial number.
server-list: type: str
server_list:
description: description:
- Additional severs that the FortiGate can use for updates (for AV, IPS, updates) and ratings (for web filter and antispam ratings) - Additional severs that the FortiGate can use for updates (for AV, IPS, updates) and ratings (for web filter and antispam ratings)
servers. servers.
type: list
suboptions: suboptions:
addr-type: addr_type:
description: description:
- Indicate whether the FortiGate communicates with the override server using an IPv4 address, an IPv6 address or a FQDN. - Indicate whether the FortiGate communicates with the override server using an IPv4 address, an IPv6 address or a FQDN.
type: str
choices: choices:
- ipv4 - ipv4
- ipv6 - ipv6
@ -154,25 +176,31 @@ options:
fqdn: fqdn:
description: description:
- FQDN address of override server. - FQDN address of override server.
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
server-address: type: int
server_address:
description: description:
- IPv4 address of override server. - IPv4 address of override server.
server-address6: type: str
server_address6:
description: description:
- IPv6 address of override server. - IPv6 address of override server.
server-type: type: str
server_type:
description: description:
- FortiGuard service type. - FortiGuard service type.
type: str
choices: choices:
- update - update
- rating - rating
type: type:
description: description:
- Central management type. - Central management type.
type: str
choices: choices:
- fortimanager - fortimanager
- fortiguard - fortiguard
@ -180,6 +208,7 @@ options:
vdom: vdom:
description: description:
- Virtual domain (VDOM) name to use when communicating with FortiManager. Source system.vdom.name. - Virtual domain (VDOM) name to use when communicating with FortiManager. Source system.vdom.name.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -189,35 +218,37 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure central management. - name: Configure central management.
fortios_system_central_management: fortios_system_central_management:
host: "{{ host }}" host: "{{ host }}"
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
system_central_management: system_central_management:
allow-monitor: "enable" allow_monitor: "enable"
allow-push-configuration: "enable" allow_push_configuration: "enable"
allow-push-firmware: "enable" allow_push_firmware: "enable"
allow-remote-firmware-upgrade: "enable" allow_remote_firmware_upgrade: "enable"
enc-algorithm: "default" enc_algorithm: "default"
fmg: "<your_own_value>" fmg: "<your_own_value>"
fmg-source-ip: "<your_own_value>" fmg_source_ip: "<your_own_value>"
fmg-source-ip6: "<your_own_value>" fmg_source_ip6: "<your_own_value>"
include-default-servers: "enable" include_default_servers: "enable"
mode: "normal" mode: "normal"
schedule-config-restore: "enable" schedule_config_restore: "enable"
schedule-script-restore: "enable" schedule_script_restore: "enable"
serial-number: "<your_own_value>" serial_number: "<your_own_value>"
server-list: server_list:
- -
addr-type: "ipv4" addr_type: "ipv4"
fqdn: "<your_own_value>" fqdn: "<your_own_value>"
id: "19" id: "19"
server-address: "<your_own_value>" server_address: "<your_own_value>"
server-address6: "<your_own_value>" server_address6: "<your_own_value>"
server-type: "update" server_type: "update"
type: "fortimanager" type: "fortimanager"
vdom: "<your_own_value> (source system.vdom.name)" vdom: "<your_own_value> (source system.vdom.name)"
''' '''
@ -242,7 +273,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
@ -282,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']:
@ -297,90 +330,106 @@ 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_system_central_management_data(json): def filter_system_central_management_data(json):
option_list = ['allow-monitor', 'allow-push-configuration', 'allow-push-firmware', option_list = ['allow_monitor', 'allow_push_configuration', 'allow_push_firmware',
'allow-remote-firmware-upgrade', 'enc-algorithm', 'fmg', 'allow_remote_firmware_upgrade', 'enc_algorithm', 'fmg',
'fmg-source-ip', 'fmg-source-ip6', 'include-default-servers', 'fmg_source_ip', 'fmg_source_ip6', 'include_default_servers',
'mode', 'schedule-config-restore', 'schedule-script-restore', 'mode', 'schedule_config_restore', 'schedule_script_restore',
'serial-number', 'server-list', 'type', 'serial_number', 'server_list', 'type',
'vdom'] 'vdom']
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 system_central_management(data, fos): def system_central_management(data, fos):
vdom = data['vdom'] vdom = data['vdom']
system_central_management_data = data['system_central_management'] system_central_management_data = data['system_central_management']
filtered_data = filter_system_central_management_data( filtered_data = underscore_to_hyphen(filter_system_central_management_data(system_central_management_data))
system_central_management_data)
return fos.set('system', return fos.set('system',
'central-management', 'central-management',
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_system(data, fos): def fortios_system(data, fos):
login(data)
methodlist = ['system_central_management'] if data['system_central_management']:
for method in methodlist: resp = system_central_management(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", "default": "", "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},
"system_central_management": { "system_central_management": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"allow-monitor": {"required": False, "type": "str", "allow_monitor": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"allow-push-configuration": {"required": False, "type": "str", "allow_push_configuration": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"allow-push-firmware": {"required": False, "type": "str", "allow_push_firmware": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"allow-remote-firmware-upgrade": {"required": False, "type": "str", "allow_remote_firmware_upgrade": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"enc-algorithm": {"required": False, "type": "str", "enc_algorithm": {"required": False, "type": "str",
"choices": ["default", "high", "low"]}, "choices": ["default", "high", "low"]},
"fmg": {"required": False, "type": "str"}, "fmg": {"required": False, "type": "str"},
"fmg-source-ip": {"required": False, "type": "str"}, "fmg_source_ip": {"required": False, "type": "str"},
"fmg-source-ip6": {"required": False, "type": "str"}, "fmg_source_ip6": {"required": False, "type": "str"},
"include-default-servers": {"required": False, "type": "str", "include_default_servers": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"mode": {"required": False, "type": "str", "mode": {"required": False, "type": "str",
"choices": ["normal", "backup"]}, "choices": ["normal", "backup"]},
"schedule-config-restore": {"required": False, "type": "str", "schedule_config_restore": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"schedule-script-restore": {"required": False, "type": "str", "schedule_script_restore": {"required": False, "type": "str",
"choices": ["enable", "disable"]}, "choices": ["enable", "disable"]},
"serial-number": {"required": False, "type": "str"}, "serial_number": {"required": False, "type": "str"},
"server-list": {"required": False, "type": "list", "server_list": {"required": False, "type": "list",
"options": { "options": {
"addr-type": {"required": False, "type": "str", "addr_type": {"required": False, "type": "str",
"choices": ["ipv4", "ipv6", "fqdn"]}, "choices": ["ipv4", "ipv6", "fqdn"]},
"fqdn": {"required": False, "type": "str"}, "fqdn": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"server-address": {"required": False, "type": "str"}, "server_address": {"required": False, "type": "str"},
"server-address6": {"required": False, "type": "str"}, "server_address6": {"required": False, "type": "str"},
"server-type": {"required": False, "type": "str", "server_type": {"required": False, "type": "str",
"choices": ["update", "rating"]} "choices": ["update", "rating"]}
}}, }},
"type": {"required": False, "type": "str", "type": {"required": False, "type": "str",
@ -393,15 +442,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: 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_system_dhcp_server module: fortios_system_dhcp_server
short_description: Configure DHCP servers in Fortinet's FortiOS and FortiGate. short_description: Configure DHCP servers in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify system_dhcp feature and server category. user to set and modify system_dhcp feature and server category.
Examples include all parameters and values need to be adjusted to datasources before usage. 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,97 +41,125 @@ 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: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
system_dhcp_server: system_dhcp_server:
description: description:
- Configure DHCP servers. - Configure DHCP servers.
default: null default: null
type: dict
suboptions: suboptions:
state: auto_configuration:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
auto-configuration:
description: description:
- Enable/disable auto configuration. - Enable/disable auto configuration.
type: str
choices: choices:
- disable - disable
- enable - enable
conflicted-ip-timeout: conflicted_ip_timeout:
description: description:
- Time in seconds to wait after a conflicted IP address is removed from the DHCP range before it can be reused. - Time in seconds to wait after a conflicted IP address is removed from the DHCP range before it can be reused.
ddns-auth: type: int
ddns_auth:
description: description:
- DDNS authentication mode. - DDNS authentication mode.
type: str
choices: choices:
- disable - disable
- tsig - tsig
ddns-key: ddns_key:
description: description:
- DDNS update key (base 64 encoding). - DDNS update key (base 64 encoding).
ddns-keyname: type: str
ddns_keyname:
description: description:
- DDNS update key name. - DDNS update key name.
ddns-server-ip: type: str
ddns_server_ip:
description: description:
- DDNS server IP. - DDNS server IP.
ddns-ttl: type: str
ddns_ttl:
description: description:
- TTL. - TTL.
ddns-update: type: int
ddns_update:
description: description:
- Enable/disable DDNS update for DHCP. - Enable/disable DDNS update for DHCP.
type: str
choices: choices:
- disable - disable
- enable - enable
ddns-update-override: ddns_update_override:
description: description:
- Enable/disable DDNS update override for DHCP. - Enable/disable DDNS update override for DHCP.
type: str
choices: choices:
- disable - disable
- enable - enable
ddns-zone: ddns_zone:
description: description:
- Zone of your domain name (ex. DDNS.com). - Zone of your domain name (ex. DDNS.com).
default-gateway: type: str
default_gateway:
description: description:
- Default gateway IP address assigned by the DHCP server. - Default gateway IP address assigned by the DHCP server.
dns-server1: type: str
dns_server1:
description: description:
- DNS server 1. - DNS server 1.
dns-server2: type: str
dns_server2:
description: description:
- DNS server 2. - DNS server 2.
dns-server3: type: str
dns_server3:
description: description:
- DNS server 3. - DNS server 3.
dns-service: type: str
dns_service:
description: description:
- Options for assigning DNS servers to DHCP clients. - Options for assigning DNS servers to DHCP clients.
type: str
choices: choices:
- local - local
- default - default
@ -142,26 +167,33 @@ options:
domain: domain:
description: description:
- Domain name suffix for the IP addresses that the DHCP server assigns to clients. - Domain name suffix for the IP addresses that the DHCP server assigns to clients.
exclude-range: type: str
exclude_range:
description: description:
- Exclude one or more ranges of IP addresses from being assigned to clients. - Exclude one or more ranges of IP addresses from being assigned to clients.
type: list
suboptions: suboptions:
end-ip: end_ip:
description: description:
- End of IP range. - End of IP range.
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
start-ip: type: int
start_ip:
description: description:
- Start of IP range. - Start of IP range.
type: str
filename: filename:
description: description:
- Name of the boot file on the TFTP server. - Name of the boot file on the TFTP server.
forticlient-on-net-status: type: str
forticlient_on_net_status:
description: description:
- Enable/disable FortiClient-On-Net service for this DHCP server. - Enable/disable FortiClient-On-Net service for this DHCP server.
type: str
choices: choices:
- disable - disable
- enable - enable
@ -169,59 +201,75 @@ options:
description: description:
- ID. - ID.
required: true required: true
type: int
interface: interface:
description: description:
- DHCP server can assign IP configurations to clients connected to this interface. Source system.interface.name. - DHCP server can assign IP configurations to clients connected to this interface. Source system.interface.name.
ip-mode: type: str
ip_mode:
description: description:
- Method used to assign client IP. - Method used to assign client IP.
type: str
choices: choices:
- range - range
- usrgrp - usrgrp
ip-range: ip_range:
description: description:
- DHCP IP range configuration. - DHCP IP range configuration.
type: list
suboptions: suboptions:
end-ip: end_ip:
description: description:
- End of IP range. - End of IP range.
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
start-ip: type: int
start_ip:
description: description:
- Start of IP range. - Start of IP range.
ipsec-lease-hold: type: str
ipsec_lease_hold:
description: description:
- DHCP over IPsec leases expire this many seconds after tunnel down (0 to disable forced-expiry). - DHCP over IPsec leases expire this many seconds after tunnel down (0 to disable forced-expiry).
lease-time: type: int
lease_time:
description: description:
- Lease time in seconds, 0 means unlimited. - Lease time in seconds, 0 means unlimited.
mac-acl-default-action: type: int
mac_acl_default_action:
description: description:
- MAC access control default action (allow or block assigning IP settings). - MAC access control default action (allow or block assigning IP settings).
type: str
choices: choices:
- assign - assign
- block - block
netmask: netmask:
description: description:
- Netmask assigned by the DHCP server. - Netmask assigned by the DHCP server.
next-server: type: str
next_server:
description: description:
- IP address of a server (for example, a TFTP sever) that DHCP clients can download a boot file from. - IP address of a server (for example, a TFTP sever) that DHCP clients can download a boot file from.
ntp-server1: type: str
ntp_server1:
description: description:
- NTP server 1. - NTP server 1.
ntp-server2: type: str
ntp_server2:
description: description:
- NTP server 2. - NTP server 2.
ntp-server3: type: str
ntp_server3:
description: description:
- NTP server 3. - NTP server 3.
ntp-service: type: str
ntp_service:
description: description:
- Options for assigning Network Time Protocol (NTP) servers to DHCP clients. - Options for assigning Network Time Protocol (NTP) servers to DHCP clients.
type: str
choices: choices:
- local - local
- default - default
@ -229,34 +277,43 @@ options:
options: options:
description: description:
- DHCP options. - DHCP options.
type: list
suboptions: suboptions:
code: code:
description: description:
- DHCP option code. - DHCP option code.
type: int
id: id:
description: description:
- ID. - ID.
required: true required: true
type: int
ip: ip:
description: description:
- DHCP option IPs. - DHCP option IPs.
type: str
type: type:
description: description:
- DHCP option type. - DHCP option type.
type: str
choices: choices:
- hex - hex
- string - string
- ip - ip
- fqdn
value: value:
description: description:
- DHCP option value. - DHCP option value.
reserved-address: type: str
reserved_address:
description: description:
- Options for the DHCP server to assign IP settings to specific MAC addresses. - Options for the DHCP server to assign IP settings to specific MAC addresses.
type: list
suboptions: suboptions:
action: action:
description: description:
- Options for the DHCP server to configure the client with the reserved MAC address. - Options for the DHCP server to configure the client with the reserved MAC address.
type: str
choices: choices:
- assign - assign
- block - block
@ -264,39 +321,47 @@ options:
description: description:
description: description:
- Description. - Description.
type: str
id: id:
description: description:
- ID. - ID.
required: true required: true
type: int
ip: ip:
description: description:
- IP address to be reserved for the MAC address. - IP address to be reserved for the MAC address.
type: str
mac: mac:
description: description:
- MAC address of the client that will get the reserved IP address. - MAC address of the client that will get the reserved IP address.
server-type: type: str
server_type:
description: description:
- DHCP server can be a normal DHCP server or an IPsec DHCP server. - DHCP server can be a normal DHCP server or an IPsec DHCP server.
type: str
choices: choices:
- regular - regular
- ipsec - ipsec
status: status:
description: description:
- Enable/disable this DHCP configuration. - Enable/disable this DHCP configuration.
type: str
choices: choices:
- disable - disable
- enable - enable
tftp-server: tftp_server:
description: description:
- One or more hostnames or IP addresses of the TFTP servers in quotes separated by spaces. - One or more hostnames or IP addresses of the TFTP servers in quotes separated by spaces.
type: list
suboptions: suboptions:
tftp-server: tftp_server:
description: description:
- TFTP server. - TFTP server.
required: true type: str
timezone: timezone:
description: description:
- Select the time zone to be assigned to DHCP clients. - Select the time zone to be assigned to DHCP clients.
type: str
choices: choices:
- 01 - 01
- 02 - 02
@ -386,42 +451,50 @@ options:
- 73 - 73
- 86 - 86
- 76 - 76
timezone-option: timezone_option:
description: description:
- Options for the DHCP server to set the client's time zone. - Options for the DHCP server to set the client's time zone.
type: str
choices: choices:
- disable - disable
- default - default
- specify - specify
vci-match: vci_match:
description: description:
- Enable/disable vendor class identifier (VCI) matching. When enabled only DHCP requests with a matching VCI are served. - Enable/disable vendor class identifier (VCI) matching. When enabled only DHCP requests with a matching VCI are served.
type: str
choices: choices:
- disable - disable
- enable - enable
vci-string: vci_string:
description: description:
- One or more VCI strings in quotes separated by spaces. - One or more VCI strings in quotes separated by spaces.
type: list
suboptions: suboptions:
vci-string: vci_string:
description: description:
- VCI strings. - VCI strings.
required: true type: str
wifi-ac1: wifi_ac1:
description: description:
- WiFi Access Controller 1 IP address (DHCP option 138, RFC 5417). - WiFi Access Controller 1 IP address (DHCP option 138, RFC 5417).
wifi-ac2: type: str
wifi_ac2:
description: description:
- WiFi Access Controller 2 IP address (DHCP option 138, RFC 5417). - WiFi Access Controller 2 IP address (DHCP option 138, RFC 5417).
wifi-ac3: type: str
wifi_ac3:
description: description:
- WiFi Access Controller 3 IP address (DHCP option 138, RFC 5417). - WiFi Access Controller 3 IP address (DHCP option 138, RFC 5417).
wins-server1: type: str
wins_server1:
description: description:
- WINS server 1. - WINS server 1.
wins-server2: type: str
wins_server2:
description: description:
- WINS server 2. - WINS server 2.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -431,6 +504,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure DHCP servers. - name: Configure DHCP servers.
fortios_system_dhcp_server: fortios_system_dhcp_server:
@ -439,48 +513,48 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
system_dhcp_server: system_dhcp_server:
state: "present" auto_configuration: "disable"
auto-configuration: "disable" conflicted_ip_timeout: "4"
conflicted-ip-timeout: "4" ddns_auth: "disable"
ddns-auth: "disable" ddns_key: "<your_own_value>"
ddns-key: "<your_own_value>" ddns_keyname: "<your_own_value>"
ddns-keyname: "<your_own_value>" ddns_server_ip: "<your_own_value>"
ddns-server-ip: "<your_own_value>" ddns_ttl: "9"
ddns-ttl: "9" ddns_update: "disable"
ddns-update: "disable" ddns_update_override: "disable"
ddns-update-override: "disable" ddns_zone: "<your_own_value>"
ddns-zone: "<your_own_value>" default_gateway: "<your_own_value>"
default-gateway: "<your_own_value>" dns_server1: "<your_own_value>"
dns-server1: "<your_own_value>" dns_server2: "<your_own_value>"
dns-server2: "<your_own_value>" dns_server3: "<your_own_value>"
dns-server3: "<your_own_value>" dns_service: "local"
dns-service: "local"
domain: "<your_own_value>" domain: "<your_own_value>"
exclude-range: exclude_range:
- -
end-ip: "<your_own_value>" end_ip: "<your_own_value>"
id: "21" id: "21"
start-ip: "<your_own_value>" start_ip: "<your_own_value>"
filename: "<your_own_value>" filename: "<your_own_value>"
forticlient-on-net-status: "disable" forticlient_on_net_status: "disable"
id: "25" id: "25"
interface: "<your_own_value> (source system.interface.name)" interface: "<your_own_value> (source system.interface.name)"
ip-mode: "range" ip_mode: "range"
ip-range: ip_range:
- -
end-ip: "<your_own_value>" end_ip: "<your_own_value>"
id: "30" id: "30"
start-ip: "<your_own_value>" start_ip: "<your_own_value>"
ipsec-lease-hold: "32" ipsec_lease_hold: "32"
lease-time: "33" lease_time: "33"
mac-acl-default-action: "assign" mac_acl_default_action: "assign"
netmask: "<your_own_value>" netmask: "<your_own_value>"
next-server: "<your_own_value>" next_server: "<your_own_value>"
ntp-server1: "<your_own_value>" ntp_server1: "<your_own_value>"
ntp-server2: "<your_own_value>" ntp_server2: "<your_own_value>"
ntp-server3: "<your_own_value>" ntp_server3: "<your_own_value>"
ntp-service: "local" ntp_service: "local"
options: options:
- -
code: "42" code: "42"
@ -488,29 +562,29 @@ EXAMPLES = '''
ip: "<your_own_value>" ip: "<your_own_value>"
type: "hex" type: "hex"
value: "<your_own_value>" value: "<your_own_value>"
reserved-address: reserved_address:
- -
action: "assign" action: "assign"
description: "<your_own_value>" description: "<your_own_value>"
id: "50" id: "50"
ip: "<your_own_value>" ip: "<your_own_value>"
mac: "<your_own_value>" mac: "<your_own_value>"
server-type: "regular" server_type: "regular"
status: "disable" status: "disable"
tftp-server: tftp_server:
- -
tftp-server: "<your_own_value>" tftp_server: "<your_own_value>"
timezone: "01" timezone: "01"
timezone-option: "disable" timezone_option: "disable"
vci-match: "disable" vci_match: "disable"
vci-string: vci_string:
- -
vci-string: "<your_own_value>" vci_string: "<your_own_value>"
wifi-ac1: "<your_own_value>" wifi_ac1: "<your_own_value>"
wifi-ac2: "<your_own_value>" wifi_ac2: "<your_own_value>"
wifi-ac3: "<your_own_value>" wifi_ac3: "<your_own_value>"
wins-server1: "<your_own_value>" wins_server1: "<your_own_value>"
wins-server2: "<your_own_value>" wins_server2: "<your_own_value>"
''' '''
RETURN = ''' RETURN = '''
@ -573,14 +647,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']:
@ -588,26 +664,26 @@ 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_system_dhcp_server_data(json): def filter_system_dhcp_server_data(json):
option_list = ['auto-configuration', 'conflicted-ip-timeout', 'ddns-auth', option_list = ['auto_configuration', 'conflicted_ip_timeout', 'ddns_auth',
'ddns-key', 'ddns-keyname', 'ddns-server-ip', 'ddns_key', 'ddns_keyname', 'ddns_server_ip',
'ddns-ttl', 'ddns-update', 'ddns-update-override', 'ddns_ttl', 'ddns_update', 'ddns_update_override',
'ddns-zone', 'default-gateway', 'dns-server1', 'ddns_zone', 'default_gateway', 'dns_server1',
'dns-server2', 'dns-server3', 'dns-service', 'dns_server2', 'dns_server3', 'dns_service',
'domain', 'exclude-range', 'filename', 'domain', 'exclude_range', 'filename',
'forticlient-on-net-status', 'id', 'interface', 'forticlient_on_net_status', 'id', 'interface',
'ip-mode', 'ip-range', 'ipsec-lease-hold', 'ip_mode', 'ip_range', 'ipsec_lease_hold',
'lease-time', 'mac-acl-default-action', 'netmask', 'lease_time', 'mac_acl_default_action', 'netmask',
'next-server', 'ntp-server1', 'ntp-server2', 'next_server', 'ntp_server1', 'ntp_server2',
'ntp-server3', 'ntp-service', 'options', 'ntp_server3', 'ntp_service', 'options',
'reserved-address', 'server-type', 'status', 'reserved_address', 'server_type', 'status',
'tftp-server', 'timezone', 'timezone-option', 'tftp_server', 'timezone', 'timezone_option',
'vci-match', 'vci-string', 'wifi-ac1', 'vci_match', 'vci_string', 'wifi_ac1',
'wifi-ac2', 'wifi-ac3', 'wins-server1', 'wifi_ac2', 'wifi_ac3', 'wins_server1',
'wins-server2'] 'wins_server2']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -617,111 +693,116 @@ def filter_system_dhcp_server_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def system_dhcp_server(data, fos): def system_dhcp_server(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
system_dhcp_server_data = data['system_dhcp_server'] system_dhcp_server_data = data['system_dhcp_server']
flattened_data = flatten_multilists_attributes(system_dhcp_server_data) filtered_data = underscore_to_hyphen(filter_system_dhcp_server_data(system_dhcp_server_data))
filtered_data = filter_system_dhcp_server_data(flattened_data)
if system_dhcp_server_data['state'] == "present": if state == "present":
return fos.set('system.dhcp', return fos.set('system.dhcp',
'server', 'server',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif system_dhcp_server_data['state'] == "absent": elif state == "absent":
return fos.delete('system.dhcp', return fos.delete('system.dhcp',
'server', 'server',
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_system_dhcp(data, fos): def fortios_system_dhcp(data, fos):
login(data)
if data['system_dhcp_server']: if data['system_dhcp_server']:
resp = system_dhcp_server(data, fos) resp = system_dhcp_server(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"system_dhcp_server": { "system_dhcp_server": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "auto_configuration": {"required": False, "type": "str",
"choices": ["present", "absent"]},
"auto-configuration": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"conflicted-ip-timeout": {"required": False, "type": "int"}, "conflicted_ip_timeout": {"required": False, "type": "int"},
"ddns-auth": {"required": False, "type": "str", "ddns_auth": {"required": False, "type": "str",
"choices": ["disable", "tsig"]}, "choices": ["disable", "tsig"]},
"ddns-key": {"required": False, "type": "str"}, "ddns_key": {"required": False, "type": "str"},
"ddns-keyname": {"required": False, "type": "str"}, "ddns_keyname": {"required": False, "type": "str"},
"ddns-server-ip": {"required": False, "type": "str"}, "ddns_server_ip": {"required": False, "type": "str"},
"ddns-ttl": {"required": False, "type": "int"}, "ddns_ttl": {"required": False, "type": "int"},
"ddns-update": {"required": False, "type": "str", "ddns_update": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"ddns-update-override": {"required": False, "type": "str", "ddns_update_override": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"ddns-zone": {"required": False, "type": "str"}, "ddns_zone": {"required": False, "type": "str"},
"default-gateway": {"required": False, "type": "str"}, "default_gateway": {"required": False, "type": "str"},
"dns-server1": {"required": False, "type": "str"}, "dns_server1": {"required": False, "type": "str"},
"dns-server2": {"required": False, "type": "str"}, "dns_server2": {"required": False, "type": "str"},
"dns-server3": {"required": False, "type": "str"}, "dns_server3": {"required": False, "type": "str"},
"dns-service": {"required": False, "type": "str", "dns_service": {"required": False, "type": "str",
"choices": ["local", "default", "specify"]}, "choices": ["local", "default", "specify"]},
"domain": {"required": False, "type": "str"}, "domain": {"required": False, "type": "str"},
"exclude-range": {"required": False, "type": "list", "exclude_range": {"required": False, "type": "list",
"options": { "options": {
"end-ip": {"required": False, "type": "str"}, "end_ip": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"start-ip": {"required": False, "type": "str"} "start_ip": {"required": False, "type": "str"}
}}, }},
"filename": {"required": False, "type": "str"}, "filename": {"required": False, "type": "str"},
"forticlient-on-net-status": {"required": False, "type": "str", "forticlient_on_net_status": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"interface": {"required": False, "type": "str"}, "interface": {"required": False, "type": "str"},
"ip-mode": {"required": False, "type": "str", "ip_mode": {"required": False, "type": "str",
"choices": ["range", "usrgrp"]}, "choices": ["range", "usrgrp"]},
"ip-range": {"required": False, "type": "list", "ip_range": {"required": False, "type": "list",
"options": { "options": {
"end-ip": {"required": False, "type": "str"}, "end_ip": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"start-ip": {"required": False, "type": "str"} "start_ip": {"required": False, "type": "str"}
}}, }},
"ipsec-lease-hold": {"required": False, "type": "int"}, "ipsec_lease_hold": {"required": False, "type": "int"},
"lease-time": {"required": False, "type": "int"}, "lease_time": {"required": False, "type": "int"},
"mac-acl-default-action": {"required": False, "type": "str", "mac_acl_default_action": {"required": False, "type": "str",
"choices": ["assign", "block"]}, "choices": ["assign", "block"]},
"netmask": {"required": False, "type": "str"}, "netmask": {"required": False, "type": "str"},
"next-server": {"required": False, "type": "str"}, "next_server": {"required": False, "type": "str"},
"ntp-server1": {"required": False, "type": "str"}, "ntp_server1": {"required": False, "type": "str"},
"ntp-server2": {"required": False, "type": "str"}, "ntp_server2": {"required": False, "type": "str"},
"ntp-server3": {"required": False, "type": "str"}, "ntp_server3": {"required": False, "type": "str"},
"ntp-service": {"required": False, "type": "str", "ntp_service": {"required": False, "type": "str",
"choices": ["local", "default", "specify"]}, "choices": ["local", "default", "specify"]},
"options": {"required": False, "type": "list", "options": {"required": False, "type": "list",
"options": { "options": {
@ -729,10 +810,11 @@ def main():
"id": {"required": True, "type": "int"}, "id": {"required": True, "type": "int"},
"ip": {"required": False, "type": "str"}, "ip": {"required": False, "type": "str"},
"type": {"required": False, "type": "str", "type": {"required": False, "type": "str",
"choices": ["hex", "string", "ip"]}, "choices": ["hex", "string", "ip",
"fqdn"]},
"value": {"required": False, "type": "str"} "value": {"required": False, "type": "str"}
}}, }},
"reserved-address": {"required": False, "type": "list", "reserved_address": {"required": False, "type": "list",
"options": { "options": {
"action": {"required": False, "type": "str", "action": {"required": False, "type": "str",
"choices": ["assign", "block", "reserved"]}, "choices": ["assign", "block", "reserved"]},
@ -741,13 +823,13 @@ def main():
"ip": {"required": False, "type": "str"}, "ip": {"required": False, "type": "str"},
"mac": {"required": False, "type": "str"} "mac": {"required": False, "type": "str"}
}}, }},
"server-type": {"required": False, "type": "str", "server_type": {"required": False, "type": "str",
"choices": ["regular", "ipsec"]}, "choices": ["regular", "ipsec"]},
"status": {"required": False, "type": "str", "status": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"tftp-server": {"required": False, "type": "list", "tftp_server": {"required": False, "type": "list",
"options": { "options": {
"tftp-server": {"required": True, "type": "str"} "tftp_server": {"required": False, "type": "str"}
}}, }},
"timezone": {"required": False, "type": "str", "timezone": {"required": False, "type": "str",
"choices": ["01", "02", "03", "choices": ["01", "02", "03",
@ -780,19 +862,19 @@ def main():
"71", "72", "00", "71", "72", "00",
"82", "73", "86", "82", "73", "86",
"76"]}, "76"]},
"timezone-option": {"required": False, "type": "str", "timezone_option": {"required": False, "type": "str",
"choices": ["disable", "default", "specify"]}, "choices": ["disable", "default", "specify"]},
"vci-match": {"required": False, "type": "str", "vci_match": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"vci-string": {"required": False, "type": "list", "vci_string": {"required": False, "type": "list",
"options": { "options": {
"vci-string": {"required": True, "type": "str"} "vci_string": {"required": False, "type": "str"}
}}, }},
"wifi-ac1": {"required": False, "type": "str"}, "wifi_ac1": {"required": False, "type": "str"},
"wifi-ac2": {"required": False, "type": "str"}, "wifi_ac2": {"required": False, "type": "str"},
"wifi-ac3": {"required": False, "type": "str"}, "wifi_ac3": {"required": False, "type": "str"},
"wins-server1": {"required": False, "type": "str"}, "wins_server1": {"required": False, "type": "str"},
"wins-server2": {"required": False, "type": "str"} "wins_server2": {"required": False, "type": "str"}
} }
} }
@ -800,15 +882,31 @@ 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system_dhcp(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system_dhcp(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system_dhcp(module.params, fos)
fos.logout()
if not is_error: 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_system_dns module: fortios_system_dns
short_description: Configure DNS in Fortinet's FortiOS and FortiGate. short_description: Configure DNS in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify system feature and dns category. user to set and modify system feature and dns category.
Examples include all parameters and values 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,64 +41,97 @@ 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: true default: true
version_added: 2.9
system_dns: system_dns:
description: description:
- Configure DNS. - Configure DNS.
default: null default: null
type: dict
suboptions: suboptions:
cache-notfound-responses: cache_notfound_responses:
description: description:
- Enable/disable response from the DNS server when a record is not in cache. - Enable/disable response from the DNS server when a record is not in cache.
type: str
choices: choices:
- disable - disable
- enable - enable
dns-cache-limit: dns_cache_limit:
description: description:
- Maximum number of records in the DNS cache. - Maximum number of records in the DNS cache.
dns-cache-ttl: type: int
dns_cache_ttl:
description: description:
- Duration in seconds that the DNS cache retains information. - Duration in seconds that the DNS cache retains information.
type: int
domain: domain:
description: description:
- Domain name suffix for the IP addresses of the DNS server. - Search suffix list for hostname lookup.
ip6-primary: type: list
suboptions:
domain:
description:
- DNS search domain list separated by space (maximum 8 domains)
required: true
type: str
ip6_primary:
description: description:
- Primary DNS server IPv6 address. - Primary DNS server IPv6 address.
ip6-secondary: type: str
ip6_secondary:
description: description:
- Secondary DNS server IPv6 address. - Secondary DNS server IPv6 address.
type: str
primary: primary:
description: description:
- Primary DNS server IP address, default is FortiGuard server at 208.81.112.53. - Primary DNS server IP address.
type: str
retry:
description:
- Number of times to retry (0 - 5).
type: int
secondary: secondary:
description: description:
- Secondary DNS server IP address, default is FortiGuard server at 208.81.112.52. - Secondary DNS server IP address.
source-ip: type: str
source_ip:
description: description:
- IP address used by the DNS server as its source IP. - IP address used by the DNS server as its source IP.
type: str
timeout:
description:
- DNS query timeout interval in seconds (1 - 10).
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -111,6 +141,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure DNS. - name: Configure DNS.
fortios_system_dns: fortios_system_dns:
@ -120,15 +151,19 @@ EXAMPLES = '''
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
system_dns: system_dns:
cache-notfound-responses: "disable" cache_notfound_responses: "disable"
dns-cache-limit: "4" dns_cache_limit: "4"
dns-cache-ttl: "5" dns_cache_ttl: "5"
domain: "<your_own_value>" domain:
ip6-primary: "<your_own_value>" -
ip6-secondary: "<your_own_value>" domain: "<your_own_value>"
ip6_primary: "<your_own_value>"
ip6_secondary: "<your_own_value>"
primary: "<your_own_value>" primary: "<your_own_value>"
retry: "11"
secondary: "<your_own_value>" secondary: "<your_own_value>"
source-ip: "84.230.14.43" source_ip: "84.230.14.43"
timeout: "14"
''' '''
RETURN = ''' RETURN = '''
@ -191,14 +226,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']:
@ -206,13 +243,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_system_dns_data(json): def filter_system_dns_data(json):
option_list = ['cache-notfound-responses', 'dns-cache-limit', 'dns-cache-ttl', option_list = ['cache_notfound_responses', 'dns_cache_limit', 'dns_cache_ttl',
'domain', 'ip6-primary', 'ip6-secondary', 'domain', 'ip6_primary', 'ip6_secondary',
'primary', 'secondary', 'source-ip'] 'primary', 'retry', 'secondary',
'source_ip', 'timeout']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -222,17 +260,15 @@ def filter_system_dns_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
@ -240,44 +276,55 @@ def flatten_multilists_attributes(data):
def system_dns(data, fos): def system_dns(data, fos):
vdom = data['vdom'] vdom = data['vdom']
system_dns_data = data['system_dns'] system_dns_data = data['system_dns']
flattened_data = flatten_multilists_attributes(system_dns_data) filtered_data = underscore_to_hyphen(filter_system_dns_data(system_dns_data))
filtered_data = filter_system_dns_data(flattened_data)
return fos.set('system', return fos.set('system',
'dns', 'dns',
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_system(data, fos): def fortios_system(data, fos):
login(data)
if data['system_dns']: if data['system_dns']:
resp = system_dns(data, fos) resp = system_dns(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"system_dns": { "system_dns": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"cache-notfound-responses": {"required": False, "type": "str", "cache_notfound_responses": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"dns-cache-limit": {"required": False, "type": "int"}, "dns_cache_limit": {"required": False, "type": "int"},
"dns-cache-ttl": {"required": False, "type": "int"}, "dns_cache_ttl": {"required": False, "type": "int"},
"domain": {"required": False, "type": "str"}, "domain": {"required": False, "type": "list",
"ip6-primary": {"required": False, "type": "str"}, "options": {
"ip6-secondary": {"required": False, "type": "str"}, "domain": {"required": True, "type": "str"}
}},
"ip6_primary": {"required": False, "type": "str"},
"ip6_secondary": {"required": False, "type": "str"},
"primary": {"required": False, "type": "str"}, "primary": {"required": False, "type": "str"},
"retry": {"required": False, "type": "int"},
"secondary": {"required": False, "type": "str"}, "secondary": {"required": False, "type": "str"},
"source-ip": {"required": False, "type": "str"} "source_ip": {"required": False, "type": "str"},
"timeout": {"required": False, "type": "int"}
} }
} }
@ -285,15 +332,31 @@ def main():
module = AnsibleModule(argument_spec=fields, 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

File diff suppressed because it is too large Load Diff

@ -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_system_sdn_connector module: fortios_system_sdn_connector
short_description: Configure connection to SDN Connector. short_description: Configure connection to SDN Connector in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
allowing the user to configure system feature and sdn_connector category. user to set and modify system feature and sdn_connector 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,142 @@ 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
required: true
choices:
- present
- absent
version_added: 2.9
system_sdn_connector: system_sdn_connector:
description: description:
- Configure connection to SDN Connector. - Configure connection to SDN Connector.
default: null default: null
type: dict
suboptions: suboptions:
state: access_key:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
access-key:
description: description:
- AWS access key ID. - AWS access key ID.
azure-region: type: str
azure_region:
description: description:
- Azure server region. - Azure server region.
type: str
choices: choices:
- global - global
- china - china
- germany - germany
- usgov - usgov
client-id: - local
client_id:
description: description:
- Azure client ID (application ID). - Azure client ID (application ID).
client-secret: type: str
client_secret:
description: description:
- Azure client secret (application key). - Azure client secret (application key).
compartment-id: type: str
compartment_id:
description: description:
- Compartment ID. - Compartment ID.
external-ip: type: str
external_ip:
description: description:
- Configure GCP external IP. - Configure GCP external IP.
type: list
suboptions: suboptions:
name: name:
description: description:
- External IP name. - External IP name.
required: true required: true
gcp-project: type: str
gcp_project:
description: description:
- GCP project name. - GCP project name.
key-passwd: type: str
key_passwd:
description: description:
- Private key password. - Private key password.
type: str
login_endpoint:
description:
- Azure Stack login enpoint.
type: str
name: name:
description: description:
- SDN connector name. - SDN connector name.
required: true required: true
type: str
nic: nic:
description: description:
- Configure Azure network interface. - Configure Azure network interface.
type: list
suboptions: suboptions:
ip: ip:
description: description:
- Configure IP configuration. - Configure IP configuration.
type: list
suboptions: suboptions:
name: name:
description: description:
- IP configuration name. - IP configuration name.
required: true required: true
public-ip: type: str
public_ip:
description: description:
- Public IP name. - Public IP name.
type: str
name: name:
description: description:
- Network interface name. - Network interface name.
required: true required: true
oci-cert: type: str
oci_cert:
description: description:
- OCI certificate. Source certificate.local.name. - OCI certificate. Source certificate.local.name.
oci-fingerprint: type: str
oci_fingerprint:
description: description:
- OCI pubkey fingerprint. - OCI pubkey fingerprint.
oci-region: type: str
oci_region:
description: description:
- OCI server region. - OCI server region.
type: str
choices: choices:
- phoenix - phoenix
- ashburn - ashburn
@ -152,95 +185,124 @@ options:
password: password:
description: description:
- Password of the remote SDN connector as login credentials. - Password of the remote SDN connector as login credentials.
private-key: type: str
private_key:
description: description:
- Private key of GCP service account. - Private key of GCP service account.
type: str
region: region:
description: description:
- AWS region name. - AWS region name.
resource-group: type: str
resource_group:
description: description:
- Azure resource group. - Azure resource group.
type: str
resource_url:
description:
- Azure Stack resource URL.
type: str
route: route:
description: description:
- Configure GCP route. - Configure GCP route.
type: list
suboptions: suboptions:
name: name:
description: description:
- Route name. - Route name.
required: true required: true
route-table: type: str
route_table:
description: description:
- Configure Azure route table. - Configure Azure route table.
type: list
suboptions: suboptions:
name: name:
description: description:
- Route table name. - Route table name.
required: true required: true
type: str
route: route:
description: description:
- Configure Azure route. - Configure Azure route.
type: list
suboptions: suboptions:
name: name:
description: description:
- Route name. - Route name.
required: true required: true
next-hop: type: str
next_hop:
description: description:
- Next hop address. - Next hop address.
secret-key: type: str
secret_key:
description: description:
- AWS secret access key. - AWS secret access key.
type: str
server: server:
description: description:
- Server address of the remote SDN connector. - Server address of the remote SDN connector.
server-port: type: str
server_port:
description: description:
- Port number of the remote SDN connector. - Port number of the remote SDN connector.
service-account: type: int
service_account:
description: description:
- GCP service account email. - GCP service account email.
type: str
status: status:
description: description:
- Enable/disable connection to the remote SDN connector. - Enable/disable connection to the remote SDN connector.
type: str
choices: choices:
- disable - disable
- enable - enable
subscription-id: subscription_id:
description: description:
- Azure subscription ID. - Azure subscription ID.
tenant-id: type: str
tenant_id:
description: description:
- Tenant ID (directory ID). - Tenant ID (directory ID).
type: str
type: type:
description: description:
- Type of SDN connector. - Type of SDN connector.
type: str
choices: choices:
- aci - aci
- aws - aws
- azure - azure
- gcp
- nsx - nsx
- nuage - nuage
- oci - oci
- gcp - openstack
update-interval: update_interval:
description: description:
- Dynamic object update interval (0 - 3600 sec, 0 means disabled, default = 60). - Dynamic object update interval (0 - 3600 sec, 0 means disabled).
use-metadata-iam: type: int
use_metadata_iam:
description: description:
- Enable/disable using IAM role from metadata to call API. - Enable/disable using IAM role from metadata to call API.
type: str
choices: choices:
- disable - disable
- enable - enable
user-id: user_id:
description: description:
- User ID. - User ID.
type: str
username: username:
description: description:
- Username of the remote SDN connector as login credentials. - Username of the remote SDN connector as login credentials.
vpc-id: type: str
vpc_id:
description: description:
- AWS VPC ID. - AWS VPC ID.
type: str
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -250,63 +312,67 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure connection to SDN Connector. - name: Configure connection to SDN Connector.
fortios_system_sdn_connector: fortios_system_sdn_connector:
host: "{{ host }}" host: "{{ host }}"
username: "{{ username }}" username: "{{ username }}"
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False"
state: "present"
system_sdn_connector: system_sdn_connector:
state: "present" access_key: "<your_own_value>"
access-key: "<your_own_value>" azure_region: "global"
azure-region: "global" client_id: "<your_own_value>"
client-id: "<your_own_value>" client_secret: "<your_own_value>"
client-secret: "<your_own_value>" compartment_id: "<your_own_value>"
compartment-id: "<your_own_value>" external_ip:
external-ip:
- -
name: "default_name_9" name: "default_name_9"
gcp-project: "<your_own_value>" gcp_project: "<your_own_value>"
key-passwd: "<your_own_value>" key_passwd: "<your_own_value>"
name: "default_name_12" login_endpoint: "<your_own_value>"
name: "default_name_13"
nic: nic:
- -
ip: ip:
- -
name: "default_name_15" name: "default_name_16"
public-ip: "<your_own_value>" public_ip: "<your_own_value>"
name: "default_name_17" name: "default_name_18"
oci-cert: "<your_own_value> (source certificate.local.name)" oci_cert: "<your_own_value> (source certificate.local.name)"
oci-fingerprint: "<your_own_value>" oci_fingerprint: "<your_own_value>"
oci-region: "phoenix" oci_region: "phoenix"
password: "<your_own_value>" password: "<your_own_value>"
private-key: "<your_own_value>" private_key: "<your_own_value>"
region: "<your_own_value>" region: "<your_own_value>"
resource-group: "<your_own_value>" resource_group: "<your_own_value>"
resource_url: "<your_own_value>"
route: route:
-
name: "default_name_26"
route-table:
- -
name: "default_name_28" name: "default_name_28"
route_table:
-
name: "default_name_30"
route: route:
- -
name: "default_name_30" name: "default_name_32"
next-hop: "<your_own_value>" next_hop: "<your_own_value>"
secret-key: "<your_own_value>" secret_key: "<your_own_value>"
server: "192.168.100.40" server: "192.168.100.40"
server-port: "34" server_port: "36"
service-account: "<your_own_value>" service_account: "<your_own_value>"
status: "disable" status: "disable"
subscription-id: "<your_own_value>" subscription_id: "<your_own_value>"
tenant-id: "<your_own_value>" tenant_id: "<your_own_value>"
type: "aci" type: "aci"
update-interval: "40" update_interval: "42"
use-metadata-iam: "disable" use_metadata_iam: "disable"
user-id: "<your_own_value>" user_id: "<your_own_value>"
username: "<your_own_value>" username: "<your_own_value>"
vpc-id: "<your_own_value>" vpc_id: "<your_own_value>"
''' '''
RETURN = ''' RETURN = '''
@ -329,7 +395,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
@ -369,14 +435,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']:
@ -384,135 +452,156 @@ 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_system_sdn_connector_data(json): def filter_system_sdn_connector_data(json):
option_list = ['access-key', 'azure-region', 'client-id', option_list = ['access_key', 'azure_region', 'client_id',
'client-secret', 'compartment-id', 'external-ip', 'client_secret', 'compartment_id', 'external_ip',
'gcp-project', 'key-passwd', 'name', 'gcp_project', 'key_passwd', 'login_endpoint',
'nic', 'oci-cert', 'oci-fingerprint', 'name', 'nic', 'oci_cert',
'oci-region', 'password', 'private-key', 'oci_fingerprint', 'oci_region', 'password',
'region', 'resource-group', 'route', 'private_key', 'region', 'resource_group',
'route-table', 'secret-key', 'server', 'resource_url', 'route', 'route_table',
'server-port', 'service-account', 'status', 'secret_key', 'server', 'server_port',
'subscription-id', 'tenant-id', 'type', 'service_account', 'status', 'subscription_id',
'update-interval', 'use-metadata-iam', 'user-id', 'tenant_id', 'type', 'update_interval',
'username', 'vpc-id'] 'use_metadata_iam', 'user_id', 'username',
'vpc_id']
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 system_sdn_connector(data, fos): def system_sdn_connector(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
system_sdn_connector_data = data['system_sdn_connector'] system_sdn_connector_data = data['system_sdn_connector']
filtered_data = filter_system_sdn_connector_data(system_sdn_connector_data) filtered_data = underscore_to_hyphen(filter_system_sdn_connector_data(system_sdn_connector_data))
if system_sdn_connector_data['state'] == "present":
if state == "present":
return fos.set('system', return fos.set('system',
'sdn-connector', 'sdn-connector',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif system_sdn_connector_data['state'] == "absent": elif state == "absent":
return fos.delete('system', return fos.delete('system',
'sdn-connector', 'sdn-connector',
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_system(data, fos): def fortios_system(data, fos):
login(data)
methodlist = ['system_sdn_connector'] if data['system_sdn_connector']:
for method in methodlist: resp = system_sdn_connector(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", "default": "", "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"]},
"system_sdn_connector": { "system_sdn_connector": {
"required": False, "type": "dict", "required": False, "type": "dict", "default": None,
"options": { "options": {
"state": {"required": True, "type": "str", "access_key": {"required": False, "type": "str"},
"choices": ["present", "absent"]}, "azure_region": {"required": False, "type": "str",
"access-key": {"required": False, "type": "str"},
"azure-region": {"required": False, "type": "str",
"choices": ["global", "china", "germany", "choices": ["global", "china", "germany",
"usgov"]}, "usgov", "local"]},
"client-id": {"required": False, "type": "str"}, "client_id": {"required": False, "type": "str"},
"client-secret": {"required": False, "type": "str"}, "client_secret": {"required": False, "type": "str"},
"compartment-id": {"required": False, "type": "str"}, "compartment_id": {"required": False, "type": "str"},
"external-ip": {"required": False, "type": "list", "external_ip": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"gcp-project": {"required": False, "type": "str"}, "gcp_project": {"required": False, "type": "str"},
"key-passwd": {"required": False, "type": "str"}, "key_passwd": {"required": False, "type": "str"},
"login_endpoint": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"nic": {"required": False, "type": "list", "nic": {"required": False, "type": "list",
"options": { "options": {
"ip": {"required": False, "type": "list", "ip": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"public-ip": {"required": False, "type": "str"} "public_ip": {"required": False, "type": "str"}
}}, }},
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"oci-cert": {"required": False, "type": "str"}, "oci_cert": {"required": False, "type": "str"},
"oci-fingerprint": {"required": False, "type": "str"}, "oci_fingerprint": {"required": False, "type": "str"},
"oci-region": {"required": False, "type": "str", "oci_region": {"required": False, "type": "str",
"choices": ["phoenix", "ashburn", "frankfurt", "choices": ["phoenix", "ashburn", "frankfurt",
"london"]}, "london"]},
"password": {"required": False, "type": "str"}, "password": {"required": False, "type": "str"},
"private-key": {"required": False, "type": "str"}, "private_key": {"required": False, "type": "str"},
"region": {"required": False, "type": "str"}, "region": {"required": False, "type": "str"},
"resource-group": {"required": False, "type": "str"}, "resource_group": {"required": False, "type": "str"},
"resource_url": {"required": False, "type": "str"},
"route": {"required": False, "type": "list", "route": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"} "name": {"required": True, "type": "str"}
}}, }},
"route-table": {"required": False, "type": "list", "route_table": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"route": {"required": False, "type": "list", "route": {"required": False, "type": "list",
"options": { "options": {
"name": {"required": True, "type": "str"}, "name": {"required": True, "type": "str"},
"next-hop": {"required": False, "type": "str"} "next_hop": {"required": False, "type": "str"}
}} }}
}}, }},
"secret-key": {"required": False, "type": "str"}, "secret_key": {"required": False, "type": "str"},
"server": {"required": False, "type": "str"}, "server": {"required": False, "type": "str"},
"server-port": {"required": False, "type": "int"}, "server_port": {"required": False, "type": "int"},
"service-account": {"required": False, "type": "str"}, "service_account": {"required": False, "type": "str"},
"status": {"required": False, "type": "str", "status": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"subscription-id": {"required": False, "type": "str"}, "subscription_id": {"required": False, "type": "str"},
"tenant-id": {"required": False, "type": "str"}, "tenant_id": {"required": False, "type": "str"},
"type": {"required": False, "type": "str", "type": {"required": False, "type": "str",
"choices": ["aci", "aws", "azure", "choices": ["aci", "aws", "azure",
"nsx", "nuage", "oci", "gcp", "nsx", "nuage",
"gcp"]}, "oci", "openstack"]},
"update-interval": {"required": False, "type": "int"}, "update_interval": {"required": False, "type": "int"},
"use-metadata-iam": {"required": False, "type": "str", "use_metadata_iam": {"required": False, "type": "str",
"choices": ["disable", "enable"]}, "choices": ["disable", "enable"]},
"user-id": {"required": False, "type": "str"}, "user_id": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"}, "username": {"required": False, "type": "str"},
"vpc-id": {"required": False, "type": "str"} "vpc_id": {"required": False, "type": "str"}
} }
} }
@ -520,15 +609,31 @@ def main():
module = AnsibleModule(argument_spec=fields, 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -130,11 +130,11 @@ options:
- disable - disable
bfd_desired_min_tx: bfd_desired_min_tx:
description: description:
- BFD desired minimal transmit interval (1 - 100000 ms, default = 50). - BFD desired minimal transmit interval (1 - 100000 ms).
type: int type: int
bfd_detect_mult: bfd_detect_mult:
description: description:
- BFD detection multiplier (1 - 50, default = 3). - BFD detection multiplier (1 - 50).
type: int type: int
bfd_dont_enforce_src_port: bfd_dont_enforce_src_port:
description: description:
@ -145,7 +145,7 @@ options:
- disable - disable
bfd_required_min_rx: bfd_required_min_rx:
description: description:
- BFD required minimal receive interval (1 - 100000 ms, default = 50). - BFD required minimal receive interval (1 - 100000 ms).
type: int type: int
block_land_attack: block_land_attack:
description: description:
@ -207,11 +207,11 @@ options:
type: str type: str
discovered_device_timeout: discovered_device_timeout:
description: description:
- Timeout for discovered devices (1 - 365 days, default = 28). - Timeout for discovered devices (1 - 365 days).
type: int type: int
ecmp_max_paths: ecmp_max_paths:
description: description:
- Maximum number of Equal Cost Multi-Path (ECMP) next-hops. Set to 1 to disable ECMP routing (1 - 100, default = 10). - Maximum number of Equal Cost Multi-Path (ECMP) next-hops. Set to 1 to disable ECMP routing (1 - 100).
type: int type: int
email_portal_check_dns: email_portal_check_dns:
description: description:
@ -649,7 +649,7 @@ options:
- global - global
mac_ttl: mac_ttl:
description: description:
- Duration of MAC addresses in Transparent mode (300 - 8640000 sec, default = 300). - Duration of MAC addresses in Transparent mode (300 - 8640000 sec).
type: int type: int
manageip: manageip:
description: description:
@ -703,7 +703,7 @@ options:
- disable - disable
sccp_port: sccp_port:
description: description:
- TCP port the SCCP proxy monitors for SCCP traffic (0 - 65535, default = 2000). - TCP port the SCCP proxy monitors for SCCP traffic (0 - 65535).
type: int type: int
ses_denied_traffic: ses_denied_traffic:
description: description:
@ -729,15 +729,15 @@ options:
- disable - disable
sip_ssl_port: sip_ssl_port:
description: description:
- TCP port the SIP proxy monitors for SIP SSL/TLS traffic (0 - 65535, default = 5061). - TCP port the SIP proxy monitors for SIP SSL/TLS traffic (0 - 65535).
type: int type: int
sip_tcp_port: sip_tcp_port:
description: description:
- TCP port the SIP proxy monitors for SIP traffic (0 - 65535, default = 5060). - TCP port the SIP proxy monitors for SIP traffic (0 - 65535).
type: int type: int
sip_udp_port: sip_udp_port:
description: description:
- UDP port the SIP proxy monitors for SIP traffic (0 - 65535, default = 5060). - UDP port the SIP proxy monitors for SIP traffic (0 - 65535).
type: int type: int
snat_hairpin_traffic: snat_hairpin_traffic:
description: description:

@ -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_system_vdom module: fortios_system_vdom
short_description: Configure virtual domain in Fortinet's FortiOS and FortiGate. short_description: Configure virtual domain in Fortinet's FortiOS and FortiGate.
description: description:
- This module is able to configure a FortiGate or FortiOS by allowing the - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify system feature and vdom category. user to set and modify system feature and vdom category.
Examples include all parameters and values 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,53 +41,70 @@ 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: true default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
system_vdom: system_vdom:
description: description:
- Configure virtual domain. - Configure virtual domain.
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:
- VDOM name. - VDOM name.
required: true required: true
short-name: type: str
short_name:
description: description:
- VDOM short name. - VDOM short name.
type: str
temporary: temporary:
description: description:
- Temporary. - Temporary.
vcluster-id: type: int
vcluster_id:
description: description:
- Virtual cluster ID (0 - 4294967295). - Virtual cluster ID (0 - 4294967295).
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -100,6 +114,7 @@ EXAMPLES = '''
username: "admin" username: "admin"
password: "" password: ""
vdom: "root" vdom: "root"
ssl_verify: "False"
tasks: tasks:
- name: Configure virtual domain. - name: Configure virtual domain.
fortios_system_vdom: fortios_system_vdom:
@ -108,12 +123,12 @@ EXAMPLES = '''
password: "{{ password }}" password: "{{ password }}"
vdom: "{{ vdom }}" vdom: "{{ vdom }}"
https: "False" https: "False"
state: "present"
system_vdom: system_vdom:
state: "present"
name: "default_name_3" name: "default_name_3"
short-name: "<your_own_value>" short_name: "<your_own_value>"
temporary: "5" temporary: "5"
vcluster-id: "6" vcluster_id: "6"
''' '''
RETURN = ''' RETURN = '''
@ -176,14 +191,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']:
@ -191,12 +208,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_system_vdom_data(json): def filter_system_vdom_data(json):
option_list = ['name', 'short-name', 'temporary', option_list = ['name', 'short_name', 'temporary',
'vcluster-id'] 'vcluster_id']
dictionary = {} dictionary = {}
for attribute in option_list: for attribute in option_list:
@ -206,65 +223,70 @@ def filter_system_vdom_data(json):
return dictionary return dictionary
def flatten_multilists_attributes(data): def underscore_to_hyphen(data):
multilist_attrs = [] if isinstance(data, list):
for elem in data:
for attr in multilist_attrs: elem = underscore_to_hyphen(elem)
try: elif isinstance(data, dict):
path = "data['" + "']['".join(elem for elem in attr) + "']" new_data = {}
current_val = eval(path) for k, v in data.items():
flattened_val = ' '.join(elem for elem in current_val) new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
exec(path + '= flattened_val') data = new_data
except BaseException:
pass
return data return data
def system_vdom(data, fos): def system_vdom(data, fos):
vdom = data['vdom'] vdom = data['vdom']
state = data['state']
system_vdom_data = data['system_vdom'] system_vdom_data = data['system_vdom']
flattened_data = flatten_multilists_attributes(system_vdom_data) filtered_data = underscore_to_hyphen(filter_system_vdom_data(system_vdom_data))
filtered_data = filter_system_vdom_data(flattened_data)
if system_vdom_data['state'] == "present": if state == "present":
return fos.set('system', return fos.set('system',
'vdom', 'vdom',
data=filtered_data, data=filtered_data,
vdom=vdom) vdom=vdom)
elif system_vdom_data['state'] == "absent": elif state == "absent":
return fos.delete('system', return fos.delete('system',
'vdom', 'vdom',
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_system(data, fos): def fortios_system(data, fos):
login(data)
if data['system_vdom']: if data['system_vdom']:
resp = system_vdom(data, fos) resp = system_vdom(data, fos)
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", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"}, "vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True}, "https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"system_vdom": { "system_vdom": {
"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"},
"short-name": {"required": False, "type": "str"}, "short_name": {"required": False, "type": "str"},
"temporary": {"required": False, "type": "int"}, "temporary": {"required": False, "type": "int"},
"vcluster-id": {"required": False, "type": "int"} "vcluster_id": {"required": False, "type": "int"}
} }
} }
@ -272,15 +294,31 @@ def main():
module = AnsibleModule(argument_spec=fields, 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 refers to using fortiosapi instead of HTTPAPI
fos = FortiOSAPI() legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_system(module.params, fos)
else:
module.fail_json(**FAIL_SOCKET_MSG)
else:
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
is_error, has_changed, result = fortios_system(module.params, fos) login(module.params, fos)
is_error, has_changed, result = fortios_system(module.params, fos)
fos.logout()
if not is_error: if not is_error:
module.exit_json(changed=has_changed, meta=result) module.exit_json(changed=has_changed, meta=result)

@ -3693,46 +3693,10 @@ lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules
lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E338 lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E338
lib/ansible/modules/network/fortios/fortios_report_chart.py validate-modules:E326 lib/ansible/modules/network/fortios/fortios_report_chart.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_spamfilter_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_ssh_filter_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_global.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_global.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_mac_sync_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_switch_controller_network_monitor_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_accprofile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_accprofile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_admin.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_admin.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_api_user.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_api_user.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_central_management.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_central_management.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E326 lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_dns.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_dns.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E326 lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_interface.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_interface.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_sdn_connector.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_vdom.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_vdom.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_virtual_wan_link.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E336 lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_user_device.py validate-modules:E337 lib/ansible/modules/network/fortios/fortios_user_device.py validate-modules:E337

@ -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_spamfilter_profile
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_spamfilter_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_spamfilter_profile_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'spamfilter_profile': {
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'external': 'enable',
'flow-based': 'enable',
'name': 'default_name_6',
'replacemsg-group': 'test_value_7',
'spam-bwl-table': '8',
'spam-bword-table': '9',
'spam-bword-threshold': '10',
'spam-filtering': 'enable',
'spam-iptrust-table': '12',
'spam-log': 'disable',
'spam-log-fortiguard-response': 'disable',
'spam-mheader-table': '15',
'spam-rbl-table': '16',
}
set_method_mock.assert_called_with('spamfilter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_spamfilter_profile_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'spamfilter_profile': {
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'external': 'enable',
'flow-based': 'enable',
'name': 'default_name_6',
'replacemsg-group': 'test_value_7',
'spam-bwl-table': '8',
'spam-bword-table': '9',
'spam-bword-threshold': '10',
'spam-filtering': 'enable',
'spam-iptrust-table': '12',
'spam-log': 'disable',
'spam-log-fortiguard-response': 'disable',
'spam-mheader-table': '15',
'spam-rbl-table': '16',
}
set_method_mock.assert_called_with('spamfilter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_spamfilter_profile_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'spamfilter_profile': {
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('spamfilter', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_spamfilter_profile_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'spamfilter_profile': {
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('spamfilter', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_spamfilter_profile_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'spamfilter_profile': {
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'external': 'enable',
'flow-based': 'enable',
'name': 'default_name_6',
'replacemsg-group': 'test_value_7',
'spam-bwl-table': '8',
'spam-bword-table': '9',
'spam-bword-threshold': '10',
'spam-filtering': 'enable',
'spam-iptrust-table': '12',
'spam-log': 'disable',
'spam-log-fortiguard-response': 'disable',
'spam-mheader-table': '15',
'spam-rbl-table': '16',
}
set_method_mock.assert_called_with('spamfilter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_spamfilter_profile_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'spamfilter_profile': {
'random_attribute_not_valid': 'tag',
'comment': 'Comment.',
'external': 'enable',
'flow_based': 'enable',
'name': 'default_name_6',
'replacemsg_group': 'test_value_7',
'spam_bwl_table': '8',
'spam_bword_table': '9',
'spam_bword_threshold': '10',
'spam_filtering': 'enable',
'spam_iptrust_table': '12',
'spam_log': 'disable',
'spam_log_fortiguard_response': 'disable',
'spam_mheader_table': '15',
'spam_rbl_table': '16',
},
'vdom': 'root'}
is_error, changed, response = fortios_spamfilter_profile.fortios_spamfilter(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'external': 'enable',
'flow-based': 'enable',
'name': 'default_name_6',
'replacemsg-group': 'test_value_7',
'spam-bwl-table': '8',
'spam-bword-table': '9',
'spam-bword-threshold': '10',
'spam-filtering': 'enable',
'spam-iptrust-table': '12',
'spam-log': 'disable',
'spam-log-fortiguard-response': 'disable',
'spam-mheader-table': '15',
'spam-rbl-table': '16',
}
set_method_mock.assert_called_with('spamfilter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,239 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_ssh_filter_profile
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_ssh_filter_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_ssh_filter_profile_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'ssh_filter_profile': {
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
expected_data = {
'block': 'x11',
'default-command-log': 'enable',
'log': 'x11',
'name': 'default_name_6',
}
set_method_mock.assert_called_with('ssh-filter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_ssh_filter_profile_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'ssh_filter_profile': {
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
expected_data = {
'block': 'x11',
'default-command-log': 'enable',
'log': 'x11',
'name': 'default_name_6',
}
set_method_mock.assert_called_with('ssh-filter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_ssh_filter_profile_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'ssh_filter_profile': {
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
delete_method_mock.assert_called_with('ssh-filter', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_ssh_filter_profile_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'ssh_filter_profile': {
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
delete_method_mock.assert_called_with('ssh-filter', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_ssh_filter_profile_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'ssh_filter_profile': {
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
expected_data = {
'block': 'x11',
'default-command-log': 'enable',
'log': 'x11',
'name': 'default_name_6',
}
set_method_mock.assert_called_with('ssh-filter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_ssh_filter_profile_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'ssh_filter_profile': {
'random_attribute_not_valid': 'tag',
'block': 'x11',
'default_command_log': 'enable',
'log': 'x11',
'name': 'default_name_6',
},
'vdom': 'root'}
is_error, changed, response = fortios_ssh_filter_profile.fortios_ssh_filter(input_data, fos_instance)
expected_data = {
'block': 'x11',
'default-command-log': 'enable',
'log': 'x11',
'name': 'default_name_6',
}
set_method_mock.assert_called_with('ssh-filter', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -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_switch_controller_global
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_global.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_global_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_global': {
'allow_multiple_interfaces': 'enable',
'default_virtual_switch_vlan': 'test_value_4',
'https_image_push': 'enable',
'log_mac_limit_violations': 'enable',
'mac_aging_interval': '7',
'mac_retention_period': '8',
'mac_violation_timer': '9'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'allow-multiple-interfaces': 'enable',
'default-virtual-switch-vlan': 'test_value_4',
'https-image-push': 'enable',
'log-mac-limit-violations': 'enable',
'mac-aging-interval': '7',
'mac-retention-period': '8',
'mac-violation-timer': '9'
}
set_method_mock.assert_called_with('switch-controller', 'global', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_global_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_global': {
'allow_multiple_interfaces': 'enable',
'default_virtual_switch_vlan': 'test_value_4',
'https_image_push': 'enable',
'log_mac_limit_violations': 'enable',
'mac_aging_interval': '7',
'mac_retention_period': '8',
'mac_violation_timer': '9'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'allow-multiple-interfaces': 'enable',
'default-virtual-switch-vlan': 'test_value_4',
'https-image-push': 'enable',
'log-mac-limit-violations': 'enable',
'mac-aging-interval': '7',
'mac-retention-period': '8',
'mac-violation-timer': '9'
}
set_method_mock.assert_called_with('switch-controller', 'global', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_global_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_global': {
'allow_multiple_interfaces': 'enable',
'default_virtual_switch_vlan': 'test_value_4',
'https_image_push': 'enable',
'log_mac_limit_violations': 'enable',
'mac_aging_interval': '7',
'mac_retention_period': '8',
'mac_violation_timer': '9'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'allow-multiple-interfaces': 'enable',
'default-virtual-switch-vlan': 'test_value_4',
'https-image-push': 'enable',
'log-mac-limit-violations': 'enable',
'mac-aging-interval': '7',
'mac-retention-period': '8',
'mac-violation-timer': '9'
}
set_method_mock.assert_called_with('switch-controller', 'global', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_global_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_global': {
'random_attribute_not_valid': 'tag',
'allow_multiple_interfaces': 'enable',
'default_virtual_switch_vlan': 'test_value_4',
'https_image_push': 'enable',
'log_mac_limit_violations': 'enable',
'mac_aging_interval': '7',
'mac_retention_period': '8',
'mac_violation_timer': '9'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_global.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'allow-multiple-interfaces': 'enable',
'default-virtual-switch-vlan': 'test_value_4',
'https-image-push': 'enable',
'log-mac-limit-violations': 'enable',
'mac-aging-interval': '7',
'mac-retention-period': '8',
'mac-violation-timer': '9'
}
set_method_mock.assert_called_with('switch-controller', 'global', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,269 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_switch_controller_lldp_profile
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_lldp_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_lldp_profile_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_profile': {
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'802.1-tlvs': 'port-vlan-id',
'802.3-tlvs': 'max-frame-size',
'auto-isl': 'disable',
'auto-isl-hello-timer': '6',
'auto-isl-port-group': '7',
'auto-isl-receive-timeout': '8',
'med-tlvs': 'inventory-management',
'name': 'default_name_10'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_lldp_profile_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_profile': {
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'802.1-tlvs': 'port-vlan-id',
'802.3-tlvs': 'max-frame-size',
'auto-isl': 'disable',
'auto-isl-hello-timer': '6',
'auto-isl-port-group': '7',
'auto-isl-receive-timeout': '8',
'med-tlvs': 'inventory-management',
'name': 'default_name_10'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_lldp_profile_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'switch_controller_lldp_profile': {
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
delete_method_mock.assert_called_with('switch-controller', 'lldp-profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_lldp_profile_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'switch_controller_lldp_profile': {
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
delete_method_mock.assert_called_with('switch-controller', 'lldp-profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_lldp_profile_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_profile': {
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'802.1-tlvs': 'port-vlan-id',
'802.3-tlvs': 'max-frame-size',
'auto-isl': 'disable',
'auto-isl-hello-timer': '6',
'auto-isl-port-group': '7',
'auto-isl-receive-timeout': '8',
'med-tlvs': 'inventory-management',
'name': 'default_name_10'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_lldp_profile_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_profile': {
'random_attribute_not_valid': 'tag',
'802.1_tlvs': 'port-vlan-id',
'802.3_tlvs': 'max-frame-size',
'auto_isl': 'disable',
'auto_isl_hello_timer': '6',
'auto_isl_port_group': '7',
'auto_isl_receive_timeout': '8',
'med_tlvs': 'inventory-management',
'name': 'default_name_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_profile.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'802.1-tlvs': 'port-vlan-id',
'802.3-tlvs': 'max-frame-size',
'auto-isl': 'disable',
'auto-isl-hello-timer': '6',
'auto-isl-port-group': '7',
'auto-isl-receive-timeout': '8',
'med-tlvs': 'inventory-management',
'name': 'default_name_10'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -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_switch_controller_lldp_settings
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_lldp_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_lldp_settings_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_settings': {
'fast_start_interval': '3',
'management_interface': 'internal',
'status': 'enable',
'tx_hold': '6',
'tx_interval': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'fast-start-interval': '3',
'management-interface': 'internal',
'status': 'enable',
'tx-hold': '6',
'tx-interval': '7'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_lldp_settings_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_settings': {
'fast_start_interval': '3',
'management_interface': 'internal',
'status': 'enable',
'tx_hold': '6',
'tx_interval': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'fast-start-interval': '3',
'management-interface': 'internal',
'status': 'enable',
'tx-hold': '6',
'tx-interval': '7'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_lldp_settings_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_settings': {
'fast_start_interval': '3',
'management_interface': 'internal',
'status': 'enable',
'tx_hold': '6',
'tx_interval': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'fast-start-interval': '3',
'management-interface': 'internal',
'status': 'enable',
'tx-hold': '6',
'tx-interval': '7'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_lldp_settings_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_lldp_settings': {
'random_attribute_not_valid': 'tag',
'fast_start_interval': '3',
'management_interface': 'internal',
'status': 'enable',
'tx_hold': '6',
'tx_interval': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_lldp_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'fast-start-interval': '3',
'management-interface': 'internal',
'status': 'enable',
'tx-hold': '6',
'tx-interval': '7'
}
set_method_mock.assert_called_with('switch-controller', 'lldp-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -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_switch_controller_mac_sync_settings
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_mac_sync_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_mac_sync_settings_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_mac_sync_settings': {
'mac_sync_interval': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'mac-sync-interval': '3'
}
set_method_mock.assert_called_with('switch-controller', 'mac-sync-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_mac_sync_settings_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_mac_sync_settings': {
'mac_sync_interval': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'mac-sync-interval': '3'
}
set_method_mock.assert_called_with('switch-controller', 'mac-sync-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_mac_sync_settings_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_mac_sync_settings': {
'mac_sync_interval': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'mac-sync-interval': '3'
}
set_method_mock.assert_called_with('switch-controller', 'mac-sync-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_mac_sync_settings_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_mac_sync_settings': {
'random_attribute_not_valid': 'tag',
'mac_sync_interval': '3'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_mac_sync_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'mac-sync-interval': '3'
}
set_method_mock.assert_called_with('switch-controller', 'mac-sync-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,389 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_switch_controller_managed_switch
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_managed_switch.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_managed_switch_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_managed_switch': {'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
expected_data = {'delayed-restart-trigger': '3',
'description': 'test_value_4',
'directly-connected': '5',
'dynamic-capability': '6',
'dynamically-discovered': '7',
'fsw-wan1-admin': 'discovered',
'fsw-wan1-peer': 'test_value_9',
'fsw-wan2-admin': 'discovered',
'fsw-wan2-peer': 'test_value_11',
'max-allowed-trunk-members': '12',
'name': 'default_name_13',
'owner-vdom': 'test_value_14',
'poe-detection-type': '15',
'poe-pre-standard-detection': 'enable',
'pre-provisioned': '17',
'staged-image-version': 'test_value_18',
'switch-device-tag': 'test_value_19',
'switch-id': 'test_value_20',
'switch-profile': 'test_value_21',
'type': 'virtual',
'version': '23'
}
set_method_mock.assert_called_with('switch-controller', 'managed-switch', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_managed_switch_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_managed_switch': {'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
expected_data = {'delayed-restart-trigger': '3',
'description': 'test_value_4',
'directly-connected': '5',
'dynamic-capability': '6',
'dynamically-discovered': '7',
'fsw-wan1-admin': 'discovered',
'fsw-wan1-peer': 'test_value_9',
'fsw-wan2-admin': 'discovered',
'fsw-wan2-peer': 'test_value_11',
'max-allowed-trunk-members': '12',
'name': 'default_name_13',
'owner-vdom': 'test_value_14',
'poe-detection-type': '15',
'poe-pre-standard-detection': 'enable',
'pre-provisioned': '17',
'staged-image-version': 'test_value_18',
'switch-device-tag': 'test_value_19',
'switch-id': 'test_value_20',
'switch-profile': 'test_value_21',
'type': 'virtual',
'version': '23'
}
set_method_mock.assert_called_with('switch-controller', 'managed-switch', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_managed_switch_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'switch_controller_managed_switch': {'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
delete_method_mock.assert_called_with('switch-controller', 'managed-switch', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_managed_switch_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'switch_controller_managed_switch': {'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
delete_method_mock.assert_called_with('switch-controller', 'managed-switch', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_managed_switch_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_managed_switch': {'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
expected_data = {'delayed-restart-trigger': '3',
'description': 'test_value_4',
'directly-connected': '5',
'dynamic-capability': '6',
'dynamically-discovered': '7',
'fsw-wan1-admin': 'discovered',
'fsw-wan1-peer': 'test_value_9',
'fsw-wan2-admin': 'discovered',
'fsw-wan2-peer': 'test_value_11',
'max-allowed-trunk-members': '12',
'name': 'default_name_13',
'owner-vdom': 'test_value_14',
'poe-detection-type': '15',
'poe-pre-standard-detection': 'enable',
'pre-provisioned': '17',
'staged-image-version': 'test_value_18',
'switch-device-tag': 'test_value_19',
'switch-id': 'test_value_20',
'switch-profile': 'test_value_21',
'type': 'virtual',
'version': '23'
}
set_method_mock.assert_called_with('switch-controller', 'managed-switch', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_managed_switch_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_managed_switch': {
'random_attribute_not_valid': 'tag', 'delayed_restart_trigger': '3',
'description': 'test_value_4',
'directly_connected': '5',
'dynamic_capability': '6',
'dynamically_discovered': '7',
'fsw_wan1_admin': 'discovered',
'fsw_wan1_peer': 'test_value_9',
'fsw_wan2_admin': 'discovered',
'fsw_wan2_peer': 'test_value_11',
'max_allowed_trunk_members': '12',
'name': 'default_name_13',
'owner_vdom': 'test_value_14',
'poe_detection_type': '15',
'poe_pre_standard_detection': 'enable',
'pre_provisioned': '17',
'staged_image_version': 'test_value_18',
'switch_device_tag': 'test_value_19',
'switch_id': 'test_value_20',
'switch_profile': 'test_value_21',
'type': 'virtual',
'version': '23'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_managed_switch.fortios_switch_controller(input_data, fos_instance)
expected_data = {'delayed-restart-trigger': '3',
'description': 'test_value_4',
'directly-connected': '5',
'dynamic-capability': '6',
'dynamically-discovered': '7',
'fsw-wan1-admin': 'discovered',
'fsw-wan1-peer': 'test_value_9',
'fsw-wan2-admin': 'discovered',
'fsw-wan2-peer': 'test_value_11',
'max-allowed-trunk-members': '12',
'name': 'default_name_13',
'owner-vdom': 'test_value_14',
'poe-detection-type': '15',
'poe-pre-standard-detection': 'enable',
'pre-provisioned': '17',
'staged-image-version': 'test_value_18',
'switch-device-tag': 'test_value_19',
'switch-id': 'test_value_20',
'switch-profile': 'test_value_21',
'type': 'virtual',
'version': '23'
}
set_method_mock.assert_called_with('switch-controller', 'managed-switch', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -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_switch_controller_network_monitor_settings
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_switch_controller_network_monitor_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_switch_controller_network_monitor_settings_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_network_monitor_settings': {
'network_monitoring': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'network-monitoring': 'enable'
}
set_method_mock.assert_called_with('switch-controller', 'network-monitor-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_switch_controller_network_monitor_settings_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_network_monitor_settings': {
'network_monitoring': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'network-monitoring': 'enable'
}
set_method_mock.assert_called_with('switch-controller', 'network-monitor-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_switch_controller_network_monitor_settings_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_network_monitor_settings': {
'network_monitoring': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'network-monitoring': 'enable'
}
set_method_mock.assert_called_with('switch-controller', 'network-monitor-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_switch_controller_network_monitor_settings_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'switch_controller_network_monitor_settings': {
'random_attribute_not_valid': 'tag',
'network_monitoring': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_switch_controller_network_monitor_settings.fortios_switch_controller(input_data, fos_instance)
expected_data = {
'network-monitoring': 'enable'
}
set_method_mock.assert_called_with('switch-controller', 'network-monitor-settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,349 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_accprofile
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_accprofile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_accprofile_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_accprofile': {
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
expected_data = {
'admintimeout': '3',
'admintimeout-override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
}
set_method_mock.assert_called_with('system', 'accprofile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_accprofile_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_accprofile': {
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
expected_data = {
'admintimeout': '3',
'admintimeout-override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
}
set_method_mock.assert_called_with('system', 'accprofile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_accprofile_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_accprofile': {
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'accprofile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_accprofile_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_accprofile': {
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'accprofile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_accprofile_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_accprofile': {
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
expected_data = {
'admintimeout': '3',
'admintimeout-override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
}
set_method_mock.assert_called_with('system', 'accprofile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_accprofile_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_accprofile': {
'random_attribute_not_valid': 'tag',
'admintimeout': '3',
'admintimeout_override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_accprofile.fortios_system(input_data, fos_instance)
expected_data = {
'admintimeout': '3',
'admintimeout-override': 'enable',
'authgrp': 'none',
'comments': 'test_value_6',
'ftviewgrp': 'none',
'fwgrp': 'none',
'loggrp': 'none',
'name': 'default_name_10',
'netgrp': 'none',
'scope': 'vdom',
'secfabgrp': 'none',
'sysgrp': 'none',
'utmgrp': 'none',
'vpngrp': 'none',
'wanoptgrp': 'none',
'wifi': 'none'
}
set_method_mock.assert_called_with('system', 'accprofile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,689 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_admin
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_admin.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_admin_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_admin': {
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'accprofile-override': 'enable',
'allow-remove-admin-session': 'enable',
'comments': 'test_value_6',
'email-to': 'test_value_7',
'force-password-change': 'enable',
'fortitoken': 'test_value_9',
'guest-auth': 'disable',
'guest-lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6-trusthost1': 'test_value_15',
'ip6-trusthost10': 'test_value_16',
'ip6-trusthost2': 'test_value_17',
'ip6-trusthost3': 'test_value_18',
'ip6-trusthost4': 'test_value_19',
'ip6-trusthost5': 'test_value_20',
'ip6-trusthost6': 'test_value_21',
'ip6-trusthost7': 'test_value_22',
'ip6-trusthost8': 'test_value_23',
'ip6-trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password-expire': 'test_value_27',
'peer-auth': 'enable',
'peer-group': 'test_value_29',
'radius-vdom-override': 'enable',
'remote-auth': 'enable',
'remote-group': 'test_value_32',
'schedule': 'test_value_33',
'sms-custom-server': 'test_value_34',
'sms-phone': 'test_value_35',
'sms-server': 'fortiguard',
'ssh-certificate': 'test_value_37',
'ssh-public-key1': 'test_value_38',
'ssh-public-key2': 'test_value_39',
'ssh-public-key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two-factor': 'disable',
'wildcard': 'enable'
}
set_method_mock.assert_called_with('system', 'admin', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_admin_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_admin': {
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'accprofile-override': 'enable',
'allow-remove-admin-session': 'enable',
'comments': 'test_value_6',
'email-to': 'test_value_7',
'force-password-change': 'enable',
'fortitoken': 'test_value_9',
'guest-auth': 'disable',
'guest-lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6-trusthost1': 'test_value_15',
'ip6-trusthost10': 'test_value_16',
'ip6-trusthost2': 'test_value_17',
'ip6-trusthost3': 'test_value_18',
'ip6-trusthost4': 'test_value_19',
'ip6-trusthost5': 'test_value_20',
'ip6-trusthost6': 'test_value_21',
'ip6-trusthost7': 'test_value_22',
'ip6-trusthost8': 'test_value_23',
'ip6-trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password-expire': 'test_value_27',
'peer-auth': 'enable',
'peer-group': 'test_value_29',
'radius-vdom-override': 'enable',
'remote-auth': 'enable',
'remote-group': 'test_value_32',
'schedule': 'test_value_33',
'sms-custom-server': 'test_value_34',
'sms-phone': 'test_value_35',
'sms-server': 'fortiguard',
'ssh-certificate': 'test_value_37',
'ssh-public-key1': 'test_value_38',
'ssh-public-key2': 'test_value_39',
'ssh-public-key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two-factor': 'disable',
'wildcard': 'enable'
}
set_method_mock.assert_called_with('system', 'admin', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_admin_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_admin': {
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'admin', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_admin_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_admin': {
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'admin', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_admin_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_admin': {
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'accprofile-override': 'enable',
'allow-remove-admin-session': 'enable',
'comments': 'test_value_6',
'email-to': 'test_value_7',
'force-password-change': 'enable',
'fortitoken': 'test_value_9',
'guest-auth': 'disable',
'guest-lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6-trusthost1': 'test_value_15',
'ip6-trusthost10': 'test_value_16',
'ip6-trusthost2': 'test_value_17',
'ip6-trusthost3': 'test_value_18',
'ip6-trusthost4': 'test_value_19',
'ip6-trusthost5': 'test_value_20',
'ip6-trusthost6': 'test_value_21',
'ip6-trusthost7': 'test_value_22',
'ip6-trusthost8': 'test_value_23',
'ip6-trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password-expire': 'test_value_27',
'peer-auth': 'enable',
'peer-group': 'test_value_29',
'radius-vdom-override': 'enable',
'remote-auth': 'enable',
'remote-group': 'test_value_32',
'schedule': 'test_value_33',
'sms-custom-server': 'test_value_34',
'sms-phone': 'test_value_35',
'sms-server': 'fortiguard',
'ssh-certificate': 'test_value_37',
'ssh-public-key1': 'test_value_38',
'ssh-public-key2': 'test_value_39',
'ssh-public-key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two-factor': 'disable',
'wildcard': 'enable'
}
set_method_mock.assert_called_with('system', 'admin', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_admin_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_admin': {
'random_attribute_not_valid': 'tag',
'accprofile': 'test_value_3',
'accprofile_override': 'enable',
'allow_remove_admin_session': 'enable',
'comments': 'test_value_6',
'email_to': 'test_value_7',
'force_password_change': 'enable',
'fortitoken': 'test_value_9',
'guest_auth': 'disable',
'guest_lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6_trusthost1': 'test_value_15',
'ip6_trusthost10': 'test_value_16',
'ip6_trusthost2': 'test_value_17',
'ip6_trusthost3': 'test_value_18',
'ip6_trusthost4': 'test_value_19',
'ip6_trusthost5': 'test_value_20',
'ip6_trusthost6': 'test_value_21',
'ip6_trusthost7': 'test_value_22',
'ip6_trusthost8': 'test_value_23',
'ip6_trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password_expire': 'test_value_27',
'peer_auth': 'enable',
'peer_group': 'test_value_29',
'radius_vdom_override': 'enable',
'remote_auth': 'enable',
'remote_group': 'test_value_32',
'schedule': 'test_value_33',
'sms_custom_server': 'test_value_34',
'sms_phone': 'test_value_35',
'sms_server': 'fortiguard',
'ssh_certificate': 'test_value_37',
'ssh_public_key1': 'test_value_38',
'ssh_public_key2': 'test_value_39',
'ssh_public_key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two_factor': 'disable',
'wildcard': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_admin.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'accprofile-override': 'enable',
'allow-remove-admin-session': 'enable',
'comments': 'test_value_6',
'email-to': 'test_value_7',
'force-password-change': 'enable',
'fortitoken': 'test_value_9',
'guest-auth': 'disable',
'guest-lang': 'test_value_11',
'hidden': '12',
'history0': 'test_value_13',
'history1': 'test_value_14',
'ip6-trusthost1': 'test_value_15',
'ip6-trusthost10': 'test_value_16',
'ip6-trusthost2': 'test_value_17',
'ip6-trusthost3': 'test_value_18',
'ip6-trusthost4': 'test_value_19',
'ip6-trusthost5': 'test_value_20',
'ip6-trusthost6': 'test_value_21',
'ip6-trusthost7': 'test_value_22',
'ip6-trusthost8': 'test_value_23',
'ip6-trusthost9': 'test_value_24',
'name': 'default_name_25',
'password': 'test_value_26',
'password-expire': 'test_value_27',
'peer-auth': 'enable',
'peer-group': 'test_value_29',
'radius-vdom-override': 'enable',
'remote-auth': 'enable',
'remote-group': 'test_value_32',
'schedule': 'test_value_33',
'sms-custom-server': 'test_value_34',
'sms-phone': 'test_value_35',
'sms-server': 'fortiguard',
'ssh-certificate': 'test_value_37',
'ssh-public-key1': 'test_value_38',
'ssh-public-key2': 'test_value_39',
'ssh-public-key3': 'test_value_40',
'trusthost1': 'test_value_41',
'trusthost10': 'test_value_42',
'trusthost2': 'test_value_43',
'trusthost3': 'test_value_44',
'trusthost4': 'test_value_45',
'trusthost5': 'test_value_46',
'trusthost6': 'test_value_47',
'trusthost7': 'test_value_48',
'trusthost8': 'test_value_49',
'trusthost9': 'test_value_50',
'two-factor': 'disable',
'wildcard': 'enable'
}
set_method_mock.assert_called_with('system', 'admin', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -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_system_api_user
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_api_user.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_api_user_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_api_user': {
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'api-key': 'test_value_4',
'comments': 'test_value_5',
'cors-allow-origin': 'test_value_6',
'name': 'default_name_7',
'peer-auth': 'enable',
'peer-group': 'test_value_9',
'schedule': 'test_value_10',
}
set_method_mock.assert_called_with('system', 'api-user', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_api_user_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_api_user': {
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'api-key': 'test_value_4',
'comments': 'test_value_5',
'cors-allow-origin': 'test_value_6',
'name': 'default_name_7',
'peer-auth': 'enable',
'peer-group': 'test_value_9',
'schedule': 'test_value_10',
}
set_method_mock.assert_called_with('system', 'api-user', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_api_user_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_api_user': {
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'api-user', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_api_user_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_api_user': {
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'api-user', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_api_user_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_api_user': {
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'api-key': 'test_value_4',
'comments': 'test_value_5',
'cors-allow-origin': 'test_value_6',
'name': 'default_name_7',
'peer-auth': 'enable',
'peer-group': 'test_value_9',
'schedule': 'test_value_10',
}
set_method_mock.assert_called_with('system', 'api-user', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_api_user_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_api_user': {
'random_attribute_not_valid': 'tag',
'accprofile': 'test_value_3',
'api_key': 'test_value_4',
'comments': 'test_value_5',
'cors_allow_origin': 'test_value_6',
'name': 'default_name_7',
'peer_auth': 'enable',
'peer_group': 'test_value_9',
'schedule': 'test_value_10',
},
'vdom': 'root'}
is_error, changed, response = fortios_system_api_user.fortios_system(input_data, fos_instance)
expected_data = {
'accprofile': 'test_value_3',
'api-key': 'test_value_4',
'comments': 'test_value_5',
'cors-allow-origin': 'test_value_6',
'name': 'default_name_7',
'peer-auth': 'enable',
'peer-group': 'test_value_9',
'schedule': 'test_value_10',
}
set_method_mock.assert_called_with('system', 'api-user', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,263 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_central_management
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_central_management.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_central_management_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_central_management': {
'allow_monitor': 'enable',
'allow_push_configuration': 'enable',
'allow_push_firmware': 'enable',
'allow_remote_firmware_upgrade': 'enable',
'enc_algorithm': 'default',
'fmg': 'test_value_8',
'fmg_source_ip': 'test_value_9',
'fmg_source_ip6': 'test_value_10',
'include_default_servers': 'enable',
'mode': 'normal',
'schedule_config_restore': 'enable',
'schedule_script_restore': 'enable',
'serial_number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance)
expected_data = {
'allow-monitor': 'enable',
'allow-push-configuration': 'enable',
'allow-push-firmware': 'enable',
'allow-remote-firmware-upgrade': 'enable',
'enc-algorithm': 'default',
'fmg': 'test_value_8',
'fmg-source-ip': 'test_value_9',
'fmg-source-ip6': 'test_value_10',
'include-default-servers': 'enable',
'mode': 'normal',
'schedule-config-restore': 'enable',
'schedule-script-restore': 'enable',
'serial-number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
}
set_method_mock.assert_called_with('system', 'central-management', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_central_management_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_central_management': {
'allow_monitor': 'enable',
'allow_push_configuration': 'enable',
'allow_push_firmware': 'enable',
'allow_remote_firmware_upgrade': 'enable',
'enc_algorithm': 'default',
'fmg': 'test_value_8',
'fmg_source_ip': 'test_value_9',
'fmg_source_ip6': 'test_value_10',
'include_default_servers': 'enable',
'mode': 'normal',
'schedule_config_restore': 'enable',
'schedule_script_restore': 'enable',
'serial_number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance)
expected_data = {
'allow-monitor': 'enable',
'allow-push-configuration': 'enable',
'allow-push-firmware': 'enable',
'allow-remote-firmware-upgrade': 'enable',
'enc-algorithm': 'default',
'fmg': 'test_value_8',
'fmg-source-ip': 'test_value_9',
'fmg-source-ip6': 'test_value_10',
'include-default-servers': 'enable',
'mode': 'normal',
'schedule-config-restore': 'enable',
'schedule-script-restore': 'enable',
'serial-number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
}
set_method_mock.assert_called_with('system', 'central-management', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_central_management_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_central_management': {
'allow_monitor': 'enable',
'allow_push_configuration': 'enable',
'allow_push_firmware': 'enable',
'allow_remote_firmware_upgrade': 'enable',
'enc_algorithm': 'default',
'fmg': 'test_value_8',
'fmg_source_ip': 'test_value_9',
'fmg_source_ip6': 'test_value_10',
'include_default_servers': 'enable',
'mode': 'normal',
'schedule_config_restore': 'enable',
'schedule_script_restore': 'enable',
'serial_number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance)
expected_data = {
'allow-monitor': 'enable',
'allow-push-configuration': 'enable',
'allow-push-firmware': 'enable',
'allow-remote-firmware-upgrade': 'enable',
'enc-algorithm': 'default',
'fmg': 'test_value_8',
'fmg-source-ip': 'test_value_9',
'fmg-source-ip6': 'test_value_10',
'include-default-servers': 'enable',
'mode': 'normal',
'schedule-config-restore': 'enable',
'schedule-script-restore': 'enable',
'serial-number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
}
set_method_mock.assert_called_with('system', 'central-management', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_central_management_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_central_management': {
'random_attribute_not_valid': 'tag',
'allow_monitor': 'enable',
'allow_push_configuration': 'enable',
'allow_push_firmware': 'enable',
'allow_remote_firmware_upgrade': 'enable',
'enc_algorithm': 'default',
'fmg': 'test_value_8',
'fmg_source_ip': 'test_value_9',
'fmg_source_ip6': 'test_value_10',
'include_default_servers': 'enable',
'mode': 'normal',
'schedule_config_restore': 'enable',
'schedule_script_restore': 'enable',
'serial_number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_central_management.fortios_system(input_data, fos_instance)
expected_data = {
'allow-monitor': 'enable',
'allow-push-configuration': 'enable',
'allow-push-firmware': 'enable',
'allow-remote-firmware-upgrade': 'enable',
'enc-algorithm': 'default',
'fmg': 'test_value_8',
'fmg-source-ip': 'test_value_9',
'fmg-source-ip6': 'test_value_10',
'include-default-servers': 'enable',
'mode': 'normal',
'schedule-config-restore': 'enable',
'schedule-script-restore': 'enable',
'serial-number': 'test_value_15',
'type': 'fortimanager',
'vdom': 'test_value_17'
}
set_method_mock.assert_called_with('system', 'central-management', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,589 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_dhcp_server
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_dhcp_server.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_dhcp_server_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dhcp_server': {
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
expected_data = {
'auto-configuration': 'disable',
'conflicted-ip-timeout': '4',
'ddns-auth': 'disable',
'ddns-key': 'test_value_6',
'ddns-keyname': 'test_value_7',
'ddns-server-ip': 'test_value_8',
'ddns-ttl': '9',
'ddns-update': 'disable',
'ddns-update-override': 'disable',
'ddns-zone': 'test_value_12',
'default-gateway': 'test_value_13',
'dns-server1': 'test_value_14',
'dns-server2': 'test_value_15',
'dns-server3': 'test_value_16',
'dns-service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient-on-net-status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip-mode': 'range',
'ipsec-lease-hold': '24',
'lease-time': '25',
'mac-acl-default-action': 'assign',
'netmask': 'test_value_27',
'next-server': 'test_value_28',
'ntp-server1': 'test_value_29',
'ntp-server2': 'test_value_30',
'ntp-server3': 'test_value_31',
'ntp-service': 'local',
'server-type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone-option': 'disable',
'vci-match': 'disable',
'wifi-ac1': 'test_value_38',
'wifi-ac2': 'test_value_39',
'wifi-ac3': 'test_value_40',
'wins-server1': 'test_value_41',
'wins-server2': 'test_value_42'
}
set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_dhcp_server_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dhcp_server': {
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
expected_data = {
'auto-configuration': 'disable',
'conflicted-ip-timeout': '4',
'ddns-auth': 'disable',
'ddns-key': 'test_value_6',
'ddns-keyname': 'test_value_7',
'ddns-server-ip': 'test_value_8',
'ddns-ttl': '9',
'ddns-update': 'disable',
'ddns-update-override': 'disable',
'ddns-zone': 'test_value_12',
'default-gateway': 'test_value_13',
'dns-server1': 'test_value_14',
'dns-server2': 'test_value_15',
'dns-server3': 'test_value_16',
'dns-service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient-on-net-status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip-mode': 'range',
'ipsec-lease-hold': '24',
'lease-time': '25',
'mac-acl-default-action': 'assign',
'netmask': 'test_value_27',
'next-server': 'test_value_28',
'ntp-server1': 'test_value_29',
'ntp-server2': 'test_value_30',
'ntp-server3': 'test_value_31',
'ntp-service': 'local',
'server-type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone-option': 'disable',
'vci-match': 'disable',
'wifi-ac1': 'test_value_38',
'wifi-ac2': 'test_value_39',
'wifi-ac3': 'test_value_40',
'wins-server1': 'test_value_41',
'wins-server2': 'test_value_42'
}
set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_dhcp_server_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_dhcp_server': {
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
delete_method_mock.assert_called_with('system.dhcp', 'server', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_dhcp_server_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_dhcp_server': {
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
delete_method_mock.assert_called_with('system.dhcp', 'server', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_dhcp_server_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dhcp_server': {
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
expected_data = {
'auto-configuration': 'disable',
'conflicted-ip-timeout': '4',
'ddns-auth': 'disable',
'ddns-key': 'test_value_6',
'ddns-keyname': 'test_value_7',
'ddns-server-ip': 'test_value_8',
'ddns-ttl': '9',
'ddns-update': 'disable',
'ddns-update-override': 'disable',
'ddns-zone': 'test_value_12',
'default-gateway': 'test_value_13',
'dns-server1': 'test_value_14',
'dns-server2': 'test_value_15',
'dns-server3': 'test_value_16',
'dns-service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient-on-net-status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip-mode': 'range',
'ipsec-lease-hold': '24',
'lease-time': '25',
'mac-acl-default-action': 'assign',
'netmask': 'test_value_27',
'next-server': 'test_value_28',
'ntp-server1': 'test_value_29',
'ntp-server2': 'test_value_30',
'ntp-server3': 'test_value_31',
'ntp-service': 'local',
'server-type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone-option': 'disable',
'vci-match': 'disable',
'wifi-ac1': 'test_value_38',
'wifi-ac2': 'test_value_39',
'wifi-ac3': 'test_value_40',
'wins-server1': 'test_value_41',
'wins-server2': 'test_value_42'
}
set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_dhcp_server_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dhcp_server': {
'random_attribute_not_valid': 'tag',
'auto_configuration': 'disable',
'conflicted_ip_timeout': '4',
'ddns_auth': 'disable',
'ddns_key': 'test_value_6',
'ddns_keyname': 'test_value_7',
'ddns_server_ip': 'test_value_8',
'ddns_ttl': '9',
'ddns_update': 'disable',
'ddns_update_override': 'disable',
'ddns_zone': 'test_value_12',
'default_gateway': 'test_value_13',
'dns_server1': 'test_value_14',
'dns_server2': 'test_value_15',
'dns_server3': 'test_value_16',
'dns_service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient_on_net_status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip_mode': 'range',
'ipsec_lease_hold': '24',
'lease_time': '25',
'mac_acl_default_action': 'assign',
'netmask': 'test_value_27',
'next_server': 'test_value_28',
'ntp_server1': 'test_value_29',
'ntp_server2': 'test_value_30',
'ntp_server3': 'test_value_31',
'ntp_service': 'local',
'server_type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone_option': 'disable',
'vci_match': 'disable',
'wifi_ac1': 'test_value_38',
'wifi_ac2': 'test_value_39',
'wifi_ac3': 'test_value_40',
'wins_server1': 'test_value_41',
'wins_server2': 'test_value_42'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dhcp_server.fortios_system_dhcp(input_data, fos_instance)
expected_data = {
'auto-configuration': 'disable',
'conflicted-ip-timeout': '4',
'ddns-auth': 'disable',
'ddns-key': 'test_value_6',
'ddns-keyname': 'test_value_7',
'ddns-server-ip': 'test_value_8',
'ddns-ttl': '9',
'ddns-update': 'disable',
'ddns-update-override': 'disable',
'ddns-zone': 'test_value_12',
'default-gateway': 'test_value_13',
'dns-server1': 'test_value_14',
'dns-server2': 'test_value_15',
'dns-server3': 'test_value_16',
'dns-service': 'local',
'domain': 'test_value_18',
'filename': 'test_value_19',
'forticlient-on-net-status': 'disable',
'id': '21',
'interface': 'test_value_22',
'ip-mode': 'range',
'ipsec-lease-hold': '24',
'lease-time': '25',
'mac-acl-default-action': 'assign',
'netmask': 'test_value_27',
'next-server': 'test_value_28',
'ntp-server1': 'test_value_29',
'ntp-server2': 'test_value_30',
'ntp-server3': 'test_value_31',
'ntp-service': 'local',
'server-type': 'regular',
'status': 'disable',
'timezone': '01',
'timezone-option': 'disable',
'vci-match': 'disable',
'wifi-ac1': 'test_value_38',
'wifi-ac2': 'test_value_39',
'wifi-ac3': 'test_value_40',
'wins-server1': 'test_value_41',
'wins-server2': 'test_value_42'
}
set_method_mock.assert_called_with('system.dhcp', 'server', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,223 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_dns
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_dns.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_dns_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dns': {
'cache_notfound_responses': 'disable',
'dns_cache_limit': '4',
'dns_cache_ttl': '5',
'ip6_primary': 'test_value_6',
'ip6_secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source_ip': '84.230.14.11',
'timeout': '12'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance)
expected_data = {
'cache-notfound-responses': 'disable',
'dns-cache-limit': '4',
'dns-cache-ttl': '5',
'ip6-primary': 'test_value_6',
'ip6-secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source-ip': '84.230.14.11',
'timeout': '12'
}
set_method_mock.assert_called_with('system', 'dns', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_dns_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dns': {
'cache_notfound_responses': 'disable',
'dns_cache_limit': '4',
'dns_cache_ttl': '5',
'ip6_primary': 'test_value_6',
'ip6_secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source_ip': '84.230.14.11',
'timeout': '12'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance)
expected_data = {
'cache-notfound-responses': 'disable',
'dns-cache-limit': '4',
'dns-cache-ttl': '5',
'ip6-primary': 'test_value_6',
'ip6-secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source-ip': '84.230.14.11',
'timeout': '12'
}
set_method_mock.assert_called_with('system', 'dns', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_dns_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dns': {
'cache_notfound_responses': 'disable',
'dns_cache_limit': '4',
'dns_cache_ttl': '5',
'ip6_primary': 'test_value_6',
'ip6_secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source_ip': '84.230.14.11',
'timeout': '12'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance)
expected_data = {
'cache-notfound-responses': 'disable',
'dns-cache-limit': '4',
'dns-cache-ttl': '5',
'ip6-primary': 'test_value_6',
'ip6-secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source-ip': '84.230.14.11',
'timeout': '12'
}
set_method_mock.assert_called_with('system', 'dns', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_dns_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_dns': {
'random_attribute_not_valid': 'tag',
'cache_notfound_responses': 'disable',
'dns_cache_limit': '4',
'dns_cache_ttl': '5',
'ip6_primary': 'test_value_6',
'ip6_secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source_ip': '84.230.14.11',
'timeout': '12'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_dns.fortios_system(input_data, fos_instance)
expected_data = {
'cache-notfound-responses': 'disable',
'dns-cache-limit': '4',
'dns-cache-ttl': '5',
'ip6-primary': 'test_value_6',
'ip6-secondary': 'test_value_7',
'primary': 'test_value_8',
'retry': '9',
'secondary': 'test_value_10',
'source-ip': '84.230.14.11',
'timeout': '12'
}
set_method_mock.assert_called_with('system', 'dns', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,489 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_sdn_connector
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_sdn_connector.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_sdn_connector_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_sdn_connector': {
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
expected_data = {
'access-key': 'test_value_3',
'azure-region': 'global',
'client-id': 'test_value_5',
'client-secret': 'test_value_6',
'compartment-id': 'test_value_7',
'gcp-project': 'test_value_8',
'key-passwd': 'test_value_9',
'login-endpoint': 'test_value_10',
'name': 'default_name_11',
'oci-cert': 'test_value_12',
'oci-fingerprint': 'test_value_13',
'oci-region': 'phoenix',
'password': 'test_value_15',
'private-key': 'test_value_16',
'region': 'test_value_17',
'resource-group': 'test_value_18',
'resource-url': 'test_value_19',
'secret-key': 'test_value_20',
'server': '192.168.100.21',
'server-port': '22',
'service-account': 'test_value_23',
'status': 'disable',
'subscription-id': 'test_value_25',
'tenant-id': 'test_value_26',
'type': 'aci',
'update-interval': '28',
'use-metadata-iam': 'disable',
'user-id': 'test_value_30',
'username': 'test_value_31',
'vpc-id': 'test_value_32'
}
set_method_mock.assert_called_with('system', 'sdn-connector', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_sdn_connector_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_sdn_connector': {
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
expected_data = {
'access-key': 'test_value_3',
'azure-region': 'global',
'client-id': 'test_value_5',
'client-secret': 'test_value_6',
'compartment-id': 'test_value_7',
'gcp-project': 'test_value_8',
'key-passwd': 'test_value_9',
'login-endpoint': 'test_value_10',
'name': 'default_name_11',
'oci-cert': 'test_value_12',
'oci-fingerprint': 'test_value_13',
'oci-region': 'phoenix',
'password': 'test_value_15',
'private-key': 'test_value_16',
'region': 'test_value_17',
'resource-group': 'test_value_18',
'resource-url': 'test_value_19',
'secret-key': 'test_value_20',
'server': '192.168.100.21',
'server-port': '22',
'service-account': 'test_value_23',
'status': 'disable',
'subscription-id': 'test_value_25',
'tenant-id': 'test_value_26',
'type': 'aci',
'update-interval': '28',
'use-metadata-iam': 'disable',
'user-id': 'test_value_30',
'username': 'test_value_31',
'vpc-id': 'test_value_32'
}
set_method_mock.assert_called_with('system', 'sdn-connector', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_sdn_connector_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_sdn_connector': {
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'sdn-connector', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_sdn_connector_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_sdn_connector': {
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'sdn-connector', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_sdn_connector_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_sdn_connector': {
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
expected_data = {
'access-key': 'test_value_3',
'azure-region': 'global',
'client-id': 'test_value_5',
'client-secret': 'test_value_6',
'compartment-id': 'test_value_7',
'gcp-project': 'test_value_8',
'key-passwd': 'test_value_9',
'login-endpoint': 'test_value_10',
'name': 'default_name_11',
'oci-cert': 'test_value_12',
'oci-fingerprint': 'test_value_13',
'oci-region': 'phoenix',
'password': 'test_value_15',
'private-key': 'test_value_16',
'region': 'test_value_17',
'resource-group': 'test_value_18',
'resource-url': 'test_value_19',
'secret-key': 'test_value_20',
'server': '192.168.100.21',
'server-port': '22',
'service-account': 'test_value_23',
'status': 'disable',
'subscription-id': 'test_value_25',
'tenant-id': 'test_value_26',
'type': 'aci',
'update-interval': '28',
'use-metadata-iam': 'disable',
'user-id': 'test_value_30',
'username': 'test_value_31',
'vpc-id': 'test_value_32'
}
set_method_mock.assert_called_with('system', 'sdn-connector', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_sdn_connector_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_sdn_connector': {
'random_attribute_not_valid': 'tag',
'access_key': 'test_value_3',
'azure_region': 'global',
'client_id': 'test_value_5',
'client_secret': 'test_value_6',
'compartment_id': 'test_value_7',
'gcp_project': 'test_value_8',
'key_passwd': 'test_value_9',
'login_endpoint': 'test_value_10',
'name': 'default_name_11',
'oci_cert': 'test_value_12',
'oci_fingerprint': 'test_value_13',
'oci_region': 'phoenix',
'password': 'test_value_15',
'private_key': 'test_value_16',
'region': 'test_value_17',
'resource_group': 'test_value_18',
'resource_url': 'test_value_19',
'secret_key': 'test_value_20',
'server': '192.168.100.21',
'server_port': '22',
'service_account': 'test_value_23',
'status': 'disable',
'subscription_id': 'test_value_25',
'tenant_id': 'test_value_26',
'type': 'aci',
'update_interval': '28',
'use_metadata_iam': 'disable',
'user_id': 'test_value_30',
'username': 'test_value_31',
'vpc_id': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_sdn_connector.fortios_system(input_data, fos_instance)
expected_data = {
'access-key': 'test_value_3',
'azure-region': 'global',
'client-id': 'test_value_5',
'client-secret': 'test_value_6',
'compartment-id': 'test_value_7',
'gcp-project': 'test_value_8',
'key-passwd': 'test_value_9',
'login-endpoint': 'test_value_10',
'name': 'default_name_11',
'oci-cert': 'test_value_12',
'oci-fingerprint': 'test_value_13',
'oci-region': 'phoenix',
'password': 'test_value_15',
'private-key': 'test_value_16',
'region': 'test_value_17',
'resource-group': 'test_value_18',
'resource-url': 'test_value_19',
'secret-key': 'test_value_20',
'server': '192.168.100.21',
'server-port': '22',
'service-account': 'test_value_23',
'status': 'disable',
'subscription-id': 'test_value_25',
'tenant-id': 'test_value_26',
'type': 'aci',
'update-interval': '28',
'use-metadata-iam': 'disable',
'user-id': 'test_value_30',
'username': 'test_value_31',
'vpc-id': 'test_value_32'
}
set_method_mock.assert_called_with('system', 'sdn-connector', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,229 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_vdom
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_vdom.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_vdom_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_vdom': {
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'short-name': 'test_value_4',
'temporary': '5',
'vcluster-id': '6'
}
set_method_mock.assert_called_with('system', 'vdom', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_vdom_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_vdom': {
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'short-name': 'test_value_4',
'temporary': '5',
'vcluster-id': '6'
}
set_method_mock.assert_called_with('system', 'vdom', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_vdom_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_vdom': {
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'vdom', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_vdom_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'system_vdom': {
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
delete_method_mock.assert_called_with('system', 'vdom', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_vdom_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_vdom': {
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'short-name': 'test_value_4',
'temporary': '5',
'vcluster-id': '6'
}
set_method_mock.assert_called_with('system', 'vdom', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_vdom_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_vdom': {
'random_attribute_not_valid': 'tag',
'name': 'default_name_3',
'short_name': 'test_value_4',
'temporary': '5',
'vcluster_id': '6'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_vdom.fortios_system(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'short-name': 'test_value_4',
'temporary': '5',
'vcluster-id': '6'
}
set_method_mock.assert_called_with('system', 'vdom', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,159 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_system_virtual_wan_link
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_virtual_wan_link.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_system_virtual_wan_link_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_virtual_wan_link': {'fail_detect': 'enable',
'load_balance_mode': 'source-ip-based',
'status': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance)
expected_data = {'fail-detect': 'enable',
'load-balance-mode': 'source-ip-based',
'status': 'disable'
}
set_method_mock.assert_called_with('system', 'virtual-wan-link', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_system_virtual_wan_link_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_virtual_wan_link': {'fail_detect': 'enable',
'load_balance_mode': 'source-ip-based',
'status': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance)
expected_data = {'fail-detect': 'enable',
'load-balance-mode': 'source-ip-based',
'status': 'disable'
}
set_method_mock.assert_called_with('system', 'virtual-wan-link', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_system_virtual_wan_link_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_virtual_wan_link': {'fail_detect': 'enable',
'load_balance_mode': 'source-ip-based',
'status': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance)
expected_data = {'fail-detect': 'enable',
'load-balance-mode': 'source-ip-based',
'status': 'disable'
}
set_method_mock.assert_called_with('system', 'virtual-wan-link', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_system_virtual_wan_link_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'system_virtual_wan_link': {
'random_attribute_not_valid': 'tag', 'fail_detect': 'enable',
'load_balance_mode': 'source-ip-based',
'status': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_system_virtual_wan_link.fortios_system(input_data, fos_instance)
expected_data = {'fail-detect': 'enable',
'load-balance-mode': 'source-ip-based',
'status': 'disable'
}
set_method_mock.assert_called_with('system', 'virtual-wan-link', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
Loading…
Cancel
Save