FortiOS modules for 2.9 - 8 (#61308)

* FortiOS modules for 2.9 - 8

* Add missing files

* Fix trailing spaces
pull/61322/head
Miguel Angel Muñoz González 5 years ago committed by Nilashish Chakraborty
parent f3f30c146b
commit 69fcd771e0

@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_report_layout
short_description: Report layout configuration in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify report feature and layout category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,50 +41,66 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: 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
report_layout:
description:
- Report layout configuration.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
body-item:
body_item:
description:
- Configure report body item.
type: list
suboptions:
chart:
description:
- Report item chart name.
chart-options:
type: str
chart_options:
description:
- Report chart options.
type: str
choices:
- include-no-data
- hide-title
@ -95,21 +108,27 @@ options:
column:
description:
- Report section column number.
type: int
content:
description:
- Report item text content.
type: str
description:
description:
- Description.
drill-down-items:
type: str
drill_down_items:
description:
- Control how drill down charts are shown.
drill-down-types:
type: str
drill_down_types:
description:
- Control whether keys from the parent being combined or not.
type: str
hide:
description:
- Enable/disable hide item in report.
type: str
choices:
- enable
- disable
@ -117,29 +136,36 @@ options:
description:
- Report item ID.
required: true
img-src:
type: int
img_src:
description:
- Report item image file name.
type: str
list:
description:
- Configure report list item.
type: list
suboptions:
content:
description:
- List entry content.
type: str
id:
description:
- List entry ID.
required: true
list-component:
type: int
list_component:
description:
- Report item list component.
type: str
choices:
- bullet
- numbered
misc-component:
misc_component:
description:
- Report item miscellaneous component.
type: str
choices:
- hline
- page-break
@ -148,38 +174,49 @@ options:
parameters:
description:
- Parameters.
type: list
suboptions:
id:
description:
- ID.
required: true
type: int
name:
description:
- Field name that match field of parameters defined in dataset.
type: str
value:
description:
- Value to replace corresponding field of parameters defined in dataset.
type: str
style:
description:
- Report item style.
table-caption-style:
type: str
table_caption_style:
description:
- Table chart caption style.
table-column-widths:
type: str
table_column_widths:
description:
- Report item table column widths.
table-even-row-style:
type: str
table_even_row_style:
description:
- Table chart even row style.
table-head-style:
type: str
table_head_style:
description:
- Table chart head style.
table-odd-row-style:
type: str
table_odd_row_style:
description:
- Table chart odd row style.
text-component:
type: str
text_component:
description:
- Report item text component.
type: str
choices:
- text
- heading1
@ -188,29 +225,35 @@ options:
title:
description:
- Report section title.
top-n:
type: str
top_n:
description:
- Value of top.
type: int
type:
description:
- Report item type.
type: str
choices:
- text
- image
- chart
- misc
cutoff-option:
cutoff_option:
description:
- Cutoff-option is either run-time or custom.
type: str
choices:
- run-time
- custom
cutoff-time:
cutoff_time:
description:
- "Custom cutoff time to generate report [hh:mm]."
type: str
day:
description:
- Schedule days of week to generate report.
type: str
choices:
- sunday
- monday
@ -222,30 +265,37 @@ options:
description:
description:
- Description.
email-recipients:
type: str
email_recipients:
description:
- Email recipients for generated reports.
email-send:
type: str
email_send:
description:
- Enable/disable sending emails after reports are generated.
type: str
choices:
- enable
- disable
format:
description:
- Report format.
type: str
choices:
- pdf
max-pdf-report:
max_pdf_report:
description:
- Maximum number of PDF reports to keep at one time (oldest report is overwritten).
type: int
name:
description:
- Report layout name.
required: true
type: str
options:
description:
- Report layout options.
type: str
choices:
- include-table-of-content
- auto-numbering-heading
@ -255,10 +305,12 @@ options:
page:
description:
- Configure report page.
type: dict
suboptions:
column-break-before:
column_break_before:
description:
- Report page auto column break before heading.
type: str
choices:
- heading1
- heading2
@ -266,78 +318,98 @@ options:
footer:
description:
- Configure report page footer.
type: dict
suboptions:
footer-item:
footer_item:
description:
- Configure report footer item.
type: list
suboptions:
content:
description:
- Report item text content.
type: str
description:
description:
- Description.
type: str
id:
description:
- Report item ID.
required: true
img-src:
type: int
img_src:
description:
- Report item image file name.
type: str
style:
description:
- Report item style.
type: str
type:
description:
- Report item type.
type: str
choices:
- text
- image
style:
description:
- Report footer style.
type: str
header:
description:
- Configure report page header.
type: dict
suboptions:
header-item:
header_item:
description:
- Configure report header item.
type: list
suboptions:
content:
description:
- Report item text content.
type: str
description:
description:
- Description.
type: str
id:
description:
- Report item ID.
required: true
img-src:
type: int
img_src:
description:
- Report item image file name.
type: str
style:
description:
- Report item style.
type: str
type:
description:
- Report item type.
type: str
choices:
- text
- image
style:
description:
- Report header style.
type: str
options:
description:
- Report page options.
type: str
choices:
- header-on-first-page
- footer-on-first-page
page-break-before:
page_break_before:
description:
- Report page auto page break before heading.
type: str
choices:
- heading1
- heading2
@ -345,28 +417,34 @@ options:
paper:
description:
- Report page paper.
type: str
choices:
- a4
- letter
schedule-type:
schedule_type:
description:
- Report schedule type.
type: str
choices:
- demand
- daily
- weekly
style-theme:
style_theme:
description:
- Report style theme.
type: str
subtitle:
description:
- Report subtitle.
type: str
time:
description:
- "Schedule time to generate report [hh:mm]."
type: str
title:
description:
- Report title.
type: str
'''
EXAMPLES = '''
@ -376,6 +454,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Report layout configuration.
fortios_report_layout:
@ -384,78 +463,78 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
report_layout:
state: "present"
body-item:
body_item:
-
chart: "<your_own_value>"
chart-options: "include-no-data"
chart_options: "include-no-data"
column: "6"
content: "<your_own_value>"
description: "<your_own_value>"
drill-down-items: "<your_own_value>"
drill-down-types: "<your_own_value>"
drill_down_items: "<your_own_value>"
drill_down_types: "<your_own_value>"
hide: "enable"
id: "12"
img-src: "<your_own_value>"
img_src: "<your_own_value>"
list:
-
content: "<your_own_value>"
id: "16"
list-component: "bullet"
misc-component: "hline"
list_component: "bullet"
misc_component: "hline"
parameters:
-
id: "20"
name: "default_name_21"
value: "<your_own_value>"
style: "<your_own_value>"
table-caption-style: "<your_own_value>"
table-column-widths: "<your_own_value>"
table-even-row-style: "<your_own_value>"
table-head-style: "<your_own_value>"
table-odd-row-style: "<your_own_value>"
text-component: "text"
table_caption_style: "<your_own_value>"
table_column_widths: "<your_own_value>"
table_even_row_style: "<your_own_value>"
table_head_style: "<your_own_value>"
table_odd_row_style: "<your_own_value>"
text_component: "text"
title: "<your_own_value>"
top-n: "31"
top_n: "31"
type: "text"
cutoff-option: "run-time"
cutoff-time: "<your_own_value>"
cutoff_option: "run-time"
cutoff_time: "<your_own_value>"
day: "sunday"
description: "<your_own_value>"
email-recipients: "<your_own_value>"
email-send: "enable"
email_recipients: "<your_own_value>"
email_send: "enable"
format: "pdf"
max-pdf-report: "40"
max_pdf_report: "40"
name: "default_name_41"
options: "include-table-of-content"
page:
column-break-before: "heading1"
column_break_before: "heading1"
footer:
footer-item:
footer_item:
-
content: "<your_own_value>"
description: "<your_own_value>"
id: "49"
img-src: "<your_own_value>"
img_src: "<your_own_value>"
style: "<your_own_value>"
type: "text"
style: "<your_own_value>"
header:
header-item:
header_item:
-
content: "<your_own_value>"
description: "<your_own_value>"
id: "58"
img-src: "<your_own_value>"
img_src: "<your_own_value>"
style: "<your_own_value>"
type: "text"
style: "<your_own_value>"
options: "header-on-first-page"
page-break-before: "heading1"
page_break_before: "heading1"
paper: "a4"
schedule-type: "demand"
style-theme: "<your_own_value>"
schedule_type: "demand"
style_theme: "<your_own_value>"
subtitle: "<your_own_value>"
time: "<your_own_value>"
title: "<your_own_value>"
@ -521,14 +600,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -536,15 +617,15 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_report_layout_data(json):
option_list = ['body-item', 'cutoff-option', 'cutoff-time',
'day', 'description', 'email-recipients',
'email-send', 'format', 'max-pdf-report',
option_list = ['body_item', 'cutoff_option', 'cutoff_time',
'day', 'description', 'email_recipients',
'email_send', 'format', 'max_pdf_report',
'name', 'options', 'page',
'schedule-type', 'style-theme', 'subtitle',
'schedule_type', 'style_theme', 'subtitle',
'time', 'title']
dictionary = {}
@ -555,83 +636,88 @@ def filter_report_layout_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def report_layout(data, fos):
vdom = data['vdom']
state = data['state']
report_layout_data = data['report_layout']
flattened_data = flatten_multilists_attributes(report_layout_data)
filtered_data = filter_report_layout_data(flattened_data)
if report_layout_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_report_layout_data(report_layout_data))
if state == "present":
return fos.set('report',
'layout',
data=filtered_data,
vdom=vdom)
elif report_layout_data['state'] == "absent":
elif state == "absent":
return fos.delete('report',
'layout',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_report(data, fos):
login(data)
if data['report_layout']:
resp = report_layout(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"report_layout": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"body-item": {"required": False, "type": "list",
"body_item": {"required": False, "type": "list",
"options": {
"chart": {"required": False, "type": "str"},
"chart-options": {"required": False, "type": "str",
"chart_options": {"required": False, "type": "str",
"choices": ["include-no-data", "hide-title", "show-caption"]},
"column": {"required": False, "type": "int"},
"content": {"required": False, "type": "str"},
"description": {"required": False, "type": "str"},
"drill-down-items": {"required": False, "type": "str"},
"drill-down-types": {"required": False, "type": "str"},
"drill_down_items": {"required": False, "type": "str"},
"drill_down_types": {"required": False, "type": "str"},
"hide": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"id": {"required": True, "type": "int"},
"img-src": {"required": False, "type": "str"},
"img_src": {"required": False, "type": "str"},
"list": {"required": False, "type": "list",
"options": {
"content": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"}
}},
"list-component": {"required": False, "type": "str",
"list_component": {"required": False, "type": "str",
"choices": ["bullet", "numbered"]},
"misc-component": {"required": False, "type": "str",
"misc_component": {"required": False, "type": "str",
"choices": ["hline", "page-break", "column-break",
"section-start"]},
"parameters": {"required": False, "type": "list",
@ -641,50 +727,50 @@ def main():
"value": {"required": False, "type": "str"}
}},
"style": {"required": False, "type": "str"},
"table-caption-style": {"required": False, "type": "str"},
"table-column-widths": {"required": False, "type": "str"},
"table-even-row-style": {"required": False, "type": "str"},
"table-head-style": {"required": False, "type": "str"},
"table-odd-row-style": {"required": False, "type": "str"},
"text-component": {"required": False, "type": "str",
"table_caption_style": {"required": False, "type": "str"},
"table_column_widths": {"required": False, "type": "str"},
"table_even_row_style": {"required": False, "type": "str"},
"table_head_style": {"required": False, "type": "str"},
"table_odd_row_style": {"required": False, "type": "str"},
"text_component": {"required": False, "type": "str",
"choices": ["text", "heading1", "heading2",
"heading3"]},
"title": {"required": False, "type": "str"},
"top-n": {"required": False, "type": "int"},
"top_n": {"required": False, "type": "int"},
"type": {"required": False, "type": "str",
"choices": ["text", "image", "chart",
"misc"]}
}},
"cutoff-option": {"required": False, "type": "str",
"cutoff_option": {"required": False, "type": "str",
"choices": ["run-time", "custom"]},
"cutoff-time": {"required": False, "type": "str"},
"cutoff_time": {"required": False, "type": "str"},
"day": {"required": False, "type": "str",
"choices": ["sunday", "monday", "tuesday",
"wednesday", "thursday", "friday",
"saturday"]},
"description": {"required": False, "type": "str"},
"email-recipients": {"required": False, "type": "str"},
"email-send": {"required": False, "type": "str",
"email_recipients": {"required": False, "type": "str"},
"email_send": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"format": {"required": False, "type": "str",
"choices": ["pdf"]},
"max-pdf-report": {"required": False, "type": "int"},
"max_pdf_report": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"},
"options": {"required": False, "type": "str",
"choices": ["include-table-of-content", "auto-numbering-heading", "view-chart-as-heading",
"show-html-navbar-before-heading", "dummy-option"]},
"page": {"required": False, "type": "dict",
"options": {
"column-break-before": {"required": False, "type": "str",
"column_break_before": {"required": False, "type": "str",
"choices": ["heading1", "heading2", "heading3"]},
"footer": {"required": False, "type": "dict",
"options": {
"footer-item": {"required": False, "type": "list",
"footer_item": {"required": False, "type": "list",
"options": {
"content": {"required": False, "type": "str"},
"description": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"img-src": {"required": False, "type": "str"},
"img_src": {"required": False, "type": "str"},
"style": {"required": False, "type": "str"},
"type": {"required": False, "type": "str",
"choices": ["text", "image"]}
@ -693,12 +779,12 @@ def main():
}},
"header": {"required": False, "type": "dict",
"options": {
"header-item": {"required": False, "type": "list",
"header_item": {"required": False, "type": "list",
"options": {
"content": {"required": False, "type": "str"},
"description": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"img-src": {"required": False, "type": "str"},
"img_src": {"required": False, "type": "str"},
"style": {"required": False, "type": "str"},
"type": {"required": False, "type": "str",
"choices": ["text", "image"]}
@ -707,14 +793,14 @@ def main():
}},
"options": {"required": False, "type": "str",
"choices": ["header-on-first-page", "footer-on-first-page"]},
"page-break-before": {"required": False, "type": "str",
"page_break_before": {"required": False, "type": "str",
"choices": ["heading1", "heading2", "heading3"]},
"paper": {"required": False, "type": "str",
"choices": ["a4", "letter"]}
}},
"schedule-type": {"required": False, "type": "str",
"schedule_type": {"required": False, "type": "str",
"choices": ["demand", "daily", "weekly"]},
"style-theme": {"required": False, "type": "str"},
"style_theme": {"required": False, "type": "str"},
"subtitle": {"required": False, "type": "str"},
"time": {"required": False, "type": "str"},
"title": {"required": False, "type": "str"}
@ -725,15 +811,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_report(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_report(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_report(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_report_setting
short_description: Report setting configuration in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify report feature and setting category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,59 +41,74 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
report_setting:
description:
- Report setting configuration.
default: null
type: dict
suboptions:
fortiview:
description:
- Enable/disable historical FortiView.
type: str
choices:
- enable
- disable
pdf-report:
pdf_report:
description:
- Enable/disable PDF report.
type: str
choices:
- enable
- disable
report-source:
report_source:
description:
- Report log source.
type: str
choices:
- forward-traffic
- sniffer-traffic
- local-deny-traffic
top-n:
top_n:
description:
- Number of items to populate (100 - 4000).
web-browsing-threshold:
type: int
web_browsing_threshold:
description:
- Web browsing time calculation threshold (3 - 15 min).
type: int
'''
EXAMPLES = '''
@ -106,6 +118,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Report setting configuration.
fortios_report_setting:
@ -116,10 +129,10 @@ EXAMPLES = '''
https: "False"
report_setting:
fortiview: "enable"
pdf-report: "enable"
report-source: "forward-traffic"
top-n: "6"
web-browsing-threshold: "7"
pdf_report: "enable"
report_source: "forward-traffic"
top_n: "6"
web_browsing_threshold: "7"
'''
RETURN = '''
@ -182,14 +195,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -197,12 +212,12 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_report_setting_data(json):
option_list = ['fortiview', 'pdf-report', 'report-source',
'top-n', 'web-browsing-threshold']
option_list = ['fortiview', 'pdf_report', 'report_source',
'top_n', 'web_browsing_threshold']
dictionary = {}
for attribute in option_list:
@ -212,17 +227,15 @@ def filter_report_setting_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -230,42 +243,48 @@ def flatten_multilists_attributes(data):
def report_setting(data, fos):
vdom = data['vdom']
report_setting_data = data['report_setting']
flattened_data = flatten_multilists_attributes(report_setting_data)
filtered_data = filter_report_setting_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_report_setting_data(report_setting_data))
return fos.set('report',
'setting',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_report(data, fos):
login(data)
if data['report_setting']:
resp = report_setting(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"report_setting": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"fortiview": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"pdf-report": {"required": False, "type": "str",
"pdf_report": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"report-source": {"required": False, "type": "str",
"report_source": {"required": False, "type": "str",
"choices": ["forward-traffic", "sniffer-traffic", "local-deny-traffic"]},
"top-n": {"required": False, "type": "int"},
"web-browsing-threshold": {"required": False, "type": "int"}
"top_n": {"required": False, "type": "int"},
"web_browsing_threshold": {"required": False, "type": "int"}
}
}
@ -273,15 +292,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_report(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_report(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_report(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_report_style
short_description: Report style configuration in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify report feature and style category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,124 +41,158 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
report_style:
description:
- Report style configuration.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
align:
description:
- Alignment.
type: str
choices:
- left
- center
- right
- justify
bg-color:
bg_color:
description:
- Background color.
border-bottom:
type: str
border_bottom:
description:
- Border bottom.
border-left:
type: str
border_left:
description:
- Border left.
border-right:
type: str
border_right:
description:
- Border right.
border-top:
type: str
border_top:
description:
- Border top.
column-gap:
type: str
column_gap:
description:
- Column gap.
column-span:
type: str
column_span:
description:
- Column span.
type: str
choices:
- none
- all
fg-color:
fg_color:
description:
- Foreground color.
font-family:
type: str
font_family:
description:
- Font family.
type: str
choices:
- Verdana
- Arial
- Helvetica
- Courier
- Times
font-size:
font_size:
description:
- Font size.
font-style:
type: str
font_style:
description:
- Font style.
type: str
choices:
- normal
- italic
font-weight:
font_weight:
description:
- Font weight.
type: str
choices:
- normal
- bold
height:
description:
- Height.
line-height:
type: str
line_height:
description:
- Text line height.
margin-bottom:
type: str
margin_bottom:
description:
- Margin bottom.
margin-left:
type: str
margin_left:
description:
- Margin left.
margin-right:
type: str
margin_right:
description:
- Margin right.
margin-top:
type: str
margin_top:
description:
- Margin top.
type: str
name:
description:
- Report style name.
required: true
type: str
options:
description:
- Report style options.
type: str
choices:
- font
- text
@ -172,21 +203,26 @@ options:
- border
- padding
- column
padding-bottom:
padding_bottom:
description:
- Padding bottom.
padding-left:
type: str
padding_left:
description:
- Padding left.
padding-right:
type: str
padding_right:
description:
- Padding right.
padding-top:
type: str
padding_top:
description:
- Padding top.
type: str
width:
description:
- Width.
type: str
'''
EXAMPLES = '''
@ -196,6 +232,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Report style configuration.
fortios_report_style:
@ -204,33 +241,33 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
report_style:
state: "present"
align: "left"
bg-color: "<your_own_value>"
border-bottom: "<your_own_value>"
border-left: "<your_own_value>"
border-right: "<your_own_value>"
border-top: "<your_own_value>"
column-gap: "<your_own_value>"
column-span: "none"
fg-color: "<your_own_value>"
font-family: "Verdana"
font-size: "<your_own_value>"
font-style: "normal"
font-weight: "normal"
bg_color: "<your_own_value>"
border_bottom: "<your_own_value>"
border_left: "<your_own_value>"
border_right: "<your_own_value>"
border_top: "<your_own_value>"
column_gap: "<your_own_value>"
column_span: "none"
fg_color: "<your_own_value>"
font_family: "Verdana"
font_size: "<your_own_value>"
font_style: "normal"
font_weight: "normal"
height: "<your_own_value>"
line-height: "<your_own_value>"
margin-bottom: "<your_own_value>"
margin-left: "<your_own_value>"
margin-right: "<your_own_value>"
margin-top: "<your_own_value>"
line_height: "<your_own_value>"
margin_bottom: "<your_own_value>"
margin_left: "<your_own_value>"
margin_right: "<your_own_value>"
margin_top: "<your_own_value>"
name: "default_name_22"
options: "font"
padding-bottom: "<your_own_value>"
padding-left: "<your_own_value>"
padding-right: "<your_own_value>"
padding-top: "<your_own_value>"
padding_bottom: "<your_own_value>"
padding_left: "<your_own_value>"
padding_right: "<your_own_value>"
padding_top: "<your_own_value>"
width: "<your_own_value>"
'''
@ -294,14 +331,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -309,19 +348,19 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_report_style_data(json):
option_list = ['align', 'bg-color', 'border-bottom',
'border-left', 'border-right', 'border-top',
'column-gap', 'column-span', 'fg-color',
'font-family', 'font-size', 'font-style',
'font-weight', 'height', 'line-height',
'margin-bottom', 'margin-left', 'margin-right',
'margin-top', 'name', 'options',
'padding-bottom', 'padding-left', 'padding-right',
'padding-top', 'width']
option_list = ['align', 'bg_color', 'border_bottom',
'border_left', 'border_right', 'border_top',
'column_gap', 'column_span', 'fg_color',
'font_family', 'font_size', 'font_style',
'font_weight', 'height', 'line_height',
'margin_bottom', 'margin_left', 'margin_right',
'margin_top', 'name', 'options',
'padding_bottom', 'padding_left', 'padding_right',
'padding_top', 'width']
dictionary = {}
for attribute in option_list:
@ -331,96 +370,101 @@ def filter_report_style_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def report_style(data, fos):
vdom = data['vdom']
state = data['state']
report_style_data = data['report_style']
flattened_data = flatten_multilists_attributes(report_style_data)
filtered_data = filter_report_style_data(flattened_data)
if report_style_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_report_style_data(report_style_data))
if state == "present":
return fos.set('report',
'style',
data=filtered_data,
vdom=vdom)
elif report_style_data['state'] == "absent":
elif state == "absent":
return fos.delete('report',
'style',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_report(data, fos):
login(data)
if data['report_style']:
resp = report_style(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"report_style": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"align": {"required": False, "type": "str",
"choices": ["left", "center", "right",
"justify"]},
"bg-color": {"required": False, "type": "str"},
"border-bottom": {"required": False, "type": "str"},
"border-left": {"required": False, "type": "str"},
"border-right": {"required": False, "type": "str"},
"border-top": {"required": False, "type": "str"},
"column-gap": {"required": False, "type": "str"},
"column-span": {"required": False, "type": "str",
"bg_color": {"required": False, "type": "str"},
"border_bottom": {"required": False, "type": "str"},
"border_left": {"required": False, "type": "str"},
"border_right": {"required": False, "type": "str"},
"border_top": {"required": False, "type": "str"},
"column_gap": {"required": False, "type": "str"},
"column_span": {"required": False, "type": "str",
"choices": ["none", "all"]},
"fg-color": {"required": False, "type": "str"},
"font-family": {"required": False, "type": "str",
"fg_color": {"required": False, "type": "str"},
"font_family": {"required": False, "type": "str",
"choices": ["Verdana", "Arial", "Helvetica",
"Courier", "Times"]},
"font-size": {"required": False, "type": "str"},
"font-style": {"required": False, "type": "str",
"font_size": {"required": False, "type": "str"},
"font_style": {"required": False, "type": "str",
"choices": ["normal", "italic"]},
"font-weight": {"required": False, "type": "str",
"font_weight": {"required": False, "type": "str",
"choices": ["normal", "bold"]},
"height": {"required": False, "type": "str"},
"line-height": {"required": False, "type": "str"},
"margin-bottom": {"required": False, "type": "str"},
"margin-left": {"required": False, "type": "str"},
"margin-right": {"required": False, "type": "str"},
"margin-top": {"required": False, "type": "str"},
"line_height": {"required": False, "type": "str"},
"margin_bottom": {"required": False, "type": "str"},
"margin_left": {"required": False, "type": "str"},
"margin_right": {"required": False, "type": "str"},
"margin_top": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"options": {"required": False, "type": "str",
"choices": ["font", "text", "color",
"align", "size", "margin",
"border", "padding", "column"]},
"padding-bottom": {"required": False, "type": "str"},
"padding-left": {"required": False, "type": "str"},
"padding-right": {"required": False, "type": "str"},
"padding-top": {"required": False, "type": "str"},
"padding_bottom": {"required": False, "type": "str"},
"padding_left": {"required": False, "type": "str"},
"padding_right": {"required": False, "type": "str"},
"padding_top": {"required": False, "type": "str"},
"width": {"required": False, "type": "str"}
}
@ -429,15 +473,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_report(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_report(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_report(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_report_theme
short_description: Report themes configuratio in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify report feature and theme category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,138 +41,181 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
report_theme:
description:
- Report themes configuration
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
bullet-list-style:
bullet_list_style:
description:
- Bullet list style.
column-count:
type: str
column_count:
description:
- Report page column count.
type: str
choices:
- 1
- 2
- 3
default-html-style:
default_html_style:
description:
- Default HTML report style.
default-pdf-style:
type: str
default_pdf_style:
description:
- Default PDF report style.
graph-chart-style:
type: str
graph_chart_style:
description:
- Graph chart style.
heading1-style:
type: str
heading1_style:
description:
- Report heading style.
heading2-style:
type: str
heading2_style:
description:
- Report heading style.
heading3-style:
type: str
heading3_style:
description:
- Report heading style.
heading4-style:
type: str
heading4_style:
description:
- Report heading style.
hline-style:
type: str
hline_style:
description:
- Horizontal line style.
image-style:
type: str
image_style:
description:
- Image style.
type: str
name:
description:
- Report theme name.
required: true
normal-text-style:
type: str
normal_text_style:
description:
- Normal text style.
numbered-list-style:
type: str
numbered_list_style:
description:
- Numbered list style.
page-footer-style:
type: str
page_footer_style:
description:
- Report page footer style.
page-header-style:
type: str
page_header_style:
description:
- Report page header style.
page-orient:
type: str
page_orient:
description:
- Report page orientation.
type: str
choices:
- portrait
- landscape
page-style:
page_style:
description:
- Report page style.
report-subtitle-style:
type: str
report_subtitle_style:
description:
- Report subtitle style.
report-title-style:
type: str
report_title_style:
description:
- Report title style.
table-chart-caption-style:
type: str
table_chart_caption_style:
description:
- Table chart caption style.
table-chart-even-row-style:
type: str
table_chart_even_row_style:
description:
- Table chart even row style.
table-chart-head-style:
type: str
table_chart_head_style:
description:
- Table chart head row style.
table-chart-odd-row-style:
type: str
table_chart_odd_row_style:
description:
- Table chart odd row style.
table-chart-style:
type: str
table_chart_style:
description:
- Table chart style.
toc-heading1-style:
type: str
toc_heading1_style:
description:
- Table of contents heading style.
toc-heading2-style:
type: str
toc_heading2_style:
description:
- Table of contents heading style.
toc-heading3-style:
type: str
toc_heading3_style:
description:
- Table of contents heading style.
toc-heading4-style:
type: str
toc_heading4_style:
description:
- Table of contents heading style.
toc-title-style:
type: str
toc_title_style:
description:
- Table of contents title style.
type: str
'''
EXAMPLES = '''
@ -185,6 +225,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Report themes configuration
fortios_report_theme:
@ -193,38 +234,38 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
report_theme:
state: "present"
bullet-list-style: "<your_own_value>"
column-count: "1"
default-html-style: "<your_own_value>"
default-pdf-style: "<your_own_value>"
graph-chart-style: "<your_own_value>"
heading1-style: "<your_own_value>"
heading2-style: "<your_own_value>"
heading3-style: "<your_own_value>"
heading4-style: "<your_own_value>"
hline-style: "<your_own_value>"
image-style: "<your_own_value>"
bullet_list_style: "<your_own_value>"
column_count: "1"
default_html_style: "<your_own_value>"
default_pdf_style: "<your_own_value>"
graph_chart_style: "<your_own_value>"
heading1_style: "<your_own_value>"
heading2_style: "<your_own_value>"
heading3_style: "<your_own_value>"
heading4_style: "<your_own_value>"
hline_style: "<your_own_value>"
image_style: "<your_own_value>"
name: "default_name_14"
normal-text-style: "<your_own_value>"
numbered-list-style: "<your_own_value>"
page-footer-style: "<your_own_value>"
page-header-style: "<your_own_value>"
page-orient: "portrait"
page-style: "<your_own_value>"
report-subtitle-style: "<your_own_value>"
report-title-style: "<your_own_value>"
table-chart-caption-style: "<your_own_value>"
table-chart-even-row-style: "<your_own_value>"
table-chart-head-style: "<your_own_value>"
table-chart-odd-row-style: "<your_own_value>"
table-chart-style: "<your_own_value>"
toc-heading1-style: "<your_own_value>"
toc-heading2-style: "<your_own_value>"
toc-heading3-style: "<your_own_value>"
toc-heading4-style: "<your_own_value>"
toc-title-style: "<your_own_value>"
normal_text_style: "<your_own_value>"
numbered_list_style: "<your_own_value>"
page_footer_style: "<your_own_value>"
page_header_style: "<your_own_value>"
page_orient: "portrait"
page_style: "<your_own_value>"
report_subtitle_style: "<your_own_value>"
report_title_style: "<your_own_value>"
table_chart_caption_style: "<your_own_value>"
table_chart_even_row_style: "<your_own_value>"
table_chart_head_style: "<your_own_value>"
table_chart_odd_row_style: "<your_own_value>"
table_chart_style: "<your_own_value>"
toc_heading1_style: "<your_own_value>"
toc_heading2_style: "<your_own_value>"
toc_heading3_style: "<your_own_value>"
toc_heading4_style: "<your_own_value>"
toc_title_style: "<your_own_value>"
'''
RETURN = '''
@ -287,14 +328,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -302,20 +345,20 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_report_theme_data(json):
option_list = ['bullet-list-style', 'column-count', 'default-html-style',
'default-pdf-style', 'graph-chart-style', 'heading1-style',
'heading2-style', 'heading3-style', 'heading4-style',
'hline-style', 'image-style', 'name',
'normal-text-style', 'numbered-list-style', 'page-footer-style',
'page-header-style', 'page-orient', 'page-style',
'report-subtitle-style', 'report-title-style', 'table-chart-caption-style',
'table-chart-even-row-style', 'table-chart-head-style', 'table-chart-odd-row-style',
'table-chart-style', 'toc-heading1-style', 'toc-heading2-style',
'toc-heading3-style', 'toc-heading4-style', 'toc-title-style']
option_list = ['bullet_list_style', 'column_count', 'default_html_style',
'default_pdf_style', 'graph_chart_style', 'heading1_style',
'heading2_style', 'heading3_style', 'heading4_style',
'hline_style', 'image_style', 'name',
'normal_text_style', 'numbered_list_style', 'page_footer_style',
'page_header_style', 'page_orient', 'page_style',
'report_subtitle_style', 'report_title_style', 'table_chart_caption_style',
'table_chart_even_row_style', 'table_chart_head_style', 'table_chart_odd_row_style',
'table_chart_style', 'toc_heading1_style', 'toc_heading2_style',
'toc_heading3_style', 'toc_heading4_style', 'toc_title_style']
dictionary = {}
for attribute in option_list:
@ -325,93 +368,98 @@ def filter_report_theme_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def report_theme(data, fos):
vdom = data['vdom']
state = data['state']
report_theme_data = data['report_theme']
flattened_data = flatten_multilists_attributes(report_theme_data)
filtered_data = filter_report_theme_data(flattened_data)
if report_theme_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_report_theme_data(report_theme_data))
if state == "present":
return fos.set('report',
'theme',
data=filtered_data,
vdom=vdom)
elif report_theme_data['state'] == "absent":
elif state == "absent":
return fos.delete('report',
'theme',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_report(data, fos):
login(data)
if data['report_theme']:
resp = report_theme(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"report_theme": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"bullet-list-style": {"required": False, "type": "str"},
"column-count": {"required": False, "type": "str",
"bullet_list_style": {"required": False, "type": "str"},
"column_count": {"required": False, "type": "str",
"choices": ["1", "2", "3"]},
"default-html-style": {"required": False, "type": "str"},
"default-pdf-style": {"required": False, "type": "str"},
"graph-chart-style": {"required": False, "type": "str"},
"heading1-style": {"required": False, "type": "str"},
"heading2-style": {"required": False, "type": "str"},
"heading3-style": {"required": False, "type": "str"},
"heading4-style": {"required": False, "type": "str"},
"hline-style": {"required": False, "type": "str"},
"image-style": {"required": False, "type": "str"},
"default_html_style": {"required": False, "type": "str"},
"default_pdf_style": {"required": False, "type": "str"},
"graph_chart_style": {"required": False, "type": "str"},
"heading1_style": {"required": False, "type": "str"},
"heading2_style": {"required": False, "type": "str"},
"heading3_style": {"required": False, "type": "str"},
"heading4_style": {"required": False, "type": "str"},
"hline_style": {"required": False, "type": "str"},
"image_style": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"normal-text-style": {"required": False, "type": "str"},
"numbered-list-style": {"required": False, "type": "str"},
"page-footer-style": {"required": False, "type": "str"},
"page-header-style": {"required": False, "type": "str"},
"page-orient": {"required": False, "type": "str",
"normal_text_style": {"required": False, "type": "str"},
"numbered_list_style": {"required": False, "type": "str"},
"page_footer_style": {"required": False, "type": "str"},
"page_header_style": {"required": False, "type": "str"},
"page_orient": {"required": False, "type": "str",
"choices": ["portrait", "landscape"]},
"page-style": {"required": False, "type": "str"},
"report-subtitle-style": {"required": False, "type": "str"},
"report-title-style": {"required": False, "type": "str"},
"table-chart-caption-style": {"required": False, "type": "str"},
"table-chart-even-row-style": {"required": False, "type": "str"},
"table-chart-head-style": {"required": False, "type": "str"},
"table-chart-odd-row-style": {"required": False, "type": "str"},
"table-chart-style": {"required": False, "type": "str"},
"toc-heading1-style": {"required": False, "type": "str"},
"toc-heading2-style": {"required": False, "type": "str"},
"toc-heading3-style": {"required": False, "type": "str"},
"toc-heading4-style": {"required": False, "type": "str"},
"toc-title-style": {"required": False, "type": "str"}
"page_style": {"required": False, "type": "str"},
"report_subtitle_style": {"required": False, "type": "str"},
"report_title_style": {"required": False, "type": "str"},
"table_chart_caption_style": {"required": False, "type": "str"},
"table_chart_even_row_style": {"required": False, "type": "str"},
"table_chart_head_style": {"required": False, "type": "str"},
"table_chart_odd_row_style": {"required": False, "type": "str"},
"table_chart_style": {"required": False, "type": "str"},
"toc_heading1_style": {"required": False, "type": "str"},
"toc_heading2_style": {"required": False, "type": "str"},
"toc_heading3_style": {"required": False, "type": "str"},
"toc_heading4_style": {"required": False, "type": "str"},
"toc_title_style": {"required": False, "type": "str"}
}
}
@ -419,15 +467,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_report(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_report(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_report(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_access_list
short_description: Configure access lists in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and access_list category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,76 +41,98 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
router_access_list:
description:
- Configure access lists.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comments:
description:
- Comment.
type: str
name:
description:
- Name.
required: true
type: str
rule:
description:
- Rule.
type: list
suboptions:
action:
description:
- Permit or deny this IP address and netmask prefix.
type: str
choices:
- permit
- deny
exact-match:
exact_match:
description:
- Enable/disable exact match.
type: str
choices:
- enable
- disable
flags:
description:
- Flags.
type: int
id:
description:
- Rule ID.
required: true
type: int
prefix:
description:
- IPv4 prefix to define regular filter criteria, such as "any" or subnets.
type: str
wildcard:
description:
- Wildcard to define Cisco-style wildcard filter criteria.
type: str
'''
EXAMPLES = '''
@ -123,6 +142,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure access lists.
fortios_router_access_list:
@ -131,14 +151,14 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_access_list:
state: "present"
comments: "<your_own_value>"
name: "default_name_4"
rule:
-
action: "permit"
exact-match: "enable"
exact_match: "enable"
flags: "8"
id: "9"
prefix: "<your_own_value>"
@ -205,14 +225,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -220,7 +242,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_access_list_data(json):
@ -234,68 +256,73 @@ def filter_router_access_list_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_access_list(data, fos):
vdom = data['vdom']
state = data['state']
router_access_list_data = data['router_access_list']
flattened_data = flatten_multilists_attributes(router_access_list_data)
filtered_data = filter_router_access_list_data(flattened_data)
if router_access_list_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_access_list_data(router_access_list_data))
if state == "present":
return fos.set('router',
'access-list',
data=filtered_data,
vdom=vdom)
elif router_access_list_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'access-list',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_access_list']:
resp = router_access_list(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_access_list": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comments": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"rule": {"required": False, "type": "list",
"options": {
"action": {"required": False, "type": "str",
"choices": ["permit", "deny"]},
"exact-match": {"required": False, "type": "str",
"exact_match": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"flags": {"required": False, "type": "int"},
"id": {"required": True, "type": "int"},
@ -309,15 +336,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_auth_path
short_description: Configure authentication based routing in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and auth_path category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,50 +41,66 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: 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
router_auth_path:
description:
- Configure authentication based routing.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
device:
description:
- Outgoing interface. Source system.interface.name.
type: str
gateway:
description:
- Gateway IP address.
type: str
name:
description:
- Name of the entry.
required: true
type: str
'''
EXAMPLES = '''
@ -97,6 +110,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure authentication based routing.
fortios_router_auth_path:
@ -105,8 +119,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_auth_path:
state: "present"
device: "<your_own_value> (source system.interface.name)"
gateway: "<your_own_value>"
name: "default_name_5"
@ -172,14 +186,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -187,7 +203,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_auth_path_data(json):
@ -201,61 +217,66 @@ def filter_router_auth_path_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_auth_path(data, fos):
vdom = data['vdom']
state = data['state']
router_auth_path_data = data['router_auth_path']
flattened_data = flatten_multilists_attributes(router_auth_path_data)
filtered_data = filter_router_auth_path_data(flattened_data)
if router_auth_path_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_auth_path_data(router_auth_path_data))
if state == "present":
return fos.set('router',
'auth-path',
data=filtered_data,
vdom=vdom)
elif router_auth_path_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'auth-path',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_auth_path']:
resp = router_auth_path(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_auth_path": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"device": {"required": False, "type": "str"},
"gateway": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"}
@ -266,15 +287,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_bfd
short_description: Configure BFD in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and bfd category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,45 +41,58 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_bfd:
description:
- Configure BFD.
default: null
type: dict
suboptions:
neighbor:
description:
- neighbor
type: list
suboptions:
interface:
description:
- Interface name. Source system.interface.name.
type: str
ip:
description:
- IPv4 address of the BFD neighbor.
required: true
type: str
'''
EXAMPLES = '''
@ -92,6 +102,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure BFD.
fortios_router_bfd:
@ -167,14 +178,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -182,7 +195,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_bfd_data(json):
@ -196,17 +209,15 @@ def filter_router_bfd_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -214,33 +225,39 @@ def flatten_multilists_attributes(data):
def router_bfd(data, fos):
vdom = data['vdom']
router_bfd_data = data['router_bfd']
flattened_data = flatten_multilists_attributes(router_bfd_data)
filtered_data = filter_router_bfd_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_bfd_data(router_bfd_data))
return fos.set('router',
'bfd',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_bfd']:
resp = router_bfd(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_bfd": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"neighbor": {"required": False, "type": "list",
"options": {
@ -254,15 +271,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_bfd6
short_description: Configure IPv6 BFD in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and bfd6 category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,45 +41,57 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_bfd6:
description:
- Configure IPv6 BFD.
default: null
type: dict
suboptions:
neighbor:
description:
- Configure neighbor of IPv6 BFD.
type: list
suboptions:
interface:
description:
- Interface to the BFD neighbor. Source system.interface.name.
ip6-address:
type: str
ip6_address:
description:
- IPv6 address of the BFD neighbor.
required: true
type: str
'''
EXAMPLES = '''
@ -92,6 +101,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv6 BFD.
fortios_router_bfd6:
@ -104,7 +114,7 @@ EXAMPLES = '''
neighbor:
-
interface: "<your_own_value> (source system.interface.name)"
ip6-address: "<your_own_value>"
ip6_address: "<your_own_value>"
'''
RETURN = '''
@ -167,14 +177,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -182,7 +194,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_bfd6_data(json):
@ -196,17 +208,15 @@ def filter_router_bfd6_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -214,38 +224,44 @@ def flatten_multilists_attributes(data):
def router_bfd6(data, fos):
vdom = data['vdom']
router_bfd6_data = data['router_bfd6']
flattened_data = flatten_multilists_attributes(router_bfd6_data)
filtered_data = filter_router_bfd6_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_bfd6_data(router_bfd6_data))
return fos.set('router',
'bfd6',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_bfd6']:
resp = router_bfd6(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_bfd6": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"neighbor": {"required": False, "type": "list",
"options": {
"interface": {"required": False, "type": "str"},
"ip6-address": {"required": True, "type": "str"}
"ip6_address": {"required": False, "type": "str"}
}}
}
@ -254,15 +270,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_multicast
short_description: Configure router multicast in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and multicast category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,287 +41,361 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_multicast:
description:
- Configure router multicast.
default: null
type: dict
suboptions:
interface:
description:
- PIM interfaces.
type: list
suboptions:
bfd:
description:
- Enable/disable Protocol Independent Multicast (PIM) Bidirectional Forwarding Detection (BFD).
type: str
choices:
- enable
- disable
cisco-exclude-genid:
cisco_exclude_genid:
description:
- Exclude GenID from hello packets (compatibility with old Cisco IOS).
type: str
choices:
- enable
- disable
dr-priority:
dr_priority:
description:
- DR election priority.
hello-holdtime:
type: int
hello_holdtime:
description:
- Time before old neighbor information expires (0 - 65535 sec, default = 105).
hello-interval:
- Time before old neighbor information expires (0 - 65535 sec).
type: int
hello_interval:
description:
- Interval between sending PIM hello messages (0 - 65535 sec, default = 30).
- Interval between sending PIM hello messages (0 - 65535 sec).
type: int
igmp:
description:
- IGMP configuration options.
type: dict
suboptions:
access-group:
access_group:
description:
- Groups IGMP hosts are allowed to join. Source router.access-list.name.
immediate-leave-group:
type: str
immediate_leave_group:
description:
- Groups to drop membership for immediately after receiving IGMPv2 leave. Source router.access-list.name.
last-member-query-count:
type: str
last_member_query_count:
description:
- Number of group specific queries before removing group (2 - 7, default = 2).
last-member-query-interval:
- Number of group specific queries before removing group (2 - 7).
type: int
last_member_query_interval:
description:
- Timeout between IGMPv2 leave and removing group (1 - 65535 msec, default = 1000).
query-interval:
- Timeout between IGMPv2 leave and removing group (1 - 65535 msec).
type: int
query_interval:
description:
- Interval between queries to IGMP hosts (1 - 65535 sec, default = 125).
query-max-response-time:
- Interval between queries to IGMP hosts (1 - 65535 sec).
type: int
query_max_response_time:
description:
- Maximum time to wait for a IGMP query response (1 - 25 sec, default = 10).
query-timeout:
- Maximum time to wait for a IGMP query response (1 - 25 sec).
type: int
query_timeout:
description:
- Timeout between queries before becoming querier for network (60 - 900, default = 255).
router-alert-check:
- Timeout between queries before becoming querier for network (60 - 900).
type: int
router_alert_check:
description:
- Enable/disable require IGMP packets contain router alert option.
type: str
choices:
- enable
- disable
version:
description:
- Maximum version of IGMP to support.
type: str
choices:
- 3
- 2
- 1
join-group:
join_group:
description:
- Join multicast groups.
type: list
suboptions:
address:
description:
- Multicast group IP address.
required: true
multicast-flow:
type: str
multicast_flow:
description:
- Acceptable source for multicast group. Source router.multicast-flow.name.
type: str
name:
description:
- Interface name. Source system.interface.name.
required: true
neighbour-filter:
type: str
neighbour_filter:
description:
- Routers acknowledged as neighbor routers. Source router.access-list.name.
type: str
passive:
description:
- Enable/disable listening to IGMP but not participating in PIM.
type: str
choices:
- enable
- disable
pim-mode:
pim_mode:
description:
- PIM operation mode.
type: str
choices:
- sparse-mode
- dense-mode
propagation-delay:
propagation_delay:
description:
- Delay flooding packets on this interface (100 - 5000 msec, default = 500).
rp-candidate:
- Delay flooding packets on this interface (100 - 5000 msec).
type: int
rp_candidate:
description:
- Enable/disable compete to become RP in elections.
type: str
choices:
- enable
- disable
rp-candidate-group:
rp_candidate_group:
description:
- Multicast groups managed by this RP. Source router.access-list.name.
rp-candidate-interval:
type: str
rp_candidate_interval:
description:
- RP candidate advertisement interval (1 - 16383 sec, default = 60).
rp-candidate-priority:
- RP candidate advertisement interval (1 - 16383 sec).
type: int
rp_candidate_priority:
description:
- Router's priority as RP.
state-refresh-interval:
type: int
state_refresh_interval:
description:
- Interval between sending state-refresh packets (1 - 100 sec, default = 60).
static-group:
- Interval between sending state-refresh packets (1 - 100 sec).
type: int
static_group:
description:
- Statically set multicast groups to forward out. Source router.multicast-flow.name.
ttl-threshold:
type: str
ttl_threshold:
description:
- Minimum TTL of multicast packets that will be forwarded (applied only to new multicast routes) (1 - 255, default = 1).
multicast-routing:
- Minimum TTL of multicast packets that will be forwarded (applied only to new multicast routes) (1 - 255).
type: int
multicast_routing:
description:
- Enable/disable IP multicast routing.
type: str
choices:
- enable
- disable
pim-sm-global:
pim_sm_global:
description:
- PIM sparse-mode global settings.
type: dict
suboptions:
accept-register-list:
accept_register_list:
description:
- Sources allowed to register packets with this Rendezvous Point (RP). Source router.access-list.name.
accept-source-list:
type: str
accept_source_list:
description:
- Sources allowed to send multicast traffic. Source router.access-list.name.
bsr-allow-quick-refresh:
type: str
bsr_allow_quick_refresh:
description:
- Enable/disable accept BSR quick refresh packets from neighbors.
type: str
choices:
- enable
- disable
bsr-candidate:
bsr_candidate:
description:
- Enable/disable allowing this router to become a bootstrap router (BSR).
type: str
choices:
- enable
- disable
bsr-hash:
bsr_hash:
description:
- BSR hash length (0 - 32, default = 10).
bsr-interface:
- BSR hash length (0 - 32).
type: int
bsr_interface:
description:
- Interface to advertise as candidate BSR. Source system.interface.name.
bsr-priority:
type: str
bsr_priority:
description:
- BSR priority (0 - 255, default = 0).
cisco-crp-prefix:
- BSR priority (0 - 255).
type: int
cisco_crp_prefix:
description:
- Enable/disable making candidate RP compatible with old Cisco IOS.
type: str
choices:
- enable
- disable
cisco-ignore-rp-set-priority:
cisco_ignore_rp_set_priority:
description:
- Use only hash for RP selection (compatibility with old Cisco IOS).
type: str
choices:
- enable
- disable
cisco-register-checksum:
cisco_register_checksum:
description:
- Checksum entire register packet(for old Cisco IOS compatibility).
type: str
choices:
- enable
- disable
cisco-register-checksum-group:
cisco_register_checksum_group:
description:
- Cisco register checksum only these groups. Source router.access-list.name.
join-prune-holdtime:
type: str
join_prune_holdtime:
description:
- Join/prune holdtime (1 - 65535, default = 210).
message-interval:
- Join/prune holdtime (1 - 65535).
type: int
message_interval:
description:
- Period of time between sending periodic PIM join/prune messages in seconds (1 - 65535, default = 60).
null-register-retries:
- Period of time between sending periodic PIM join/prune messages in seconds (1 - 65535).
type: int
null_register_retries:
description:
- Maximum retries of null register (1 - 20, default = 1).
register-rate-limit:
- Maximum retries of null register (1 - 20).
type: int
register_rate_limit:
description:
- Limit of packets/sec per source registered through this RP (0 - 65535, default = 0 which means unlimited).
register-rp-reachability:
- Limit of packets/sec per source registered through this RP (0 - 65535).
type: int
register_rp_reachability:
description:
- Enable/disable check RP is reachable before registering packets.
type: str
choices:
- enable
- disable
register-source:
register_source:
description:
- Override source address in register packets.
type: str
choices:
- disable
- interface
- ip-address
register-source-interface:
register_source_interface:
description:
- Override with primary interface address. Source system.interface.name.
register-source-ip:
type: str
register_source_ip:
description:
- Override with local IP address.
register-supression:
type: str
register_supression:
description:
- Period of time to honor register-stop message (1 - 65535 sec, default = 60).
rp-address:
- Period of time to honor register-stop message (1 - 65535 sec).
type: int
rp_address:
description:
- Statically configure RP addresses.
type: list
suboptions:
group:
description:
- Groups to use this RP. Source router.access-list.name.
type: str
id:
description:
- ID.
required: true
ip-address:
type: int
ip_address:
description:
- RP router address.
rp-register-keepalive:
type: str
rp_register_keepalive:
description:
- Timeout for RP receiving data on (S,G) tree (1 - 65535 sec, default = 185).
spt-threshold:
- Timeout for RP receiving data on (S,G) tree (1 - 65535 sec).
type: int
spt_threshold:
description:
- Enable/disable switching to source specific trees.
type: str
choices:
- enable
- disable
spt-threshold-group:
spt_threshold_group:
description:
- Groups allowed to switch to source tree. Source router.access-list.name.
type: str
ssm:
description:
- Enable/disable source specific multicast.
type: str
choices:
- enable
- disable
ssm-range:
ssm_range:
description:
- Groups allowed to source specific multicast. Source router.access-list.name.
route-limit:
type: str
route_limit:
description:
- Maximum number of multicast routes.
route-threshold:
type: int
route_threshold:
description:
- Generate warnings when the number of multicast routes exceeds this number, must not be greater than route-limit.
type: int
'''
EXAMPLES = '''
@ -334,6 +405,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure router multicast.
fortios_router_multicast:
@ -346,70 +418,70 @@ EXAMPLES = '''
interface:
-
bfd: "enable"
cisco-exclude-genid: "enable"
dr-priority: "6"
hello-holdtime: "7"
hello-interval: "8"
cisco_exclude_genid: "enable"
dr_priority: "6"
hello_holdtime: "7"
hello_interval: "8"
igmp:
access-group: "<your_own_value> (source router.access-list.name)"
immediate-leave-group: "<your_own_value> (source router.access-list.name)"
last-member-query-count: "12"
last-member-query-interval: "13"
query-interval: "14"
query-max-response-time: "15"
query-timeout: "16"
router-alert-check: "enable"
access_group: "<your_own_value> (source router.access-list.name)"
immediate_leave_group: "<your_own_value> (source router.access-list.name)"
last_member_query_count: "12"
last_member_query_interval: "13"
query_interval: "14"
query_max_response_time: "15"
query_timeout: "16"
router_alert_check: "enable"
version: "3"
join-group:
join_group:
-
address: "<your_own_value>"
multicast-flow: "<your_own_value> (source router.multicast-flow.name)"
multicast_flow: "<your_own_value> (source router.multicast-flow.name)"
name: "default_name_22 (source system.interface.name)"
neighbour-filter: "<your_own_value> (source router.access-list.name)"
neighbour_filter: "<your_own_value> (source router.access-list.name)"
passive: "enable"
pim-mode: "sparse-mode"
propagation-delay: "26"
rp-candidate: "enable"
rp-candidate-group: "<your_own_value> (source router.access-list.name)"
rp-candidate-interval: "29"
rp-candidate-priority: "30"
state-refresh-interval: "31"
static-group: "<your_own_value> (source router.multicast-flow.name)"
ttl-threshold: "33"
multicast-routing: "enable"
pim-sm-global:
accept-register-list: "<your_own_value> (source router.access-list.name)"
accept-source-list: "<your_own_value> (source router.access-list.name)"
bsr-allow-quick-refresh: "enable"
bsr-candidate: "enable"
bsr-hash: "40"
bsr-interface: "<your_own_value> (source system.interface.name)"
bsr-priority: "42"
cisco-crp-prefix: "enable"
cisco-ignore-rp-set-priority: "enable"
cisco-register-checksum: "enable"
cisco-register-checksum-group: "<your_own_value> (source router.access-list.name)"
join-prune-holdtime: "47"
message-interval: "48"
null-register-retries: "49"
register-rate-limit: "50"
register-rp-reachability: "enable"
register-source: "disable"
register-source-interface: "<your_own_value> (source system.interface.name)"
register-source-ip: "<your_own_value>"
register-supression: "55"
rp-address:
pim_mode: "sparse-mode"
propagation_delay: "26"
rp_candidate: "enable"
rp_candidate_group: "<your_own_value> (source router.access-list.name)"
rp_candidate_interval: "29"
rp_candidate_priority: "30"
state_refresh_interval: "31"
static_group: "<your_own_value> (source router.multicast-flow.name)"
ttl_threshold: "33"
multicast_routing: "enable"
pim_sm_global:
accept_register_list: "<your_own_value> (source router.access-list.name)"
accept_source_list: "<your_own_value> (source router.access-list.name)"
bsr_allow_quick_refresh: "enable"
bsr_candidate: "enable"
bsr_hash: "40"
bsr_interface: "<your_own_value> (source system.interface.name)"
bsr_priority: "42"
cisco_crp_prefix: "enable"
cisco_ignore_rp_set_priority: "enable"
cisco_register_checksum: "enable"
cisco_register_checksum_group: "<your_own_value> (source router.access-list.name)"
join_prune_holdtime: "47"
message_interval: "48"
null_register_retries: "49"
register_rate_limit: "50"
register_rp_reachability: "enable"
register_source: "disable"
register_source_interface: "<your_own_value> (source system.interface.name)"
register_source_ip: "<your_own_value>"
register_supression: "55"
rp_address:
-
group: "<your_own_value> (source router.access-list.name)"
id: "58"
ip-address: "<your_own_value>"
rp-register-keepalive: "60"
spt-threshold: "enable"
spt-threshold-group: "<your_own_value> (source router.access-list.name)"
ip_address: "<your_own_value>"
rp_register_keepalive: "60"
spt_threshold: "enable"
spt_threshold_group: "<your_own_value> (source router.access-list.name)"
ssm: "enable"
ssm-range: "<your_own_value> (source router.access-list.name)"
route-limit: "65"
route-threshold: "66"
ssm_range: "<your_own_value> (source router.access-list.name)"
route_limit: "65"
route_threshold: "66"
'''
RETURN = '''
@ -472,14 +544,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -487,12 +561,12 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_multicast_data(json):
option_list = ['interface', 'multicast-routing', 'pim-sm-global',
'route-limit', 'route-threshold']
option_list = ['interface', 'multicast_routing', 'pim_sm_global',
'route_limit', 'route_threshold']
dictionary = {}
for attribute in option_list:
@ -502,17 +576,15 @@ def filter_router_multicast_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -520,125 +592,131 @@ def flatten_multilists_attributes(data):
def router_multicast(data, fos):
vdom = data['vdom']
router_multicast_data = data['router_multicast']
flattened_data = flatten_multilists_attributes(router_multicast_data)
filtered_data = filter_router_multicast_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_multicast_data(router_multicast_data))
return fos.set('router',
'multicast',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_multicast']:
resp = router_multicast(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_multicast": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"interface": {"required": False, "type": "list",
"options": {
"bfd": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"cisco-exclude-genid": {"required": False, "type": "str",
"cisco_exclude_genid": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"dr-priority": {"required": False, "type": "int"},
"hello-holdtime": {"required": False, "type": "int"},
"hello-interval": {"required": False, "type": "int"},
"dr_priority": {"required": False, "type": "int"},
"hello_holdtime": {"required": False, "type": "int"},
"hello_interval": {"required": False, "type": "int"},
"igmp": {"required": False, "type": "dict",
"options": {
"access-group": {"required": False, "type": "str"},
"immediate-leave-group": {"required": False, "type": "str"},
"last-member-query-count": {"required": False, "type": "int"},
"last-member-query-interval": {"required": False, "type": "int"},
"query-interval": {"required": False, "type": "int"},
"query-max-response-time": {"required": False, "type": "int"},
"query-timeout": {"required": False, "type": "int"},
"router-alert-check": {"required": False, "type": "str",
"access_group": {"required": False, "type": "str"},
"immediate_leave_group": {"required": False, "type": "str"},
"last_member_query_count": {"required": False, "type": "int"},
"last_member_query_interval": {"required": False, "type": "int"},
"query_interval": {"required": False, "type": "int"},
"query_max_response_time": {"required": False, "type": "int"},
"query_timeout": {"required": False, "type": "int"},
"router_alert_check": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"version": {"required": False, "type": "str",
"choices": ["3", "2", "1"]}
}},
"join-group": {"required": False, "type": "list",
"join_group": {"required": False, "type": "list",
"options": {
"address": {"required": True, "type": "str"}
}},
"multicast-flow": {"required": False, "type": "str"},
"multicast_flow": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"neighbour-filter": {"required": False, "type": "str"},
"neighbour_filter": {"required": False, "type": "str"},
"passive": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"pim-mode": {"required": False, "type": "str",
"pim_mode": {"required": False, "type": "str",
"choices": ["sparse-mode", "dense-mode"]},
"propagation-delay": {"required": False, "type": "int"},
"rp-candidate": {"required": False, "type": "str",
"propagation_delay": {"required": False, "type": "int"},
"rp_candidate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"rp-candidate-group": {"required": False, "type": "str"},
"rp-candidate-interval": {"required": False, "type": "int"},
"rp-candidate-priority": {"required": False, "type": "int"},
"state-refresh-interval": {"required": False, "type": "int"},
"static-group": {"required": False, "type": "str"},
"ttl-threshold": {"required": False, "type": "int"}
"rp_candidate_group": {"required": False, "type": "str"},
"rp_candidate_interval": {"required": False, "type": "int"},
"rp_candidate_priority": {"required": False, "type": "int"},
"state_refresh_interval": {"required": False, "type": "int"},
"static_group": {"required": False, "type": "str"},
"ttl_threshold": {"required": False, "type": "int"}
}},
"multicast-routing": {"required": False, "type": "str",
"multicast_routing": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"pim-sm-global": {"required": False, "type": "dict",
"pim_sm_global": {"required": False, "type": "dict",
"options": {
"accept-register-list": {"required": False, "type": "str"},
"accept-source-list": {"required": False, "type": "str"},
"bsr-allow-quick-refresh": {"required": False, "type": "str",
"accept_register_list": {"required": False, "type": "str"},
"accept_source_list": {"required": False, "type": "str"},
"bsr_allow_quick_refresh": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"bsr-candidate": {"required": False, "type": "str",
"bsr_candidate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"bsr-hash": {"required": False, "type": "int"},
"bsr-interface": {"required": False, "type": "str"},
"bsr-priority": {"required": False, "type": "int"},
"cisco-crp-prefix": {"required": False, "type": "str",
"bsr_hash": {"required": False, "type": "int"},
"bsr_interface": {"required": False, "type": "str"},
"bsr_priority": {"required": False, "type": "int"},
"cisco_crp_prefix": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"cisco-ignore-rp-set-priority": {"required": False, "type": "str",
"cisco_ignore_rp_set_priority": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"cisco-register-checksum": {"required": False, "type": "str",
"cisco_register_checksum": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"cisco-register-checksum-group": {"required": False, "type": "str"},
"join-prune-holdtime": {"required": False, "type": "int"},
"message-interval": {"required": False, "type": "int"},
"null-register-retries": {"required": False, "type": "int"},
"register-rate-limit": {"required": False, "type": "int"},
"register-rp-reachability": {"required": False, "type": "str",
"cisco_register_checksum_group": {"required": False, "type": "str"},
"join_prune_holdtime": {"required": False, "type": "int"},
"message_interval": {"required": False, "type": "int"},
"null_register_retries": {"required": False, "type": "int"},
"register_rate_limit": {"required": False, "type": "int"},
"register_rp_reachability": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"register-source": {"required": False, "type": "str",
"register_source": {"required": False, "type": "str",
"choices": ["disable", "interface", "ip-address"]},
"register-source-interface": {"required": False, "type": "str"},
"register-source-ip": {"required": False, "type": "str"},
"register-supression": {"required": False, "type": "int"},
"rp-address": {"required": False, "type": "list",
"register_source_interface": {"required": False, "type": "str"},
"register_source_ip": {"required": False, "type": "str"},
"register_supression": {"required": False, "type": "int"},
"rp_address": {"required": False, "type": "list",
"options": {
"group": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"ip-address": {"required": False, "type": "str"}
"ip_address": {"required": False, "type": "str"}
}},
"rp-register-keepalive": {"required": False, "type": "int"},
"spt-threshold": {"required": False, "type": "str",
"rp_register_keepalive": {"required": False, "type": "int"},
"spt_threshold": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"spt-threshold-group": {"required": False, "type": "str"},
"spt_threshold_group": {"required": False, "type": "str"},
"ssm": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ssm-range": {"required": False, "type": "str"}
"ssm_range": {"required": False, "type": "str"}
}},
"route-limit": {"required": False, "type": "int"},
"route-threshold": {"required": False, "type": "int"}
"route_limit": {"required": False, "type": "int"},
"route_threshold": {"required": False, "type": "int"}
}
}
@ -646,15 +724,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_multicast6
short_description: Configure IPv6 multicast in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and multicast6 category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,78 +41,99 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_multicast6:
description:
- Configure IPv6 multicast.
default: null
type: dict
suboptions:
interface:
description:
- Protocol Independent Multicast (PIM) interfaces.
type: list
suboptions:
hello-holdtime:
hello_holdtime:
description:
- Time before old neighbour information expires (1 - 65535 sec, default = 105).
hello-interval:
- Time before old neighbour information expires (1 - 65535 sec).
type: int
hello_interval:
description:
- Interval between sending PIM hello messages (1 - 65535 sec, default = 30)..
- Interval between sending PIM hello messages (1 - 65535 sec)..
type: int
name:
description:
- Interface name. Source system.interface.name.
required: true
multicast-pmtu:
type: str
multicast_pmtu:
description:
- Enable/disable PMTU for IPv6 multicast.
type: str
choices:
- enable
- disable
multicast-routing:
multicast_routing:
description:
- Enable/disable IPv6 multicast routing.
type: str
choices:
- enable
- disable
pim-sm-global:
pim_sm_global:
description:
- PIM sparse-mode global settings.
type: dict
suboptions:
register-rate-limit:
register_rate_limit:
description:
- Limit of packets/sec per source registered through this RP (0 means unlimited).
rp-address:
type: int
rp_address:
description:
- Statically configured RP addresses.
type: list
suboptions:
id:
description:
- ID of the entry.
required: true
ip6-address:
type: int
ip6_address:
description:
- RP router IPv6 address.
type: str
'''
EXAMPLES = '''
@ -125,6 +143,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv6 multicast.
fortios_router_multicast6:
@ -136,17 +155,17 @@ EXAMPLES = '''
router_multicast6:
interface:
-
hello-holdtime: "4"
hello-interval: "5"
hello_holdtime: "4"
hello_interval: "5"
name: "default_name_6 (source system.interface.name)"
multicast-pmtu: "enable"
multicast-routing: "enable"
pim-sm-global:
register-rate-limit: "10"
rp-address:
multicast_pmtu: "enable"
multicast_routing: "enable"
pim_sm_global:
register_rate_limit: "10"
rp_address:
-
id: "12"
ip6-address: "<your_own_value>"
ip6_address: "<your_own_value>"
'''
RETURN = '''
@ -209,14 +228,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -224,12 +245,12 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_multicast6_data(json):
option_list = ['interface', 'multicast-pmtu', 'multicast-routing',
'pim-sm-global']
option_list = ['interface', 'multicast_pmtu', 'multicast_routing',
'pim_sm_global']
dictionary = {}
for attribute in option_list:
@ -239,17 +260,15 @@ def filter_router_multicast6_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -257,51 +276,57 @@ def flatten_multilists_attributes(data):
def router_multicast6(data, fos):
vdom = data['vdom']
router_multicast6_data = data['router_multicast6']
flattened_data = flatten_multilists_attributes(router_multicast6_data)
filtered_data = filter_router_multicast6_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_multicast6_data(router_multicast6_data))
return fos.set('router',
'multicast6',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_multicast6']:
resp = router_multicast6(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_multicast6": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"interface": {"required": False, "type": "list",
"options": {
"hello-holdtime": {"required": False, "type": "int"},
"hello-interval": {"required": False, "type": "int"},
"hello_holdtime": {"required": False, "type": "int"},
"hello_interval": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"}
}},
"multicast-pmtu": {"required": False, "type": "str",
"multicast_pmtu": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"multicast-routing": {"required": False, "type": "str",
"multicast_routing": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"pim-sm-global": {"required": False, "type": "dict",
"pim_sm_global": {"required": False, "type": "dict",
"options": {
"register-rate-limit": {"required": False, "type": "int"},
"rp-address": {"required": False, "type": "list",
"register_rate_limit": {"required": False, "type": "int"},
"rp_address": {"required": False, "type": "list",
"options": {
"id": {"required": True, "type": "int"},
"ip6-address": {"required": False, "type": "str"}
"ip6_address": {"required": False, "type": "str"}
}}
}}
@ -311,15 +336,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_multicast_flow
short_description: Configure multicast-flow in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and multicast_flow category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,61 +41,80 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: 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
router_multicast_flow:
description:
- Configure multicast-flow.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comments:
description:
- Comment.
type: str
flows:
description:
- Multicast-flow entries.
type: list
suboptions:
group-addr:
group_addr:
description:
- Multicast group IP address.
type: str
id:
description:
- Flow ID.
required: true
source-addr:
type: int
source_addr:
description:
- Multicast source IP address.
type: str
name:
description:
- Name.
required: true
type: str
'''
EXAMPLES = '''
@ -108,6 +124,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure multicast-flow.
fortios_router_multicast_flow:
@ -116,14 +133,14 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_multicast_flow:
state: "present"
comments: "<your_own_value>"
flows:
-
group-addr: "<your_own_value>"
group_addr: "<your_own_value>"
id: "6"
source-addr: "<your_own_value>"
source_addr: "<your_own_value>"
name: "default_name_8"
'''
@ -187,14 +204,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -202,7 +221,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_multicast_flow_data(json):
@ -216,67 +235,72 @@ def filter_router_multicast_flow_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_multicast_flow(data, fos):
vdom = data['vdom']
state = data['state']
router_multicast_flow_data = data['router_multicast_flow']
flattened_data = flatten_multilists_attributes(router_multicast_flow_data)
filtered_data = filter_router_multicast_flow_data(flattened_data)
if router_multicast_flow_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_multicast_flow_data(router_multicast_flow_data))
if state == "present":
return fos.set('router',
'multicast-flow',
data=filtered_data,
vdom=vdom)
elif router_multicast_flow_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'multicast-flow',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_multicast_flow']:
resp = router_multicast_flow(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_multicast_flow": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comments": {"required": False, "type": "str"},
"flows": {"required": False, "type": "list",
"options": {
"group-addr": {"required": False, "type": "str"},
"group_addr": {"required": False, "type": "str"},
"id": {"required": True, "type": "int"},
"source-addr": {"required": False, "type": "str"}
"source_addr": {"required": False, "type": "str"}
}},
"name": {"required": True, "type": "str"}
@ -286,15 +310,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_ospf6
short_description: Configure IPv6 OSPF in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and ospf6 category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,37 +41,48 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_ospf6:
description:
- Configure IPv6 OSPF.
default: null
type: dict
suboptions:
abr-type:
abr_type:
description:
- Area border router type.
type: str
choices:
- cisco
- ibm
@ -82,38 +90,46 @@ options:
area:
description:
- OSPF6 area configuration.
type: list
suboptions:
default-cost:
default_cost:
description:
- Summary default cost of stub or NSSA area.
type: int
id:
description:
- Area entry IP address.
required: true
nssa-default-information-originate:
type: str
nssa_default_information_originate:
description:
- Enable/disable originate type 7 default into NSSA area.
type: str
choices:
- enable
- disable
nssa-default-information-originate-metric:
nssa_default_information_originate_metric:
description:
- OSPFv3 default metric.
nssa-default-information-originate-metric-type:
type: int
nssa_default_information_originate_metric_type:
description:
- OSPFv3 metric type for default routes.
type: str
choices:
- 1
- 2
nssa-redistribution:
nssa_redistribution:
description:
- Enable/disable redistribute into NSSA area.
type: str
choices:
- enable
- disable
nssa-translator-role:
nssa_translator_role:
description:
- NSSA translator role type.
type: str
choices:
- candidate
- never
@ -121,10 +137,12 @@ options:
range:
description:
- OSPF6 area range configuration.
type: list
suboptions:
advertise:
description:
- Enable/disable advertise status.
type: str
choices:
- disable
- enable
@ -132,92 +150,114 @@ options:
description:
- Range entry ID.
required: true
type: int
prefix6:
description:
- IPv6 prefix.
stub-type:
type: str
stub_type:
description:
- Stub summary setting.
type: str
choices:
- no-summary
- summary
type:
description:
- Area type setting.
type: str
choices:
- regular
- nssa
- stub
virtual-link:
virtual_link:
description:
- OSPF6 virtual link configuration.
type: list
suboptions:
dead-interval:
dead_interval:
description:
- Dead interval.
hello-interval:
type: int
hello_interval:
description:
- Hello interval.
type: int
name:
description:
- Virtual link entry name.
required: true
type: str
peer:
description:
- A.B.C.D, peer router ID.
retransmit-interval:
type: str
retransmit_interval:
description:
- Retransmit interval.
transmit-delay:
type: int
transmit_delay:
description:
- Transmit delay.
auto-cost-ref-bandwidth:
type: int
auto_cost_ref_bandwidth:
description:
- Reference bandwidth in terms of megabits per second.
type: int
bfd:
description:
- Enable/disable Bidirectional Forwarding Detection (BFD).
type: str
choices:
- enable
- disable
default-information-metric:
default_information_metric:
description:
- Default information metric.
default-information-metric-type:
type: int
default_information_metric_type:
description:
- Default information metric type.
type: str
choices:
- 1
- 2
default-information-originate:
default_information_originate:
description:
- Enable/disable generation of default route.
type: str
choices:
- enable
- always
- disable
default-information-route-map:
default_information_route_map:
description:
- Default information route map. Source router.route-map.name.
default-metric:
type: str
default_metric:
description:
- Default metric of redistribute routes.
log-neighbour-changes:
type: int
log_neighbour_changes:
description:
- Enable logging of OSPFv3 neighbour's changes
type: str
choices:
- enable
- disable
ospf6-interface:
ospf6_interface:
description:
- OSPF6 interface configuration.
type: list
suboptions:
area-id:
area_id:
description:
- A.B.C.D, in IPv4 address format.
type: str
bfd:
description:
- Enable/disable Bidirectional Forwarding Detection (BFD).
type: str
choices:
- global
- enable
@ -225,39 +265,61 @@ options:
cost:
description:
- Cost of the interface, value range from 0 to 65535, 0 means auto-cost.
dead-interval:
type: int
dead_interval:
description:
- Dead interval.
hello-interval:
type: int
hello_interval:
description:
- Hello interval.
type: int
interface:
description:
- Configuration interface name. Source system.interface.name.
type: str
mtu:
description:
- MTU for OSPFv3 packets.
type: int
mtu_ignore:
description:
- Enable/disable ignoring MTU field in DBD packets.
type: str
choices:
- enable
- disable
name:
description:
- Interface entry name.
required: true
type: str
neighbor:
description:
- OSPFv3 neighbors are used when OSPFv3 runs on non-broadcast media
type: list
suboptions:
cost:
description:
- Cost of the interface, value range from 0 to 65535, 0 means auto-cost.
type: int
ip6:
description:
- IPv6 link local address of the neighbor.
required: true
poll-interval:
type: str
poll_interval:
description:
- Poll interval time in seconds.
type: int
priority:
description:
- priority
network-type:
type: int
network_type:
description:
- Network type.
type: str
choices:
- broadcast
- point-to-point
@ -267,36 +329,45 @@ options:
priority:
description:
- priority
retransmit-interval:
type: int
retransmit_interval:
description:
- Retransmit interval.
type: int
status:
description:
- Enable/disable OSPF6 routing on this interface.
type: str
choices:
- disable
- enable
transmit-delay:
transmit_delay:
description:
- Transmit delay.
passive-interface:
type: int
passive_interface:
description:
- Passive interface configuration.
type: list
suboptions:
name:
description:
- Passive interface name. Source system.interface.name.
required: true
type: str
redistribute:
description:
- Redistribute configuration.
type: list
suboptions:
metric:
description:
- Redistribute metric setting.
metric-type:
type: int
metric_type:
description:
- Metric type.
type: str
choices:
- 1
- 2
@ -304,28 +375,35 @@ options:
description:
- Redistribute name.
required: true
type: str
routemap:
description:
- Route map name. Source router.route-map.name.
type: str
status:
description:
- status
type: str
choices:
- enable
- disable
router-id:
router_id:
description:
- A.B.C.D, in IPv4 address format.
spf-timers:
type: str
spf_timers:
description:
- SPF calculation frequency.
summary-address:
type: str
summary_address:
description:
- IPv6 address summary configuration.
type: list
suboptions:
advertise:
description:
- Enable/disable advertise status.
type: str
choices:
- disable
- enable
@ -333,12 +411,15 @@ options:
description:
- Summary address entry ID.
required: true
type: int
prefix6:
description:
- IPv6 prefix.
type: str
tag:
description:
- Tag value.
type: int
'''
EXAMPLES = '''
@ -348,6 +429,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv6 OSPF.
fortios_router_ospf6:
@ -357,77 +439,79 @@ EXAMPLES = '''
vdom: "{{ vdom }}"
https: "False"
router_ospf6:
abr-type: "cisco"
abr_type: "cisco"
area:
-
default-cost: "5"
default_cost: "5"
id: "6"
nssa-default-information-originate: "enable"
nssa-default-information-originate-metric: "8"
nssa-default-information-originate-metric-type: "1"
nssa-redistribution: "enable"
nssa-translator-role: "candidate"
nssa_default_information_originate: "enable"
nssa_default_information_originate_metric: "8"
nssa_default_information_originate_metric_type: "1"
nssa_redistribution: "enable"
nssa_translator_role: "candidate"
range:
-
advertise: "disable"
id: "14"
prefix6: "<your_own_value>"
stub-type: "no-summary"
stub_type: "no-summary"
type: "regular"
virtual-link:
virtual_link:
-
dead-interval: "19"
hello-interval: "20"
dead_interval: "19"
hello_interval: "20"
name: "default_name_21"
peer: "<your_own_value>"
retransmit-interval: "23"
transmit-delay: "24"
auto-cost-ref-bandwidth: "25"
retransmit_interval: "23"
transmit_delay: "24"
auto_cost_ref_bandwidth: "25"
bfd: "enable"
default-information-metric: "27"
default-information-metric-type: "1"
default-information-originate: "enable"
default-information-route-map: "<your_own_value> (source router.route-map.name)"
default-metric: "31"
log-neighbour-changes: "enable"
ospf6-interface:
default_information_metric: "27"
default_information_metric_type: "1"
default_information_originate: "enable"
default_information_route_map: "<your_own_value> (source router.route-map.name)"
default_metric: "31"
log_neighbour_changes: "enable"
ospf6_interface:
-
area-id: "<your_own_value>"
area_id: "<your_own_value>"
bfd: "global"
cost: "36"
dead-interval: "37"
hello-interval: "38"
dead_interval: "37"
hello_interval: "38"
interface: "<your_own_value> (source system.interface.name)"
name: "default_name_40"
mtu: "40"
mtu_ignore: "enable"
name: "default_name_42"
neighbor:
-
cost: "42"
cost: "44"
ip6: "<your_own_value>"
poll-interval: "44"
priority: "45"
network-type: "broadcast"
priority: "47"
retransmit-interval: "48"
poll_interval: "46"
priority: "47"
network_type: "broadcast"
priority: "49"
retransmit_interval: "50"
status: "disable"
transmit-delay: "50"
passive-interface:
transmit_delay: "52"
passive_interface:
-
name: "default_name_52 (source system.interface.name)"
name: "default_name_54 (source system.interface.name)"
redistribute:
-
metric: "54"
metric-type: "1"
name: "default_name_56"
metric: "56"
metric_type: "1"
name: "default_name_58"
routemap: "<your_own_value> (source router.route-map.name)"
status: "enable"
router-id: "<your_own_value>"
spf-timers: "<your_own_value>"
summary-address:
router_id: "<your_own_value>"
spf_timers: "<your_own_value>"
summary_address:
-
advertise: "disable"
id: "63"
id: "65"
prefix6: "<your_own_value>"
tag: "65"
tag: "67"
'''
RETURN = '''
@ -490,14 +574,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -505,16 +591,16 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_ospf6_data(json):
option_list = ['abr-type', 'area', 'auto-cost-ref-bandwidth',
'bfd', 'default-information-metric', 'default-information-metric-type',
'default-information-originate', 'default-information-route-map', 'default-metric',
'log-neighbour-changes', 'ospf6-interface', 'passive-interface',
'redistribute', 'router-id', 'spf-timers',
'summary-address']
option_list = ['abr_type', 'area', 'auto_cost_ref_bandwidth',
'bfd', 'default_information_metric', 'default_information_metric_type',
'default_information_originate', 'default_information_route_map', 'default_metric',
'log_neighbour_changes', 'ospf6_interface', 'passive_interface',
'redistribute', 'router_id', 'spf_timers',
'summary_address']
dictionary = {}
for attribute in option_list:
@ -524,17 +610,15 @@ def filter_router_ospf6_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -542,48 +626,54 @@ def flatten_multilists_attributes(data):
def router_ospf6(data, fos):
vdom = data['vdom']
router_ospf6_data = data['router_ospf6']
flattened_data = flatten_multilists_attributes(router_ospf6_data)
filtered_data = filter_router_ospf6_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_ospf6_data(router_ospf6_data))
return fos.set('router',
'ospf6',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_ospf6']:
resp = router_ospf6(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_ospf6": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"abr-type": {"required": False, "type": "str",
"abr_type": {"required": False, "type": "str",
"choices": ["cisco", "ibm", "standard"]},
"area": {"required": False, "type": "list",
"options": {
"default-cost": {"required": False, "type": "int"},
"default_cost": {"required": False, "type": "int"},
"id": {"required": True, "type": "str"},
"nssa-default-information-originate": {"required": False, "type": "str",
"nssa_default_information_originate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"nssa-default-information-originate-metric": {"required": False, "type": "int"},
"nssa-default-information-originate-metric-type": {"required": False, "type": "str",
"nssa_default_information_originate_metric": {"required": False, "type": "int"},
"nssa_default_information_originate_metric_type": {"required": False, "type": "str",
"choices": ["1", "2"]},
"nssa-redistribution": {"required": False, "type": "str",
"nssa_redistribution": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"nssa-translator-role": {"required": False, "type": "str",
"nssa_translator_role": {"required": False, "type": "str",
"choices": ["candidate", "never", "always"]},
"range": {"required": False, "type": "list",
"options": {
@ -592,75 +682,78 @@ def main():
"id": {"required": True, "type": "int"},
"prefix6": {"required": False, "type": "str"}
}},
"stub-type": {"required": False, "type": "str",
"stub_type": {"required": False, "type": "str",
"choices": ["no-summary", "summary"]},
"type": {"required": False, "type": "str",
"choices": ["regular", "nssa", "stub"]},
"virtual-link": {"required": False, "type": "list",
"virtual_link": {"required": False, "type": "list",
"options": {
"dead-interval": {"required": False, "type": "int"},
"hello-interval": {"required": False, "type": "int"},
"dead_interval": {"required": False, "type": "int"},
"hello_interval": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"},
"peer": {"required": False, "type": "str"},
"retransmit-interval": {"required": False, "type": "int"},
"transmit-delay": {"required": False, "type": "int"}
"retransmit_interval": {"required": False, "type": "int"},
"transmit_delay": {"required": False, "type": "int"}
}}
}},
"auto-cost-ref-bandwidth": {"required": False, "type": "int"},
"auto_cost_ref_bandwidth": {"required": False, "type": "int"},
"bfd": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"default-information-metric": {"required": False, "type": "int"},
"default-information-metric-type": {"required": False, "type": "str",
"default_information_metric": {"required": False, "type": "int"},
"default_information_metric_type": {"required": False, "type": "str",
"choices": ["1", "2"]},
"default-information-originate": {"required": False, "type": "str",
"default_information_originate": {"required": False, "type": "str",
"choices": ["enable", "always", "disable"]},
"default-information-route-map": {"required": False, "type": "str"},
"default-metric": {"required": False, "type": "int"},
"log-neighbour-changes": {"required": False, "type": "str",
"default_information_route_map": {"required": False, "type": "str"},
"default_metric": {"required": False, "type": "int"},
"log_neighbour_changes": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ospf6-interface": {"required": False, "type": "list",
"ospf6_interface": {"required": False, "type": "list",
"options": {
"area-id": {"required": False, "type": "str"},
"area_id": {"required": False, "type": "str"},
"bfd": {"required": False, "type": "str",
"choices": ["global", "enable", "disable"]},
"cost": {"required": False, "type": "int"},
"dead-interval": {"required": False, "type": "int"},
"hello-interval": {"required": False, "type": "int"},
"dead_interval": {"required": False, "type": "int"},
"hello_interval": {"required": False, "type": "int"},
"interface": {"required": False, "type": "str"},
"mtu": {"required": False, "type": "int"},
"mtu_ignore": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"},
"neighbor": {"required": False, "type": "list",
"options": {
"cost": {"required": False, "type": "int"},
"ip6": {"required": True, "type": "str"},
"poll-interval": {"required": False, "type": "int"},
"poll_interval": {"required": False, "type": "int"},
"priority": {"required": False, "type": "int"}
}},
"network-type": {"required": False, "type": "str",
"network_type": {"required": False, "type": "str",
"choices": ["broadcast", "point-to-point", "non-broadcast",
"point-to-multipoint", "point-to-multipoint-non-broadcast"]},
"priority": {"required": False, "type": "int"},
"retransmit-interval": {"required": False, "type": "int"},
"retransmit_interval": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"transmit-delay": {"required": False, "type": "int"}
"transmit_delay": {"required": False, "type": "int"}
}},
"passive-interface": {"required": False, "type": "list",
"passive_interface": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"redistribute": {"required": False, "type": "list",
"options": {
"metric": {"required": False, "type": "int"},
"metric-type": {"required": False, "type": "str",
"metric_type": {"required": False, "type": "str",
"choices": ["1", "2"]},
"name": {"required": True, "type": "str"},
"routemap": {"required": False, "type": "str"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"router-id": {"required": False, "type": "str"},
"spf-timers": {"required": False, "type": "str"},
"summary-address": {"required": False, "type": "list",
"router_id": {"required": False, "type": "str"},
"spf_timers": {"required": False, "type": "str"},
"summary_address": {"required": False, "type": "list",
"options": {
"advertise": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
@ -675,15 +768,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_policy
short_description: Configure IPv4 routing policies in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and policy category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,138 +41,175 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
router_policy:
description:
- Configure IPv4 routing policies.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
action:
description:
- Action of the policy route.
type: str
choices:
- deny
- permit
comments:
description:
- Optional comments.
type: str
dst:
description:
- Destination IP and mask (x.x.x.x/x).
type: list
suboptions:
subnet:
description:
- IP and mask.
required: true
dst-negate:
type: str
dst_negate:
description:
- Enable/disable negating destination address match.
type: str
choices:
- enable
- disable
dstaddr:
description:
- Destination address name.
type: list
suboptions:
name:
description:
- Address/group name. Source firewall.address.name firewall.addrgrp.name.
required: true
end-port:
type: str
end_port:
description:
- End destination port number (0 - 65535).
end-source-port:
type: int
end_source_port:
description:
- End source port number (0 - 65535).
type: int
gateway:
description:
- IP address of the gateway.
input-device:
type: str
input_device:
description:
- Incoming interface name.
type: list
suboptions:
name:
description:
- Interface name. Source system.interface.name.
required: true
output-device:
type: str
output_device:
description:
- Outgoing interface name. Source system.interface.name.
type: str
protocol:
description:
- Protocol number (0 - 255).
seq-num:
type: int
seq_num:
description:
- Sequence number.
required: true
type: int
src:
description:
- Source IP and mask (x.x.x.x/x).
type: list
suboptions:
subnet:
description:
- IP and mask.
required: true
src-negate:
type: str
src_negate:
description:
- Enable/disable negating source address match.
type: str
choices:
- enable
- disable
srcaddr:
description:
- Source address name.
type: list
suboptions:
name:
description:
- Address/group name. Source firewall.address.name firewall.addrgrp.name.
required: true
start-port:
type: str
start_port:
description:
- Start destination port number (0 - 65535).
start-source-port:
type: int
start_source_port:
description:
- Start source port number (0 - 65535).
type: int
status:
description:
- Enable/disable this policy route.
type: str
choices:
- enable
- disable
tos:
description:
- Type of service bit pattern.
tos-mask:
type: str
tos_mask:
description:
- Type of service evaluated bits.
type: str
'''
EXAMPLES = '''
@ -185,6 +219,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv4 routing policies.
fortios_router_policy:
@ -193,38 +228,38 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_policy:
state: "present"
action: "deny"
comments: "<your_own_value>"
dst:
-
subnet: "<your_own_value>"
dst-negate: "enable"
dst_negate: "enable"
dstaddr:
-
name: "default_name_9 (source firewall.address.name firewall.addrgrp.name)"
end-port: "10"
end-source-port: "11"
end_port: "10"
end_source_port: "11"
gateway: "<your_own_value>"
input-device:
input_device:
-
name: "default_name_14 (source system.interface.name)"
output-device: "<your_own_value> (source system.interface.name)"
output_device: "<your_own_value> (source system.interface.name)"
protocol: "16"
seq-num: "17"
seq_num: "17"
src:
-
subnet: "<your_own_value>"
src-negate: "enable"
src_negate: "enable"
srcaddr:
-
name: "default_name_22 (source firewall.address.name firewall.addrgrp.name)"
start-port: "23"
start-source-port: "24"
start_port: "23"
start_source_port: "24"
status: "enable"
tos: "<your_own_value>"
tos-mask: "<your_own_value>"
tos_mask: "<your_own_value>"
'''
RETURN = '''
@ -287,14 +322,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -302,17 +339,17 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_policy_data(json):
option_list = ['action', 'comments', 'dst',
'dst-negate', 'dstaddr', 'end-port',
'end-source-port', 'gateway', 'input-device',
'output-device', 'protocol', 'seq-num',
'src', 'src-negate', 'srcaddr',
'start-port', 'start-source-port', 'status',
'tos', 'tos-mask']
'dst_negate', 'dstaddr', 'end_port',
'end_source_port', 'gateway', 'input_device',
'output_device', 'protocol', 'seq_num',
'src', 'src_negate', 'srcaddr',
'start_port', 'start_source_port', 'status',
'tos', 'tos_mask']
dictionary = {}
for attribute in option_list:
@ -322,61 +359,66 @@ def filter_router_policy_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_policy(data, fos):
vdom = data['vdom']
state = data['state']
router_policy_data = data['router_policy']
flattened_data = flatten_multilists_attributes(router_policy_data)
filtered_data = filter_router_policy_data(flattened_data)
if router_policy_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_policy_data(router_policy_data))
if state == "present":
return fos.set('router',
'policy',
data=filtered_data,
vdom=vdom)
elif router_policy_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'policy',
mkey=filtered_data['seq-num'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_policy']:
resp = router_policy(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_policy": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"action": {"required": False, "type": "str",
"choices": ["deny", "permit"]},
"comments": {"required": False, "type": "str"},
@ -384,38 +426,38 @@ def main():
"options": {
"subnet": {"required": True, "type": "str"}
}},
"dst-negate": {"required": False, "type": "str",
"dst_negate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"dstaddr": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"end-port": {"required": False, "type": "int"},
"end-source-port": {"required": False, "type": "int"},
"end_port": {"required": False, "type": "int"},
"end_source_port": {"required": False, "type": "int"},
"gateway": {"required": False, "type": "str"},
"input-device": {"required": False, "type": "list",
"input_device": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"output-device": {"required": False, "type": "str"},
"output_device": {"required": False, "type": "str"},
"protocol": {"required": False, "type": "int"},
"seq-num": {"required": True, "type": "int"},
"seq_num": {"required": False, "type": "int"},
"src": {"required": False, "type": "list",
"options": {
"subnet": {"required": True, "type": "str"}
}},
"src-negate": {"required": False, "type": "str",
"src_negate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"srcaddr": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"start-port": {"required": False, "type": "int"},
"start-source-port": {"required": False, "type": "int"},
"start_port": {"required": False, "type": "int"},
"start_source_port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tos": {"required": False, "type": "str"},
"tos-mask": {"required": False, "type": "str"}
"tos_mask": {"required": False, "type": "str"}
}
}
@ -423,15 +465,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_policy6
short_description: Configure IPv6 routing policies in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and policy6 category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,83 +41,108 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
router_policy6:
description:
- Configure IPv6 routing policies.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comments:
description:
- Optional comments.
type: str
dst:
description:
- Destination IPv6 prefix.
end-port:
type: str
end_port:
description:
- End destination port number (1 - 65535).
type: int
gateway:
description:
- IPv6 address of the gateway.
input-device:
type: str
input_device:
description:
- Incoming interface name. Source system.interface.name.
output-device:
type: str
output_device:
description:
- Outgoing interface name. Source system.interface.name.
type: str
protocol:
description:
- Protocol number (0 - 255).
seq-num:
type: int
seq_num:
description:
- Sequence number.
required: true
type: int
src:
description:
- Source IPv6 prefix.
start-port:
type: str
start_port:
description:
- Start destination port number (1 - 65535).
type: int
status:
description:
- Enable/disable this policy route.
type: str
choices:
- enable
- disable
tos:
description:
- Type of service bit pattern.
tos-mask:
type: str
tos_mask:
description:
- Type of service evaluated bits.
type: str
'''
EXAMPLES = '''
@ -130,6 +152,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv6 routing policies.
fortios_router_policy6:
@ -138,21 +161,21 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_policy6:
state: "present"
comments: "<your_own_value>"
dst: "<your_own_value>"
end-port: "5"
end_port: "5"
gateway: "<your_own_value>"
input-device: "<your_own_value> (source system.interface.name)"
output-device: "<your_own_value> (source system.interface.name)"
input_device: "<your_own_value> (source system.interface.name)"
output_device: "<your_own_value> (source system.interface.name)"
protocol: "9"
seq-num: "10"
seq_num: "10"
src: "<your_own_value>"
start-port: "12"
start_port: "12"
status: "enable"
tos: "<your_own_value>"
tos-mask: "<your_own_value>"
tos_mask: "<your_own_value>"
'''
RETURN = '''
@ -215,14 +238,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -230,15 +255,15 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_policy6_data(json):
option_list = ['comments', 'dst', 'end-port',
'gateway', 'input-device', 'output-device',
'protocol', 'seq-num', 'src',
'start-port', 'status', 'tos',
'tos-mask']
option_list = ['comments', 'dst', 'end_port',
'gateway', 'input_device', 'output_device',
'protocol', 'seq_num', 'src',
'start_port', 'status', 'tos',
'tos_mask']
dictionary = {}
for attribute in option_list:
@ -248,75 +273,80 @@ def filter_router_policy6_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_policy6(data, fos):
vdom = data['vdom']
state = data['state']
router_policy6_data = data['router_policy6']
flattened_data = flatten_multilists_attributes(router_policy6_data)
filtered_data = filter_router_policy6_data(flattened_data)
if router_policy6_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_policy6_data(router_policy6_data))
if state == "present":
return fos.set('router',
'policy6',
data=filtered_data,
vdom=vdom)
elif router_policy6_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'policy6',
mkey=filtered_data['seq-num'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_policy6']:
resp = router_policy6(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_policy6": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comments": {"required": False, "type": "str"},
"dst": {"required": False, "type": "str"},
"end-port": {"required": False, "type": "int"},
"end_port": {"required": False, "type": "int"},
"gateway": {"required": False, "type": "str"},
"input-device": {"required": False, "type": "str"},
"output-device": {"required": False, "type": "str"},
"input_device": {"required": False, "type": "str"},
"output_device": {"required": False, "type": "str"},
"protocol": {"required": False, "type": "int"},
"seq-num": {"required": True, "type": "int"},
"seq_num": {"required": False, "type": "int"},
"src": {"required": False, "type": "str"},
"start-port": {"required": False, "type": "int"},
"start_port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tos": {"required": False, "type": "str"},
"tos-mask": {"required": False, "type": "str"}
"tos_mask": {"required": False, "type": "str"}
}
}
@ -324,15 +354,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_prefix_list
short_description: Configure IPv4 prefix lists in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and prefix_list category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,73 +41,95 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
router_prefix_list:
description:
- Configure IPv4 prefix lists.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comments:
description:
- Comment.
type: str
name:
description:
- Name.
required: true
type: str
rule:
description:
- IPv4 prefix list rule.
type: list
suboptions:
action:
description:
- Permit or deny this IP address and netmask prefix.
type: str
choices:
- permit
- deny
flags:
description:
- Flags.
type: int
ge:
description:
- Minimum prefix length to be matched (0 - 32).
type: int
id:
description:
- Rule ID.
required: true
type: int
le:
description:
- Maximum prefix length to be matched (0 - 32).
type: int
prefix:
description:
- IPv4 prefix to define regular filter criteria, such as "any" or subnets.
type: str
'''
EXAMPLES = '''
@ -120,6 +139,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv4 prefix lists.
fortios_router_prefix_list:
@ -128,8 +148,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_prefix_list:
state: "present"
comments: "<your_own_value>"
name: "default_name_4"
rule:
@ -202,14 +222,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -217,7 +239,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_prefix_list_data(json):
@ -231,61 +253,66 @@ def filter_router_prefix_list_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_prefix_list(data, fos):
vdom = data['vdom']
state = data['state']
router_prefix_list_data = data['router_prefix_list']
flattened_data = flatten_multilists_attributes(router_prefix_list_data)
filtered_data = filter_router_prefix_list_data(flattened_data)
if router_prefix_list_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_prefix_list_data(router_prefix_list_data))
if state == "present":
return fos.set('router',
'prefix-list',
data=filtered_data,
vdom=vdom)
elif router_prefix_list_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'prefix-list',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_prefix_list']:
resp = router_prefix_list(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_prefix_list": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comments": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"rule": {"required": False, "type": "list",
@ -305,15 +332,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_rip
short_description: Configure RIP in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and rip category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,67 +41,86 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_rip:
description:
- Configure RIP.
default: null
type: dict
suboptions:
default-information-originate:
default_information_originate:
description:
- Enable/disable generation of default route.
type: str
choices:
- enable
- disable
default-metric:
default_metric:
description:
- Default metric.
type: int
distance:
description:
- distance
type: list
suboptions:
access-list:
access_list:
description:
- Access list for route destination. Source router.access-list.name.
type: str
distance:
description:
- Distance (1 - 255).
type: int
id:
description:
- Distance ID.
required: true
type: int
prefix:
description:
- Distance prefix.
distribute-list:
type: str
distribute_list:
description:
- Distribute list.
type: list
suboptions:
direction:
description:
- Distribute list direction.
type: str
choices:
- in
- out
@ -112,110 +128,136 @@ options:
description:
- Distribute list ID.
required: true
type: int
interface:
description:
- Distribute list interface name. Source system.interface.name.
type: str
listname:
description:
- Distribute access/prefix list name. Source router.access-list.name router.prefix-list.name.
type: str
status:
description:
- status
type: str
choices:
- enable
- disable
garbage-timer:
garbage_timer:
description:
- Garbage timer in seconds.
type: int
interface:
description:
- RIP interface configuration.
type: list
suboptions:
auth-keychain:
auth_keychain:
description:
- Authentication key-chain name. Source router.key-chain.name.
auth-mode:
type: str
auth_mode:
description:
- Authentication mode.
type: str
choices:
- none
- text
- md5
auth-string:
auth_string:
description:
- Authentication string/password.
type: str
flags:
description:
- flags
type: int
name:
description:
- Interface name. Source system.interface.name.
required: true
receive-version:
type: str
receive_version:
description:
- Receive version.
type: str
choices:
- 1
- 2
send-version:
send_version:
description:
- Send version.
type: str
choices:
- 1
- 2
send-version2-broadcast:
send_version2_broadcast:
description:
- Enable/disable broadcast version 1 compatible packets.
type: str
choices:
- disable
- enable
split-horizon:
split_horizon:
description:
- Enable/disable split horizon.
type: str
choices:
- poisoned
- regular
split-horizon-status:
split_horizon_status:
description:
- Enable/disable split horizon.
type: str
choices:
- enable
- disable
max-out-metric:
max_out_metric:
description:
- Maximum metric allowed to output(0 means 'not set').
type: int
neighbor:
description:
- neighbor
type: list
suboptions:
id:
description:
- Neighbor entry ID.
required: true
type: int
ip:
description:
- IP address.
type: str
network:
description:
- network
type: list
suboptions:
id:
description:
- Network entry ID.
required: true
type: int
prefix:
description:
- Network prefix.
offset-list:
type: str
offset_list:
description:
- Offset list.
type: list
suboptions:
access-list:
access_list:
description:
- Access list name. Source router.access-list.name.
type: str
direction:
description:
- Offset list direction.
type: str
choices:
- in
- out
@ -223,58 +265,73 @@ options:
description:
- Offset-list ID.
required: true
type: int
interface:
description:
- Interface name. Source system.interface.name.
type: str
offset:
description:
- offset
type: int
status:
description:
- status
type: str
choices:
- enable
- disable
passive-interface:
passive_interface:
description:
- Passive interface configuration.
type: list
suboptions:
name:
description:
- Passive interface name. Source system.interface.name.
required: true
recv-buffer-size:
type: str
recv_buffer_size:
description:
- Receiving buffer size.
type: int
redistribute:
description:
- Redistribute configuration.
type: list
suboptions:
metric:
description:
- Redistribute metric setting.
type: int
name:
description:
- Redistribute name.
required: true
type: str
routemap:
description:
- Route map name. Source router.route-map.name.
type: str
status:
description:
- status
type: str
choices:
- enable
- disable
timeout-timer:
timeout_timer:
description:
- Timeout timer in seconds.
update-timer:
type: int
update_timer:
description:
- Update timer in seconds.
type: int
version:
description:
- RIP version.
type: str
choices:
- 1
- 2
@ -287,6 +344,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure RIP.
fortios_router_rip:
@ -296,35 +354,35 @@ EXAMPLES = '''
vdom: "{{ vdom }}"
https: "False"
router_rip:
default-information-originate: "enable"
default-metric: "4"
default_information_originate: "enable"
default_metric: "4"
distance:
-
access-list: "<your_own_value> (source router.access-list.name)"
access_list: "<your_own_value> (source router.access-list.name)"
distance: "7"
id: "8"
prefix: "<your_own_value>"
distribute-list:
distribute_list:
-
direction: "in"
id: "12"
interface: "<your_own_value> (source system.interface.name)"
listname: "<your_own_value> (source router.access-list.name router.prefix-list.name)"
status: "enable"
garbage-timer: "16"
garbage_timer: "16"
interface:
-
auth-keychain: "<your_own_value> (source router.key-chain.name)"
auth-mode: "none"
auth-string: "<your_own_value>"
auth_keychain: "<your_own_value> (source router.key-chain.name)"
auth_mode: "none"
auth_string: "<your_own_value>"
flags: "21"
name: "default_name_22 (source system.interface.name)"
receive-version: "1"
send-version: "1"
send-version2-broadcast: "disable"
split-horizon: "poisoned"
split-horizon-status: "enable"
max-out-metric: "28"
receive_version: "1"
send_version: "1"
send_version2_broadcast: "disable"
split_horizon: "poisoned"
split_horizon_status: "enable"
max_out_metric: "28"
neighbor:
-
id: "30"
@ -333,26 +391,26 @@ EXAMPLES = '''
-
id: "33"
prefix: "<your_own_value>"
offset-list:
offset_list:
-
access-list: "<your_own_value> (source router.access-list.name)"
access_list: "<your_own_value> (source router.access-list.name)"
direction: "in"
id: "38"
interface: "<your_own_value> (source system.interface.name)"
offset: "40"
status: "enable"
passive-interface:
passive_interface:
-
name: "default_name_43 (source system.interface.name)"
recv-buffer-size: "44"
recv_buffer_size: "44"
redistribute:
-
metric: "46"
name: "default_name_47"
routemap: "<your_own_value> (source router.route-map.name)"
status: "enable"
timeout-timer: "50"
update-timer: "51"
timeout_timer: "50"
update_timer: "51"
version: "1"
'''
@ -416,14 +474,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -431,15 +491,15 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_rip_data(json):
option_list = ['default-information-originate', 'default-metric', 'distance',
'distribute-list', 'garbage-timer', 'interface',
'max-out-metric', 'neighbor', 'network',
'offset-list', 'passive-interface', 'recv-buffer-size',
'redistribute', 'timeout-timer', 'update-timer',
option_list = ['default_information_originate', 'default_metric', 'distance',
'distribute_list', 'garbage_timer', 'interface',
'max_out_metric', 'neighbor', 'network',
'offset_list', 'passive_interface', 'recv_buffer_size',
'redistribute', 'timeout_timer', 'update_timer',
'version']
dictionary = {}
@ -450,17 +510,15 @@ def filter_router_rip_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -468,45 +526,51 @@ def flatten_multilists_attributes(data):
def router_rip(data, fos):
vdom = data['vdom']
router_rip_data = data['router_rip']
flattened_data = flatten_multilists_attributes(router_rip_data)
filtered_data = filter_router_rip_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_rip_data(router_rip_data))
return fos.set('router',
'rip',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_rip']:
resp = router_rip(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_rip": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"default-information-originate": {"required": False, "type": "str",
"default_information_originate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"default-metric": {"required": False, "type": "int"},
"default_metric": {"required": False, "type": "int"},
"distance": {"required": False, "type": "list",
"options": {
"access-list": {"required": False, "type": "str"},
"access_list": {"required": False, "type": "str"},
"distance": {"required": False, "type": "int"},
"id": {"required": True, "type": "int"},
"prefix": {"required": False, "type": "str"}
}},
"distribute-list": {"required": False, "type": "list",
"distribute_list": {"required": False, "type": "list",
"options": {
"direction": {"required": False, "type": "str",
"choices": ["in", "out"]},
@ -516,27 +580,27 @@ def main():
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"garbage-timer": {"required": False, "type": "int"},
"garbage_timer": {"required": False, "type": "int"},
"interface": {"required": False, "type": "list",
"options": {
"auth-keychain": {"required": False, "type": "str"},
"auth-mode": {"required": False, "type": "str",
"auth_keychain": {"required": False, "type": "str"},
"auth_mode": {"required": False, "type": "str",
"choices": ["none", "text", "md5"]},
"auth-string": {"required": False, "type": "str"},
"auth_string": {"required": False, "type": "str"},
"flags": {"required": False, "type": "int"},
"name": {"required": True, "type": "str"},
"receive-version": {"required": False, "type": "str",
"receive_version": {"required": False, "type": "str",
"choices": ["1", "2"]},
"send-version": {"required": False, "type": "str",
"send_version": {"required": False, "type": "str",
"choices": ["1", "2"]},
"send-version2-broadcast": {"required": False, "type": "str",
"send_version2_broadcast": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"split-horizon": {"required": False, "type": "str",
"split_horizon": {"required": False, "type": "str",
"choices": ["poisoned", "regular"]},
"split-horizon-status": {"required": False, "type": "str",
"split_horizon_status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"max-out-metric": {"required": False, "type": "int"},
"max_out_metric": {"required": False, "type": "int"},
"neighbor": {"required": False, "type": "list",
"options": {
"id": {"required": True, "type": "int"},
@ -547,9 +611,9 @@ def main():
"id": {"required": True, "type": "int"},
"prefix": {"required": False, "type": "str"}
}},
"offset-list": {"required": False, "type": "list",
"offset_list": {"required": False, "type": "list",
"options": {
"access-list": {"required": False, "type": "str"},
"access_list": {"required": False, "type": "str"},
"direction": {"required": False, "type": "str",
"choices": ["in", "out"]},
"id": {"required": True, "type": "int"},
@ -558,11 +622,11 @@ def main():
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"passive-interface": {"required": False, "type": "list",
"passive_interface": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"recv-buffer-size": {"required": False, "type": "int"},
"recv_buffer_size": {"required": False, "type": "int"},
"redistribute": {"required": False, "type": "list",
"options": {
"metric": {"required": False, "type": "int"},
@ -571,8 +635,8 @@ def main():
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"timeout-timer": {"required": False, "type": "int"},
"update-timer": {"required": False, "type": "int"},
"timeout_timer": {"required": False, "type": "int"},
"update_timer": {"required": False, "type": "int"},
"version": {"required": False, "type": "str",
"choices": ["1", "2"]}
@ -582,15 +646,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_setting
short_description: Configure router settings in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and setting category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,40 +41,52 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
router_setting:
description:
- Configure router settings.
default: null
type: dict
suboptions:
hostname:
description:
- Hostname for this virtual domain router.
show-filter:
type: str
show_filter:
description:
- Prefix-list as filter for showing routes. Source router.prefix-list.name.
type: str
'''
EXAMPLES = '''
@ -87,6 +96,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure router settings.
fortios_router_setting:
@ -97,7 +107,7 @@ EXAMPLES = '''
https: "False"
router_setting:
hostname: "myhostname"
show-filter: "<your_own_value> (source router.prefix-list.name)"
show_filter: "<your_own_value> (source router.prefix-list.name)"
'''
RETURN = '''
@ -160,14 +170,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -175,11 +187,11 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_setting_data(json):
option_list = ['hostname', 'show-filter']
option_list = ['hostname', 'show_filter']
dictionary = {}
for attribute in option_list:
@ -189,17 +201,15 @@ def filter_router_setting_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
@ -207,36 +217,42 @@ def flatten_multilists_attributes(data):
def router_setting(data, fos):
vdom = data['vdom']
router_setting_data = data['router_setting']
flattened_data = flatten_multilists_attributes(router_setting_data)
filtered_data = filter_router_setting_data(flattened_data)
filtered_data = underscore_to_hyphen(filter_router_setting_data(router_setting_data))
return fos.set('router',
'setting',
data=filtered_data,
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_setting']:
resp = router_setting(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"router_setting": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"hostname": {"required": False, "type": "str"},
"show-filter": {"required": False, "type": "str"}
"show_filter": {"required": False, "type": "str"}
}
}
@ -244,15 +260,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
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
# 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
@ -29,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_router_static
short_description: Configure IPv4 static routing tables in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify router feature and static category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,116 +41,147 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
router_static:
description:
- Configure IPv4 static routing tables.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
bfd:
description:
- Enable/disable Bidirectional Forwarding Detection (BFD).
type: str
choices:
- enable
- disable
blackhole:
description:
- Enable/disable black hole.
type: str
choices:
- enable
- disable
comment:
description:
- Optional comments.
type: str
device:
description:
- Gateway out interface or tunnel. Source system.interface.name.
type: str
distance:
description:
- Administrative distance (1 - 255).
type: int
dst:
description:
- Destination IP and mask for this route.
type: str
dstaddr:
description:
- Name of firewall address or address group. Source firewall.address.name firewall.addrgrp.name.
dynamic-gateway:
type: str
dynamic_gateway:
description:
- Enable use of dynamic gateway retrieved from a DHCP or PPP server.
type: str
choices:
- enable
- disable
gateway:
description:
- Gateway IP for this route.
internet-service:
type: str
internet_service:
description:
- Application ID in the Internet service database. Source firewall.internet-service.id.
internet-service-custom:
type: int
internet_service_custom:
description:
- Application name in the Internet service custom database. Source firewall.internet-service-custom.name.
link-monitor-exempt:
type: str
link_monitor_exempt:
description:
- Enable/disable withdrawing this route when link monitor or health check is down.
type: str
choices:
- enable
- disable
priority:
description:
- Administrative priority (0 - 4294967295).
seq-num:
type: int
seq_num:
description:
- Sequence number.
required: true
type: int
src:
description:
- Source prefix for this route.
type: str
status:
description:
- Enable/disable this static route.
type: str
choices:
- enable
- disable
virtual-wan-link:
virtual_wan_link:
description:
- Enable/disable egress through the virtual-wan-link.
type: str
choices:
- enable
- disable
vrf:
description:
- Virtual Routing Forwarding ID.
type: int
weight:
description:
- Administrative weight (0 - 255).
type: int
'''
EXAMPLES = '''
@ -163,6 +191,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPv4 static routing tables.
fortios_router_static:
@ -171,8 +200,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
router_static:
state: "present"
bfd: "enable"
blackhole: "enable"
comment: "Optional comments."
@ -180,16 +209,16 @@ EXAMPLES = '''
distance: "7"
dst: "<your_own_value>"
dstaddr: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
dynamic-gateway: "enable"
dynamic_gateway: "enable"
gateway: "<your_own_value>"
internet-service: "12 (source firewall.internet-service.id)"
internet-service-custom: "<your_own_value> (source firewall.internet-service-custom.name)"
link-monitor-exempt: "enable"
internet_service: "12 (source firewall.internet-service.id)"
internet_service_custom: "<your_own_value> (source firewall.internet-service-custom.name)"
link_monitor_exempt: "enable"
priority: "15"
seq-num: "16"
seq_num: "16"
src: "<your_own_value>"
status: "enable"
virtual-wan-link: "enable"
virtual_wan_link: "enable"
vrf: "20"
weight: "21"
'''
@ -254,14 +283,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -269,16 +300,16 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_router_static_data(json):
option_list = ['bfd', 'blackhole', 'comment',
'device', 'distance', 'dst',
'dstaddr', 'dynamic-gateway', 'gateway',
'internet-service', 'internet-service-custom', 'link-monitor-exempt',
'priority', 'seq-num', 'src',
'status', 'virtual-wan-link', 'vrf',
'dstaddr', 'dynamic_gateway', 'gateway',
'internet_service', 'internet_service_custom', 'link_monitor_exempt',
'priority', 'seq_num', 'src',
'status', 'virtual_wan_link', 'vrf',
'weight']
dictionary = {}
@ -289,61 +320,66 @@ def filter_router_static_data(json):
return dictionary
def flatten_multilists_attributes(data):
multilist_attrs = []
for attr in multilist_attrs:
try:
path = "data['" + "']['".join(elem for elem in attr) + "']"
current_val = eval(path)
flattened_val = ' '.join(elem for elem in current_val)
exec(path + '= flattened_val')
except BaseException:
pass
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def router_static(data, fos):
vdom = data['vdom']
state = data['state']
router_static_data = data['router_static']
flattened_data = flatten_multilists_attributes(router_static_data)
filtered_data = filter_router_static_data(flattened_data)
if router_static_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_router_static_data(router_static_data))
if state == "present":
return fos.set('router',
'static',
data=filtered_data,
vdom=vdom)
elif router_static_data['state'] == "absent":
elif state == "absent":
return fos.delete('router',
'static',
mkey=filtered_data['seq-num'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_router(data, fos):
login(data)
if data['router_static']:
resp = router_static(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"router_static": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"bfd": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"blackhole": {"required": False, "type": "str",
@ -353,19 +389,19 @@ def main():
"distance": {"required": False, "type": "int"},
"dst": {"required": False, "type": "str"},
"dstaddr": {"required": False, "type": "str"},
"dynamic-gateway": {"required": False, "type": "str",
"dynamic_gateway": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"gateway": {"required": False, "type": "str"},
"internet-service": {"required": False, "type": "int"},
"internet-service-custom": {"required": False, "type": "str"},
"link-monitor-exempt": {"required": False, "type": "str",
"internet_service": {"required": False, "type": "int"},
"internet_service_custom": {"required": False, "type": "str"},
"link_monitor_exempt": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"priority": {"required": False, "type": "int"},
"seq-num": {"required": True, "type": "int"},
"seq_num": {"required": False, "type": "int"},
"src": {"required": False, "type": "str"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"virtual-wan-link": {"required": False, "type": "str",
"virtual_wan_link": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"vrf": {"required": False, "type": "int"},
"weight": {"required": False, "type": "int"}
@ -376,15 +412,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_router(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_router(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_router(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -3695,43 +3695,6 @@ lib/ansible/modules/network/fortios/fortios_firewall_sniffer.py validate-modules
lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_ipv4_policy.py validate-modules:E338
lib/ansible/modules/network/fortios/fortios_report_chart.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_report_layout.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_report_layout.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_report_setting.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_report_setting.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_report_style.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_report_style.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_report_theme.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_report_theme.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_access_list.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_access_list.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_auth_path.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_bfd.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_bfd6.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_bfd6.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_bgp.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_bgp.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_multicast.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_multicast.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_multicast6.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_multicast6.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_multicast_flow.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_multicast_flow.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_ospf.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_ospf.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_ospf6.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_ospf6.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_policy.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_policy.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_policy6.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_policy6.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_prefix_list.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_rip.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_rip.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_setting.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_setting.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_router_static.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_router_static.py validate-modules:E337
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

@ -0,0 +1,329 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <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_report_layout
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_report_layout.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_report_layout_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',
'report_layout': {'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
expected_data = {'cutoff-option': 'run-time',
'cutoff-time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email-recipients': 'test_value_7',
'email-send': 'enable',
'format': 'pdf',
'max-pdf-report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule-type': 'demand',
'style-theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
}
set_method_mock.assert_called_with('report', 'layout', 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_report_layout_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',
'report_layout': {'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
expected_data = {'cutoff-option': 'run-time',
'cutoff-time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email-recipients': 'test_value_7',
'email-send': 'enable',
'format': 'pdf',
'max-pdf-report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule-type': 'demand',
'style-theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
}
set_method_mock.assert_called_with('report', 'layout', 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_report_layout_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',
'report_layout': {'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'layout', 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_report_layout_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',
'report_layout': {'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'layout', 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_report_layout_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',
'report_layout': {'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
expected_data = {'cutoff-option': 'run-time',
'cutoff-time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email-recipients': 'test_value_7',
'email-send': 'enable',
'format': 'pdf',
'max-pdf-report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule-type': 'demand',
'style-theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
}
set_method_mock.assert_called_with('report', 'layout', 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_report_layout_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',
'report_layout': {
'random_attribute_not_valid': 'tag', 'cutoff_option': 'run-time',
'cutoff_time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email_recipients': 'test_value_7',
'email_send': 'enable',
'format': 'pdf',
'max_pdf_report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule_type': 'demand',
'style_theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_layout.fortios_report(input_data, fos_instance)
expected_data = {'cutoff-option': 'run-time',
'cutoff-time': 'test_value_4',
'day': 'sunday',
'description': 'test_value_6',
'email-recipients': 'test_value_7',
'email-send': 'enable',
'format': 'pdf',
'max-pdf-report': '10',
'name': 'default_name_11',
'options': 'include-table-of-content',
'schedule-type': 'demand',
'style-theme': 'test_value_14',
'subtitle': 'test_value_15',
'time': 'test_value_16',
'title': 'test_value_17'
}
set_method_mock.assert_called_with('report', 'layout', 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_report_setting
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_report_setting.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_report_setting_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'report_setting': {
'fortiview': 'enable',
'pdf_report': 'enable',
'report_source': 'forward-traffic',
'top_n': '6',
'web_browsing_threshold': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_setting.fortios_report(input_data, fos_instance)
expected_data = {
'fortiview': 'enable',
'pdf-report': 'enable',
'report-source': 'forward-traffic',
'top-n': '6',
'web-browsing-threshold': '7'
}
set_method_mock.assert_called_with('report', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_report_setting_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'report_setting': {
'fortiview': 'enable',
'pdf_report': 'enable',
'report_source': 'forward-traffic',
'top_n': '6',
'web_browsing_threshold': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_setting.fortios_report(input_data, fos_instance)
expected_data = {
'fortiview': 'enable',
'pdf-report': 'enable',
'report-source': 'forward-traffic',
'top-n': '6',
'web-browsing-threshold': '7'
}
set_method_mock.assert_called_with('report', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_report_setting_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'report_setting': {
'fortiview': 'enable',
'pdf_report': 'enable',
'report_source': 'forward-traffic',
'top_n': '6',
'web_browsing_threshold': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_setting.fortios_report(input_data, fos_instance)
expected_data = {
'fortiview': 'enable',
'pdf-report': 'enable',
'report-source': 'forward-traffic',
'top-n': '6',
'web-browsing-threshold': '7'
}
set_method_mock.assert_called_with('report', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_report_setting_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'report_setting': {
'random_attribute_not_valid': 'tag',
'fortiview': 'enable',
'pdf_report': 'enable',
'report_source': 'forward-traffic',
'top_n': '6',
'web_browsing_threshold': '7'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_setting.fortios_report(input_data, fos_instance)
expected_data = {
'fortiview': 'enable',
'pdf-report': 'enable',
'report-source': 'forward-traffic',
'top-n': '6',
'web-browsing-threshold': '7'
}
set_method_mock.assert_called_with('report', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,449 @@
# 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_report_style
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_report_style.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_report_style_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',
'report_style': {
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
expected_data = {
'align': 'left',
'bg-color': 'test_value_4',
'border-bottom': 'test_value_5',
'border-left': 'test_value_6',
'border-right': 'test_value_7',
'border-top': 'test_value_8',
'column-gap': 'test_value_9',
'column-span': 'none',
'fg-color': 'test_value_11',
'font-family': 'Verdana',
'font-size': 'test_value_13',
'font-style': 'normal',
'font-weight': 'normal',
'height': 'test_value_16',
'line-height': 'test_value_17',
'margin-bottom': 'test_value_18',
'margin-left': 'test_value_19',
'margin-right': 'test_value_20',
'margin-top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding-bottom': 'test_value_24',
'padding-left': 'test_value_25',
'padding-right': 'test_value_26',
'padding-top': 'test_value_27',
'width': 'test_value_28'
}
set_method_mock.assert_called_with('report', 'style', 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_report_style_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',
'report_style': {
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
expected_data = {
'align': 'left',
'bg-color': 'test_value_4',
'border-bottom': 'test_value_5',
'border-left': 'test_value_6',
'border-right': 'test_value_7',
'border-top': 'test_value_8',
'column-gap': 'test_value_9',
'column-span': 'none',
'fg-color': 'test_value_11',
'font-family': 'Verdana',
'font-size': 'test_value_13',
'font-style': 'normal',
'font-weight': 'normal',
'height': 'test_value_16',
'line-height': 'test_value_17',
'margin-bottom': 'test_value_18',
'margin-left': 'test_value_19',
'margin-right': 'test_value_20',
'margin-top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding-bottom': 'test_value_24',
'padding-left': 'test_value_25',
'padding-right': 'test_value_26',
'padding-top': 'test_value_27',
'width': 'test_value_28'
}
set_method_mock.assert_called_with('report', 'style', 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_report_style_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',
'report_style': {
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'style', 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_report_style_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',
'report_style': {
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'style', 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_report_style_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',
'report_style': {
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
expected_data = {
'align': 'left',
'bg-color': 'test_value_4',
'border-bottom': 'test_value_5',
'border-left': 'test_value_6',
'border-right': 'test_value_7',
'border-top': 'test_value_8',
'column-gap': 'test_value_9',
'column-span': 'none',
'fg-color': 'test_value_11',
'font-family': 'Verdana',
'font-size': 'test_value_13',
'font-style': 'normal',
'font-weight': 'normal',
'height': 'test_value_16',
'line-height': 'test_value_17',
'margin-bottom': 'test_value_18',
'margin-left': 'test_value_19',
'margin-right': 'test_value_20',
'margin-top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding-bottom': 'test_value_24',
'padding-left': 'test_value_25',
'padding-right': 'test_value_26',
'padding-top': 'test_value_27',
'width': 'test_value_28'
}
set_method_mock.assert_called_with('report', 'style', 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_report_style_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',
'report_style': {
'random_attribute_not_valid': 'tag',
'align': 'left',
'bg_color': 'test_value_4',
'border_bottom': 'test_value_5',
'border_left': 'test_value_6',
'border_right': 'test_value_7',
'border_top': 'test_value_8',
'column_gap': 'test_value_9',
'column_span': 'none',
'fg_color': 'test_value_11',
'font_family': 'Verdana',
'font_size': 'test_value_13',
'font_style': 'normal',
'font_weight': 'normal',
'height': 'test_value_16',
'line_height': 'test_value_17',
'margin_bottom': 'test_value_18',
'margin_left': 'test_value_19',
'margin_right': 'test_value_20',
'margin_top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding_bottom': 'test_value_24',
'padding_left': 'test_value_25',
'padding_right': 'test_value_26',
'padding_top': 'test_value_27',
'width': 'test_value_28'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_style.fortios_report(input_data, fos_instance)
expected_data = {
'align': 'left',
'bg-color': 'test_value_4',
'border-bottom': 'test_value_5',
'border-left': 'test_value_6',
'border-right': 'test_value_7',
'border-top': 'test_value_8',
'column-gap': 'test_value_9',
'column-span': 'none',
'fg-color': 'test_value_11',
'font-family': 'Verdana',
'font-size': 'test_value_13',
'font-style': 'normal',
'font-weight': 'normal',
'height': 'test_value_16',
'line-height': 'test_value_17',
'margin-bottom': 'test_value_18',
'margin-left': 'test_value_19',
'margin-right': 'test_value_20',
'margin-top': 'test_value_21',
'name': 'default_name_22',
'options': 'font',
'padding-bottom': 'test_value_24',
'padding-left': 'test_value_25',
'padding-right': 'test_value_26',
'padding-top': 'test_value_27',
'width': 'test_value_28'
}
set_method_mock.assert_called_with('report', 'style', 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_report_theme
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_report_theme.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_report_theme_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',
'report_theme': {
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
expected_data = {
'bullet-list-style': 'test_value_3',
'column-count': '1',
'default-html-style': 'test_value_5',
'default-pdf-style': 'test_value_6',
'graph-chart-style': 'test_value_7',
'heading1-style': 'test_value_8',
'heading2-style': 'test_value_9',
'heading3-style': 'test_value_10',
'heading4-style': 'test_value_11',
'hline-style': 'test_value_12',
'image-style': 'test_value_13',
'name': 'default_name_14',
'normal-text-style': 'test_value_15',
'numbered-list-style': 'test_value_16',
'page-footer-style': 'test_value_17',
'page-header-style': 'test_value_18',
'page-orient': 'portrait',
'page-style': 'test_value_20',
'report-subtitle-style': 'test_value_21',
'report-title-style': 'test_value_22',
'table-chart-caption-style': 'test_value_23',
'table-chart-even-row-style': 'test_value_24',
'table-chart-head-style': 'test_value_25',
'table-chart-odd-row-style': 'test_value_26',
'table-chart-style': 'test_value_27',
'toc-heading1-style': 'test_value_28',
'toc-heading2-style': 'test_value_29',
'toc-heading3-style': 'test_value_30',
'toc-heading4-style': 'test_value_31',
'toc-title-style': 'test_value_32'
}
set_method_mock.assert_called_with('report', 'theme', 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_report_theme_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',
'report_theme': {
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
expected_data = {
'bullet-list-style': 'test_value_3',
'column-count': '1',
'default-html-style': 'test_value_5',
'default-pdf-style': 'test_value_6',
'graph-chart-style': 'test_value_7',
'heading1-style': 'test_value_8',
'heading2-style': 'test_value_9',
'heading3-style': 'test_value_10',
'heading4-style': 'test_value_11',
'hline-style': 'test_value_12',
'image-style': 'test_value_13',
'name': 'default_name_14',
'normal-text-style': 'test_value_15',
'numbered-list-style': 'test_value_16',
'page-footer-style': 'test_value_17',
'page-header-style': 'test_value_18',
'page-orient': 'portrait',
'page-style': 'test_value_20',
'report-subtitle-style': 'test_value_21',
'report-title-style': 'test_value_22',
'table-chart-caption-style': 'test_value_23',
'table-chart-even-row-style': 'test_value_24',
'table-chart-head-style': 'test_value_25',
'table-chart-odd-row-style': 'test_value_26',
'table-chart-style': 'test_value_27',
'toc-heading1-style': 'test_value_28',
'toc-heading2-style': 'test_value_29',
'toc-heading3-style': 'test_value_30',
'toc-heading4-style': 'test_value_31',
'toc-title-style': 'test_value_32'
}
set_method_mock.assert_called_with('report', 'theme', 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_report_theme_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',
'report_theme': {
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'theme', 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_report_theme_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',
'report_theme': {
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
delete_method_mock.assert_called_with('report', 'theme', 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_report_theme_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',
'report_theme': {
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
expected_data = {
'bullet-list-style': 'test_value_3',
'column-count': '1',
'default-html-style': 'test_value_5',
'default-pdf-style': 'test_value_6',
'graph-chart-style': 'test_value_7',
'heading1-style': 'test_value_8',
'heading2-style': 'test_value_9',
'heading3-style': 'test_value_10',
'heading4-style': 'test_value_11',
'hline-style': 'test_value_12',
'image-style': 'test_value_13',
'name': 'default_name_14',
'normal-text-style': 'test_value_15',
'numbered-list-style': 'test_value_16',
'page-footer-style': 'test_value_17',
'page-header-style': 'test_value_18',
'page-orient': 'portrait',
'page-style': 'test_value_20',
'report-subtitle-style': 'test_value_21',
'report-title-style': 'test_value_22',
'table-chart-caption-style': 'test_value_23',
'table-chart-even-row-style': 'test_value_24',
'table-chart-head-style': 'test_value_25',
'table-chart-odd-row-style': 'test_value_26',
'table-chart-style': 'test_value_27',
'toc-heading1-style': 'test_value_28',
'toc-heading2-style': 'test_value_29',
'toc-heading3-style': 'test_value_30',
'toc-heading4-style': 'test_value_31',
'toc-title-style': 'test_value_32'
}
set_method_mock.assert_called_with('report', 'theme', 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_report_theme_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',
'report_theme': {
'random_attribute_not_valid': 'tag',
'bullet_list_style': 'test_value_3',
'column_count': '1',
'default_html_style': 'test_value_5',
'default_pdf_style': 'test_value_6',
'graph_chart_style': 'test_value_7',
'heading1_style': 'test_value_8',
'heading2_style': 'test_value_9',
'heading3_style': 'test_value_10',
'heading4_style': 'test_value_11',
'hline_style': 'test_value_12',
'image_style': 'test_value_13',
'name': 'default_name_14',
'normal_text_style': 'test_value_15',
'numbered_list_style': 'test_value_16',
'page_footer_style': 'test_value_17',
'page_header_style': 'test_value_18',
'page_orient': 'portrait',
'page_style': 'test_value_20',
'report_subtitle_style': 'test_value_21',
'report_title_style': 'test_value_22',
'table_chart_caption_style': 'test_value_23',
'table_chart_even_row_style': 'test_value_24',
'table_chart_head_style': 'test_value_25',
'table_chart_odd_row_style': 'test_value_26',
'table_chart_style': 'test_value_27',
'toc_heading1_style': 'test_value_28',
'toc_heading2_style': 'test_value_29',
'toc_heading3_style': 'test_value_30',
'toc_heading4_style': 'test_value_31',
'toc_title_style': 'test_value_32'
},
'vdom': 'root'}
is_error, changed, response = fortios_report_theme.fortios_report(input_data, fos_instance)
expected_data = {
'bullet-list-style': 'test_value_3',
'column-count': '1',
'default-html-style': 'test_value_5',
'default-pdf-style': 'test_value_6',
'graph-chart-style': 'test_value_7',
'heading1-style': 'test_value_8',
'heading2-style': 'test_value_9',
'heading3-style': 'test_value_10',
'heading4-style': 'test_value_11',
'hline-style': 'test_value_12',
'image-style': 'test_value_13',
'name': 'default_name_14',
'normal-text-style': 'test_value_15',
'numbered-list-style': 'test_value_16',
'page-footer-style': 'test_value_17',
'page-header-style': 'test_value_18',
'page-orient': 'portrait',
'page-style': 'test_value_20',
'report-subtitle-style': 'test_value_21',
'report-title-style': 'test_value_22',
'table-chart-caption-style': 'test_value_23',
'table-chart-even-row-style': 'test_value_24',
'table-chart-head-style': 'test_value_25',
'table-chart-odd-row-style': 'test_value_26',
'table-chart-style': 'test_value_27',
'toc-heading1-style': 'test_value_28',
'toc-heading2-style': 'test_value_29',
'toc-heading3-style': 'test_value_30',
'toc-heading4-style': 'test_value_31',
'toc-title-style': 'test_value_32'
}
set_method_mock.assert_called_with('report', 'theme', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_access_list
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_router_access_list.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_access_list_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_access_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'access-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_access_list_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_access_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'access-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_access_list_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_access_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'access-list', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_access_list_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_access_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'access-list', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_access_list_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_access_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'access-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_router_access_list_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_access_list': {
'random_attribute_not_valid': 'tag',
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_access_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'access-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_auth_path
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_router_auth_path.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_auth_path_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',
'router_auth_path': {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
expected_data = {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('router', 'auth-path', 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_router_auth_path_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',
'router_auth_path': {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
expected_data = {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('router', 'auth-path', 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_router_auth_path_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',
'router_auth_path': {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'auth-path', 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_router_auth_path_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',
'router_auth_path': {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'auth-path', 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_router_auth_path_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',
'router_auth_path': {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
expected_data = {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('router', 'auth-path', 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_router_auth_path_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',
'router_auth_path': {
'random_attribute_not_valid': 'tag',
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_auth_path.fortios_router(input_data, fos_instance)
expected_data = {
'device': 'test_value_3',
'gateway': 'test_value_4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('router', 'auth-path', 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,143 @@
# 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_router_bfd
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_router_bfd.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_bfd_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',
'router_bfd': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd', 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_router_bfd_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',
'router_bfd': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd', 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_router_bfd_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',
'router_bfd': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd', 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_router_bfd_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',
'router_bfd': {
'random_attribute_not_valid': 'tag',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd.fortios_router(input_data, fos_instance)
expected_data = {
}
set_method_mock.assert_called_with('router', 'bfd', 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,143 @@
# 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_router_bfd6
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_router_bfd6.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_bfd6_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',
'router_bfd6': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd6.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd6', 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_router_bfd6_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',
'router_bfd6': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd6.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd6', 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_router_bfd6_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',
'router_bfd6': {
'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd6.fortios_router(input_data, fos_instance)
expected_data = {'neighbor': [{'interface': 'if1', 'ip': '10.20.10.10'}]}
set_method_mock.assert_called_with('router', 'bfd6', 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_router_bfd6_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',
'router_bfd6': {
'random_attribute_not_valid': 'tag',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bfd6.fortios_router(input_data, fos_instance)
expected_data = {
}
set_method_mock.assert_called_with('router', 'bfd6', 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,447 @@
# 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_router_bgp
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_router_bgp.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_bgp_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',
'router_bgp': {'always_compare_med': 'enable',
'as': '4',
'bestpath_as_path_ignore': 'enable',
'bestpath_cmp_confed_aspath': 'enable',
'bestpath_cmp_routerid': 'enable',
'bestpath_med_confed': 'enable',
'bestpath_med_missing_as_worst': 'enable',
'client_to_client_reflection': 'enable',
'cluster_id': 'test_value_11',
'confederation_identifier': '12',
'dampening': 'enable',
'dampening_max_suppress_time': '14',
'dampening_reachability_half_life': '15',
'dampening_reuse': '16',
'dampening_route_map': 'test_value_17',
'dampening_suppress': '18',
'dampening_unreachability_half_life': '19',
'default_local_preference': '20',
'deterministic_med': 'enable',
'distance_external': '22',
'distance_internal': '23',
'distance_local': '24',
'ebgp_multipath': 'enable',
'enforce_first_as': 'enable',
'fast_external_failover': 'enable',
'graceful_end_on_timer': 'enable',
'graceful_restart': 'enable',
'graceful_restart_time': '30',
'graceful_stalepath_time': '31',
'graceful_update_delay': '32',
'holdtime_timer': '33',
'ibgp_multipath': 'enable',
'ignore_optional_capability': 'enable',
'keepalive_timer': '36',
'log_neighbour_changes': 'enable',
'network_import_check': 'enable',
'router_id': 'test_value_39',
'scan_time': '40',
'synchronization': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bgp.fortios_router(input_data, fos_instance)
expected_data = {'always-compare-med': 'enable',
'as': '4',
'bestpath-as-path-ignore': 'enable',
'bestpath-cmp-confed-aspath': 'enable',
'bestpath-cmp-routerid': 'enable',
'bestpath-med-confed': 'enable',
'bestpath-med-missing-as-worst': 'enable',
'client-to-client-reflection': 'enable',
'cluster-id': 'test_value_11',
'confederation-identifier': '12',
'dampening': 'enable',
'dampening-max-suppress-time': '14',
'dampening-reachability-half-life': '15',
'dampening-reuse': '16',
'dampening-route-map': 'test_value_17',
'dampening-suppress': '18',
'dampening-unreachability-half-life': '19',
'default-local-preference': '20',
'deterministic-med': 'enable',
'distance-external': '22',
'distance-internal': '23',
'distance-local': '24',
'ebgp-multipath': 'enable',
'enforce-first-as': 'enable',
'fast-external-failover': 'enable',
'graceful-end-on-timer': 'enable',
'graceful-restart': 'enable',
'graceful-restart-time': '30',
'graceful-stalepath-time': '31',
'graceful-update-delay': '32',
'holdtime-timer': '33',
'ibgp-multipath': 'enable',
'ignore-optional-capability': 'enable',
'keepalive-timer': '36',
'log-neighbour-changes': 'enable',
'network-import-check': 'enable',
'router-id': 'test_value_39',
'scan-time': '40',
'synchronization': 'enable'
}
set_method_mock.assert_called_with('router', 'bgp', 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_router_bgp_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',
'router_bgp': {'always_compare_med': 'enable',
'as': '4',
'bestpath_as_path_ignore': 'enable',
'bestpath_cmp_confed_aspath': 'enable',
'bestpath_cmp_routerid': 'enable',
'bestpath_med_confed': 'enable',
'bestpath_med_missing_as_worst': 'enable',
'client_to_client_reflection': 'enable',
'cluster_id': 'test_value_11',
'confederation_identifier': '12',
'dampening': 'enable',
'dampening_max_suppress_time': '14',
'dampening_reachability_half_life': '15',
'dampening_reuse': '16',
'dampening_route_map': 'test_value_17',
'dampening_suppress': '18',
'dampening_unreachability_half_life': '19',
'default_local_preference': '20',
'deterministic_med': 'enable',
'distance_external': '22',
'distance_internal': '23',
'distance_local': '24',
'ebgp_multipath': 'enable',
'enforce_first_as': 'enable',
'fast_external_failover': 'enable',
'graceful_end_on_timer': 'enable',
'graceful_restart': 'enable',
'graceful_restart_time': '30',
'graceful_stalepath_time': '31',
'graceful_update_delay': '32',
'holdtime_timer': '33',
'ibgp_multipath': 'enable',
'ignore_optional_capability': 'enable',
'keepalive_timer': '36',
'log_neighbour_changes': 'enable',
'network_import_check': 'enable',
'router_id': 'test_value_39',
'scan_time': '40',
'synchronization': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bgp.fortios_router(input_data, fos_instance)
expected_data = {'always-compare-med': 'enable',
'as': '4',
'bestpath-as-path-ignore': 'enable',
'bestpath-cmp-confed-aspath': 'enable',
'bestpath-cmp-routerid': 'enable',
'bestpath-med-confed': 'enable',
'bestpath-med-missing-as-worst': 'enable',
'client-to-client-reflection': 'enable',
'cluster-id': 'test_value_11',
'confederation-identifier': '12',
'dampening': 'enable',
'dampening-max-suppress-time': '14',
'dampening-reachability-half-life': '15',
'dampening-reuse': '16',
'dampening-route-map': 'test_value_17',
'dampening-suppress': '18',
'dampening-unreachability-half-life': '19',
'default-local-preference': '20',
'deterministic-med': 'enable',
'distance-external': '22',
'distance-internal': '23',
'distance-local': '24',
'ebgp-multipath': 'enable',
'enforce-first-as': 'enable',
'fast-external-failover': 'enable',
'graceful-end-on-timer': 'enable',
'graceful-restart': 'enable',
'graceful-restart-time': '30',
'graceful-stalepath-time': '31',
'graceful-update-delay': '32',
'holdtime-timer': '33',
'ibgp-multipath': 'enable',
'ignore-optional-capability': 'enable',
'keepalive-timer': '36',
'log-neighbour-changes': 'enable',
'network-import-check': 'enable',
'router-id': 'test_value_39',
'scan-time': '40',
'synchronization': 'enable'
}
set_method_mock.assert_called_with('router', 'bgp', 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_router_bgp_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',
'router_bgp': {'always_compare_med': 'enable',
'as': '4',
'bestpath_as_path_ignore': 'enable',
'bestpath_cmp_confed_aspath': 'enable',
'bestpath_cmp_routerid': 'enable',
'bestpath_med_confed': 'enable',
'bestpath_med_missing_as_worst': 'enable',
'client_to_client_reflection': 'enable',
'cluster_id': 'test_value_11',
'confederation_identifier': '12',
'dampening': 'enable',
'dampening_max_suppress_time': '14',
'dampening_reachability_half_life': '15',
'dampening_reuse': '16',
'dampening_route_map': 'test_value_17',
'dampening_suppress': '18',
'dampening_unreachability_half_life': '19',
'default_local_preference': '20',
'deterministic_med': 'enable',
'distance_external': '22',
'distance_internal': '23',
'distance_local': '24',
'ebgp_multipath': 'enable',
'enforce_first_as': 'enable',
'fast_external_failover': 'enable',
'graceful_end_on_timer': 'enable',
'graceful_restart': 'enable',
'graceful_restart_time': '30',
'graceful_stalepath_time': '31',
'graceful_update_delay': '32',
'holdtime_timer': '33',
'ibgp_multipath': 'enable',
'ignore_optional_capability': 'enable',
'keepalive_timer': '36',
'log_neighbour_changes': 'enable',
'network_import_check': 'enable',
'router_id': 'test_value_39',
'scan_time': '40',
'synchronization': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bgp.fortios_router(input_data, fos_instance)
expected_data = {'always-compare-med': 'enable',
'as': '4',
'bestpath-as-path-ignore': 'enable',
'bestpath-cmp-confed-aspath': 'enable',
'bestpath-cmp-routerid': 'enable',
'bestpath-med-confed': 'enable',
'bestpath-med-missing-as-worst': 'enable',
'client-to-client-reflection': 'enable',
'cluster-id': 'test_value_11',
'confederation-identifier': '12',
'dampening': 'enable',
'dampening-max-suppress-time': '14',
'dampening-reachability-half-life': '15',
'dampening-reuse': '16',
'dampening-route-map': 'test_value_17',
'dampening-suppress': '18',
'dampening-unreachability-half-life': '19',
'default-local-preference': '20',
'deterministic-med': 'enable',
'distance-external': '22',
'distance-internal': '23',
'distance-local': '24',
'ebgp-multipath': 'enable',
'enforce-first-as': 'enable',
'fast-external-failover': 'enable',
'graceful-end-on-timer': 'enable',
'graceful-restart': 'enable',
'graceful-restart-time': '30',
'graceful-stalepath-time': '31',
'graceful-update-delay': '32',
'holdtime-timer': '33',
'ibgp-multipath': 'enable',
'ignore-optional-capability': 'enable',
'keepalive-timer': '36',
'log-neighbour-changes': 'enable',
'network-import-check': 'enable',
'router-id': 'test_value_39',
'scan-time': '40',
'synchronization': 'enable'
}
set_method_mock.assert_called_with('router', 'bgp', 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_router_bgp_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',
'router_bgp': {
'random_attribute_not_valid': 'tag', 'always_compare_med': 'enable',
'as': '4',
'bestpath_as_path_ignore': 'enable',
'bestpath_cmp_confed_aspath': 'enable',
'bestpath_cmp_routerid': 'enable',
'bestpath_med_confed': 'enable',
'bestpath_med_missing_as_worst': 'enable',
'client_to_client_reflection': 'enable',
'cluster_id': 'test_value_11',
'confederation_identifier': '12',
'dampening': 'enable',
'dampening_max_suppress_time': '14',
'dampening_reachability_half_life': '15',
'dampening_reuse': '16',
'dampening_route_map': 'test_value_17',
'dampening_suppress': '18',
'dampening_unreachability_half_life': '19',
'default_local_preference': '20',
'deterministic_med': 'enable',
'distance_external': '22',
'distance_internal': '23',
'distance_local': '24',
'ebgp_multipath': 'enable',
'enforce_first_as': 'enable',
'fast_external_failover': 'enable',
'graceful_end_on_timer': 'enable',
'graceful_restart': 'enable',
'graceful_restart_time': '30',
'graceful_stalepath_time': '31',
'graceful_update_delay': '32',
'holdtime_timer': '33',
'ibgp_multipath': 'enable',
'ignore_optional_capability': 'enable',
'keepalive_timer': '36',
'log_neighbour_changes': 'enable',
'network_import_check': 'enable',
'router_id': 'test_value_39',
'scan_time': '40',
'synchronization': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_bgp.fortios_router(input_data, fos_instance)
expected_data = {'always-compare-med': 'enable',
'as': '4',
'bestpath-as-path-ignore': 'enable',
'bestpath-cmp-confed-aspath': 'enable',
'bestpath-cmp-routerid': 'enable',
'bestpath-med-confed': 'enable',
'bestpath-med-missing-as-worst': 'enable',
'client-to-client-reflection': 'enable',
'cluster-id': 'test_value_11',
'confederation-identifier': '12',
'dampening': 'enable',
'dampening-max-suppress-time': '14',
'dampening-reachability-half-life': '15',
'dampening-reuse': '16',
'dampening-route-map': 'test_value_17',
'dampening-suppress': '18',
'dampening-unreachability-half-life': '19',
'default-local-preference': '20',
'deterministic-med': 'enable',
'distance-external': '22',
'distance-internal': '23',
'distance-local': '24',
'ebgp-multipath': 'enable',
'enforce-first-as': 'enable',
'fast-external-failover': 'enable',
'graceful-end-on-timer': 'enable',
'graceful-restart': 'enable',
'graceful-restart-time': '30',
'graceful-stalepath-time': '31',
'graceful-update-delay': '32',
'holdtime-timer': '33',
'ibgp-multipath': 'enable',
'ignore-optional-capability': 'enable',
'keepalive-timer': '36',
'log-neighbour-changes': 'enable',
'network-import-check': 'enable',
'router-id': 'test_value_39',
'scan-time': '40',
'synchronization': 'enable'
}
set_method_mock.assert_called_with('router', 'bgp', 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_router_multicast
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_router_multicast.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_multicast_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',
'router_multicast': {'multicast_routing': 'enable',
'route_limit': '4',
'route_threshold': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast.fortios_router(input_data, fos_instance)
expected_data = {'multicast-routing': 'enable',
'route-limit': '4',
'route-threshold': '5'
}
set_method_mock.assert_called_with('router', 'multicast', 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_router_multicast_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',
'router_multicast': {'multicast_routing': 'enable',
'route_limit': '4',
'route_threshold': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast.fortios_router(input_data, fos_instance)
expected_data = {'multicast-routing': 'enable',
'route-limit': '4',
'route-threshold': '5'
}
set_method_mock.assert_called_with('router', 'multicast', 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_router_multicast_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',
'router_multicast': {'multicast_routing': 'enable',
'route_limit': '4',
'route_threshold': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast.fortios_router(input_data, fos_instance)
expected_data = {'multicast-routing': 'enable',
'route-limit': '4',
'route-threshold': '5'
}
set_method_mock.assert_called_with('router', 'multicast', 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_router_multicast_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',
'router_multicast': {
'random_attribute_not_valid': 'tag', 'multicast_routing': 'enable',
'route_limit': '4',
'route_threshold': '5'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast.fortios_router(input_data, fos_instance)
expected_data = {'multicast-routing': 'enable',
'route-limit': '4',
'route-threshold': '5'
}
set_method_mock.assert_called_with('router', 'multicast', 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_router_multicast6
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_router_multicast6.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_multicast6_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',
'router_multicast6': {'multicast_pmtu': 'enable',
'multicast_routing': 'enable',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast6.fortios_router(input_data, fos_instance)
expected_data = {'multicast-pmtu': 'enable',
'multicast-routing': 'enable',
}
set_method_mock.assert_called_with('router', 'multicast6', 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_router_multicast6_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',
'router_multicast6': {'multicast_pmtu': 'enable',
'multicast_routing': 'enable',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast6.fortios_router(input_data, fos_instance)
expected_data = {'multicast-pmtu': 'enable',
'multicast-routing': 'enable',
}
set_method_mock.assert_called_with('router', 'multicast6', 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_router_multicast6_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',
'router_multicast6': {'multicast_pmtu': 'enable',
'multicast_routing': 'enable',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast6.fortios_router(input_data, fos_instance)
expected_data = {'multicast-pmtu': 'enable',
'multicast-routing': 'enable',
}
set_method_mock.assert_called_with('router', 'multicast6', 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_router_multicast6_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',
'router_multicast6': {
'random_attribute_not_valid': 'tag', 'multicast_pmtu': 'enable',
'multicast_routing': 'enable',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast6.fortios_router(input_data, fos_instance)
expected_data = {'multicast-pmtu': 'enable',
'multicast-routing': 'enable',
}
set_method_mock.assert_called_with('router', 'multicast6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,209 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_multicast_flow
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_router_multicast_flow.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_multicast_flow_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',
'router_multicast_flow': {
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4'
}
set_method_mock.assert_called_with('router', 'multicast-flow', 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_router_multicast_flow_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',
'router_multicast_flow': {
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4'
}
set_method_mock.assert_called_with('router', 'multicast-flow', 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_router_multicast_flow_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',
'router_multicast_flow': {
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'multicast-flow', 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_router_multicast_flow_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',
'router_multicast_flow': {
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'multicast-flow', 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_router_multicast_flow_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',
'router_multicast_flow': {
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4'
}
set_method_mock.assert_called_with('router', 'multicast-flow', 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_router_multicast_flow_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',
'router_multicast_flow': {
'random_attribute_not_valid': 'tag',
'comments': 'test_value_3',
'name': 'default_name_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_multicast_flow.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4'
}
set_method_mock.assert_called_with('router', 'multicast-flow', 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,335 @@
# 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_router_ospf
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_router_ospf.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_ospf_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',
'router_ospf': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'database_overflow': 'enable',
'database_overflow_max_lsas': '7',
'database_overflow_time_to_recover': '8',
'default_information_metric': '9',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_12',
'default_metric': '13',
'distance': '14',
'distance_external': '15',
'distance_inter_area': '16',
'distance_intra_area': '17',
'distribute_list_in': 'test_value_18',
'distribute_route_map_in': 'test_value_19',
'log_neighbour_changes': 'enable',
'restart_mode': 'none',
'restart_period': '22',
'rfc1583_compatible': 'enable',
'router_id': 'test_value_24',
'spf_timers': 'test_value_25',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'database-overflow': 'enable',
'database-overflow-max-lsas': '7',
'database-overflow-time-to-recover': '8',
'default-information-metric': '9',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_12',
'default-metric': '13',
'distance': '14',
'distance-external': '15',
'distance-inter-area': '16',
'distance-intra-area': '17',
'distribute-list-in': 'test_value_18',
'distribute-route-map-in': 'test_value_19',
'log-neighbour-changes': 'enable',
'restart-mode': 'none',
'restart-period': '22',
'rfc1583-compatible': 'enable',
'router-id': 'test_value_24',
'spf-timers': 'test_value_25',
}
set_method_mock.assert_called_with('router', 'ospf', 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_router_ospf_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',
'router_ospf': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'database_overflow': 'enable',
'database_overflow_max_lsas': '7',
'database_overflow_time_to_recover': '8',
'default_information_metric': '9',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_12',
'default_metric': '13',
'distance': '14',
'distance_external': '15',
'distance_inter_area': '16',
'distance_intra_area': '17',
'distribute_list_in': 'test_value_18',
'distribute_route_map_in': 'test_value_19',
'log_neighbour_changes': 'enable',
'restart_mode': 'none',
'restart_period': '22',
'rfc1583_compatible': 'enable',
'router_id': 'test_value_24',
'spf_timers': 'test_value_25',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'database-overflow': 'enable',
'database-overflow-max-lsas': '7',
'database-overflow-time-to-recover': '8',
'default-information-metric': '9',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_12',
'default-metric': '13',
'distance': '14',
'distance-external': '15',
'distance-inter-area': '16',
'distance-intra-area': '17',
'distribute-list-in': 'test_value_18',
'distribute-route-map-in': 'test_value_19',
'log-neighbour-changes': 'enable',
'restart-mode': 'none',
'restart-period': '22',
'rfc1583-compatible': 'enable',
'router-id': 'test_value_24',
'spf-timers': 'test_value_25',
}
set_method_mock.assert_called_with('router', 'ospf', 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_router_ospf_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',
'router_ospf': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'database_overflow': 'enable',
'database_overflow_max_lsas': '7',
'database_overflow_time_to_recover': '8',
'default_information_metric': '9',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_12',
'default_metric': '13',
'distance': '14',
'distance_external': '15',
'distance_inter_area': '16',
'distance_intra_area': '17',
'distribute_list_in': 'test_value_18',
'distribute_route_map_in': 'test_value_19',
'log_neighbour_changes': 'enable',
'restart_mode': 'none',
'restart_period': '22',
'rfc1583_compatible': 'enable',
'router_id': 'test_value_24',
'spf_timers': 'test_value_25',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'database-overflow': 'enable',
'database-overflow-max-lsas': '7',
'database-overflow-time-to-recover': '8',
'default-information-metric': '9',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_12',
'default-metric': '13',
'distance': '14',
'distance-external': '15',
'distance-inter-area': '16',
'distance-intra-area': '17',
'distribute-list-in': 'test_value_18',
'distribute-route-map-in': 'test_value_19',
'log-neighbour-changes': 'enable',
'restart-mode': 'none',
'restart-period': '22',
'rfc1583-compatible': 'enable',
'router-id': 'test_value_24',
'spf-timers': 'test_value_25',
}
set_method_mock.assert_called_with('router', 'ospf', 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_router_ospf_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',
'router_ospf': {
'random_attribute_not_valid': 'tag',
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'database_overflow': 'enable',
'database_overflow_max_lsas': '7',
'database_overflow_time_to_recover': '8',
'default_information_metric': '9',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_12',
'default_metric': '13',
'distance': '14',
'distance_external': '15',
'distance_inter_area': '16',
'distance_intra_area': '17',
'distribute_list_in': 'test_value_18',
'distribute_route_map_in': 'test_value_19',
'log_neighbour_changes': 'enable',
'restart_mode': 'none',
'restart_period': '22',
'rfc1583_compatible': 'enable',
'router_id': 'test_value_24',
'spf_timers': 'test_value_25',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'database-overflow': 'enable',
'database-overflow-max-lsas': '7',
'database-overflow-time-to-recover': '8',
'default-information-metric': '9',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_12',
'default-metric': '13',
'distance': '14',
'distance-external': '15',
'distance-inter-area': '16',
'distance-intra-area': '17',
'distribute-list-in': 'test_value_18',
'distribute-route-map-in': 'test_value_19',
'log-neighbour-changes': 'enable',
'restart-mode': 'none',
'restart-period': '22',
'rfc1583-compatible': 'enable',
'router-id': 'test_value_24',
'spf-timers': 'test_value_25',
}
set_method_mock.assert_called_with('router', 'ospf', 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_router_ospf6
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_router_ospf6.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_ospf6_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',
'router_ospf6': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'default_information_metric': '6',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_9',
'default_metric': '10',
'log_neighbour_changes': 'enable',
'router_id': 'test_value_12',
'spf_timers': 'test_value_13',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf6.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'default-information-metric': '6',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_9',
'default-metric': '10',
'log-neighbour-changes': 'enable',
'router-id': 'test_value_12',
'spf-timers': 'test_value_13',
}
set_method_mock.assert_called_with('router', 'ospf6', 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_router_ospf6_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',
'router_ospf6': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'default_information_metric': '6',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_9',
'default_metric': '10',
'log_neighbour_changes': 'enable',
'router_id': 'test_value_12',
'spf_timers': 'test_value_13',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf6.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'default-information-metric': '6',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_9',
'default-metric': '10',
'log-neighbour-changes': 'enable',
'router-id': 'test_value_12',
'spf-timers': 'test_value_13',
}
set_method_mock.assert_called_with('router', 'ospf6', 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_router_ospf6_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',
'router_ospf6': {
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'default_information_metric': '6',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_9',
'default_metric': '10',
'log_neighbour_changes': 'enable',
'router_id': 'test_value_12',
'spf_timers': 'test_value_13',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf6.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'default-information-metric': '6',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_9',
'default-metric': '10',
'log-neighbour-changes': 'enable',
'router-id': 'test_value_12',
'spf-timers': 'test_value_13',
}
set_method_mock.assert_called_with('router', 'ospf6', 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_router_ospf6_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',
'router_ospf6': {
'random_attribute_not_valid': 'tag',
'abr_type': 'cisco',
'auto_cost_ref_bandwidth': '4',
'bfd': 'enable',
'default_information_metric': '6',
'default_information_metric_type': '1',
'default_information_originate': 'enable',
'default_information_route_map': 'test_value_9',
'default_metric': '10',
'log_neighbour_changes': 'enable',
'router_id': 'test_value_12',
'spf_timers': 'test_value_13',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_ospf6.fortios_router(input_data, fos_instance)
expected_data = {
'abr-type': 'cisco',
'auto-cost-ref-bandwidth': '4',
'bfd': 'enable',
'default-information-metric': '6',
'default-information-metric-type': '1',
'default-information-originate': 'enable',
'default-information-route-map': 'test_value_9',
'default-metric': '10',
'log-neighbour-changes': 'enable',
'router-id': 'test_value_12',
'spf-timers': 'test_value_13',
}
set_method_mock.assert_called_with('router', 'ospf6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,339 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_policy
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_router_policy.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_policy_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy': {
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
expected_data = {
'action': 'deny',
'comments': 'test_value_4',
'dst-negate': 'enable',
'end-port': '6',
'end-source-port': '7',
'gateway': 'test_value_8',
'output-device': 'test_value_9',
'protocol': '10',
'seq-num': '11',
'src-negate': 'enable',
'start-port': '13',
'start-source-port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos-mask': 'test_value_17'
}
set_method_mock.assert_called_with('router', 'policy', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_policy_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy': {
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
expected_data = {
'action': 'deny',
'comments': 'test_value_4',
'dst-negate': 'enable',
'end-port': '6',
'end-source-port': '7',
'gateway': 'test_value_8',
'output-device': 'test_value_9',
'protocol': '10',
'seq-num': '11',
'src-negate': 'enable',
'start-port': '13',
'start-source-port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos-mask': 'test_value_17'
}
set_method_mock.assert_called_with('router', 'policy', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_policy_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_policy': {
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'policy', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_policy_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_policy': {
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'policy', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_policy_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy': {
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
expected_data = {
'action': 'deny',
'comments': 'test_value_4',
'dst-negate': 'enable',
'end-port': '6',
'end-source-port': '7',
'gateway': 'test_value_8',
'output-device': 'test_value_9',
'protocol': '10',
'seq-num': '11',
'src-negate': 'enable',
'start-port': '13',
'start-source-port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos-mask': 'test_value_17'
}
set_method_mock.assert_called_with('router', 'policy', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_router_policy_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy': {
'random_attribute_not_valid': 'tag',
'action': 'deny',
'comments': 'test_value_4',
'dst_negate': 'enable',
'end_port': '6',
'end_source_port': '7',
'gateway': 'test_value_8',
'output_device': 'test_value_9',
'protocol': '10',
'seq_num': '11',
'src_negate': 'enable',
'start_port': '13',
'start_source_port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos_mask': 'test_value_17'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy.fortios_router(input_data, fos_instance)
expected_data = {
'action': 'deny',
'comments': 'test_value_4',
'dst-negate': 'enable',
'end-port': '6',
'end-source-port': '7',
'gateway': 'test_value_8',
'output-device': 'test_value_9',
'protocol': '10',
'seq-num': '11',
'src-negate': 'enable',
'start-port': '13',
'start-source-port': '14',
'status': 'enable',
'tos': 'test_value_16',
'tos-mask': 'test_value_17'
}
set_method_mock.assert_called_with('router', 'policy', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,319 @@
# 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_router_policy6
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_router_policy6.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_policy6_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy6': {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end-port': '5',
'gateway': 'test_value_6',
'input-device': 'test_value_7',
'output-device': 'test_value_8',
'protocol': '9',
'seq-num': '10',
'src': 'test_value_11',
'start-port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos-mask': 'test_value_15'
}
set_method_mock.assert_called_with('router', 'policy6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_policy6_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy6': {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end-port': '5',
'gateway': 'test_value_6',
'input-device': 'test_value_7',
'output-device': 'test_value_8',
'protocol': '9',
'seq-num': '10',
'src': 'test_value_11',
'start-port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos-mask': 'test_value_15'
}
set_method_mock.assert_called_with('router', 'policy6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_policy6_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_policy6': {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'policy6', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_policy6_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_policy6': {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'policy6', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_policy6_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy6': {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end-port': '5',
'gateway': 'test_value_6',
'input-device': 'test_value_7',
'output-device': 'test_value_8',
'protocol': '9',
'seq-num': '10',
'src': 'test_value_11',
'start-port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos-mask': 'test_value_15'
}
set_method_mock.assert_called_with('router', 'policy6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_router_policy6_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_policy6': {
'random_attribute_not_valid': 'tag',
'comments': 'test_value_3',
'dst': 'test_value_4',
'end_port': '5',
'gateway': 'test_value_6',
'input_device': 'test_value_7',
'output_device': 'test_value_8',
'protocol': '9',
'seq_num': '10',
'src': 'test_value_11',
'start_port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos_mask': 'test_value_15'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_policy6.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'dst': 'test_value_4',
'end-port': '5',
'gateway': 'test_value_6',
'input-device': 'test_value_7',
'output-device': 'test_value_8',
'protocol': '9',
'seq-num': '10',
'src': 'test_value_11',
'start-port': '12',
'status': 'enable',
'tos': 'test_value_14',
'tos-mask': 'test_value_15'
}
set_method_mock.assert_called_with('router', 'policy6', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_prefix_list
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_router_prefix_list.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_prefix_list_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_prefix_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'prefix-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_prefix_list_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_prefix_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'prefix-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_prefix_list_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_prefix_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'prefix-list', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_prefix_list_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'router_prefix_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'prefix-list', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_prefix_list_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_prefix_list': {
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'prefix-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_router_prefix_list_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_prefix_list': {
'random_attribute_not_valid': 'tag',
'comments': 'test_value_3',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_router_prefix_list.fortios_router(input_data, fos_instance)
expected_data = {
'comments': 'test_value_3',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('router', 'prefix-list', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,207 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_router_rip
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_router_rip.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_rip_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',
'router_rip': {
'default_information_originate': 'enable',
'default_metric': '4',
'garbage_timer': '5',
'max_out_metric': '6',
'recv_buffer_size': '7',
'timeout_timer': '8',
'update_timer': '9',
'version': '1'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_rip.fortios_router(input_data, fos_instance)
expected_data = {
'default-information-originate': 'enable',
'default-metric': '4',
'garbage-timer': '5',
'max-out-metric': '6',
'recv-buffer-size': '7',
'timeout-timer': '8',
'update-timer': '9',
'version': '1'
}
set_method_mock.assert_called_with('router', 'rip', 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_router_rip_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',
'router_rip': {
'default_information_originate': 'enable',
'default_metric': '4',
'garbage_timer': '5',
'max_out_metric': '6',
'recv_buffer_size': '7',
'timeout_timer': '8',
'update_timer': '9',
'version': '1'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_rip.fortios_router(input_data, fos_instance)
expected_data = {
'default-information-originate': 'enable',
'default-metric': '4',
'garbage-timer': '5',
'max-out-metric': '6',
'recv-buffer-size': '7',
'timeout-timer': '8',
'update-timer': '9',
'version': '1'
}
set_method_mock.assert_called_with('router', 'rip', 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_router_rip_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',
'router_rip': {
'default_information_originate': 'enable',
'default_metric': '4',
'garbage_timer': '5',
'max_out_metric': '6',
'recv_buffer_size': '7',
'timeout_timer': '8',
'update_timer': '9',
'version': '1'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_rip.fortios_router(input_data, fos_instance)
expected_data = {
'default-information-originate': 'enable',
'default-metric': '4',
'garbage-timer': '5',
'max-out-metric': '6',
'recv-buffer-size': '7',
'timeout-timer': '8',
'update-timer': '9',
'version': '1'
}
set_method_mock.assert_called_with('router', 'rip', 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_router_rip_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',
'router_rip': {
'random_attribute_not_valid': 'tag',
'default_information_originate': 'enable',
'default_metric': '4',
'garbage_timer': '5',
'max_out_metric': '6',
'recv_buffer_size': '7',
'timeout_timer': '8',
'update_timer': '9',
'version': '1'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_rip.fortios_router(input_data, fos_instance)
expected_data = {
'default-information-originate': 'enable',
'default-metric': '4',
'garbage-timer': '5',
'max-out-metric': '6',
'recv-buffer-size': '7',
'timeout-timer': '8',
'update-timer': '9',
'version': '1'
}
set_method_mock.assert_called_with('router', 'rip', 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_router_setting
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_router_setting.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_setting_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_setting': {
'hostname': 'myhostname3',
'show_filter': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_setting.fortios_router(input_data, fos_instance)
expected_data = {
'hostname': 'myhostname3',
'show-filter': 'test_value_4'
}
set_method_mock.assert_called_with('router', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_router_setting_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_setting': {
'hostname': 'myhostname3',
'show_filter': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_setting.fortios_router(input_data, fos_instance)
expected_data = {
'hostname': 'myhostname3',
'show-filter': 'test_value_4'
}
set_method_mock.assert_called_with('router', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_router_setting_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_setting': {
'hostname': 'myhostname3',
'show_filter': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_setting.fortios_router(input_data, fos_instance)
expected_data = {
'hostname': 'myhostname3',
'show-filter': 'test_value_4'
}
set_method_mock.assert_called_with('router', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_router_setting_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'router_setting': {
'random_attribute_not_valid': 'tag',
'hostname': 'myhostname3',
'show_filter': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_setting.fortios_router(input_data, fos_instance)
expected_data = {
'hostname': 'myhostname3',
'show-filter': 'test_value_4'
}
set_method_mock.assert_called_with('router', 'setting', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,379 @@
# 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_router_static
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_router_static.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_router_static_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',
'router_static': {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
expected_data = {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic-gateway': 'enable',
'gateway': 'test_value_11',
'internet-service': '12',
'internet-service-custom': 'test_value_13',
'link-monitor-exempt': 'enable',
'priority': '15',
'seq-num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual-wan-link': 'enable',
'vrf': '20',
'weight': '21'
}
set_method_mock.assert_called_with('router', 'static', 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_router_static_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',
'router_static': {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
expected_data = {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic-gateway': 'enable',
'gateway': 'test_value_11',
'internet-service': '12',
'internet-service-custom': 'test_value_13',
'link-monitor-exempt': 'enable',
'priority': '15',
'seq-num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual-wan-link': 'enable',
'vrf': '20',
'weight': '21'
}
set_method_mock.assert_called_with('router', 'static', 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_router_static_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',
'router_static': {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'static', 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_router_static_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',
'router_static': {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
delete_method_mock.assert_called_with('router', 'static', 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_router_static_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',
'router_static': {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
expected_data = {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic-gateway': 'enable',
'gateway': 'test_value_11',
'internet-service': '12',
'internet-service-custom': 'test_value_13',
'link-monitor-exempt': 'enable',
'priority': '15',
'seq-num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual-wan-link': 'enable',
'vrf': '20',
'weight': '21'
}
set_method_mock.assert_called_with('router', 'static', 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_router_static_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',
'router_static': {
'random_attribute_not_valid': 'tag',
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic_gateway': 'enable',
'gateway': 'test_value_11',
'internet_service': '12',
'internet_service_custom': 'test_value_13',
'link_monitor_exempt': 'enable',
'priority': '15',
'seq_num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual_wan_link': 'enable',
'vrf': '20',
'weight': '21'
},
'vdom': 'root'}
is_error, changed, response = fortios_router_static.fortios_router(input_data, fos_instance)
expected_data = {
'bfd': 'enable',
'blackhole': 'enable',
'comment': 'Optional comments.',
'device': 'test_value_6',
'distance': '7',
'dst': 'test_value_8',
'dstaddr': 'test_value_9',
'dynamic-gateway': 'enable',
'gateway': 'test_value_11',
'internet-service': '12',
'internet-service-custom': 'test_value_13',
'link-monitor-exempt': 'enable',
'priority': '15',
'seq-num': '16',
'src': 'test_value_17',
'status': 'enable',
'virtual-wan-link': 'enable',
'vrf': '20',
'weight': '21'
}
set_method_mock.assert_called_with('router', 'static', 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