FortiOS modules for 2.9 - 10 (#61367)

* FortiOS modules for 2.9 - 10

* Fortios User Device was wrongly set to 2.8 instead of 2.9

* Retriggering shippable due to random failure
pull/61387/head
Miguel Angel Muñoz González 5 years ago committed by Nilashish Chakraborty
parent d29aaffb16
commit 5e4e32b45e

@ -26,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_user_adgrp
short_description: Configure FSSO groups 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 user feature and adgrp category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -41,47 +41,62 @@ 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
user_adgrp:
description:
- Configure FSSO groups.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
name:
description:
- Name.
required: true
server-name:
type: str
server_name:
description:
- FSSO agent name. Source user.fsso.name.
type: str
'''
EXAMPLES = '''
@ -91,6 +106,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure FSSO groups.
fortios_user_adgrp:
@ -99,10 +115,10 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
user_adgrp:
state: "present"
name: "default_name_3"
server-name: "<your_own_value> (source user.fsso.name)"
server_name: "<your_own_value> (source user.fsso.name)"
'''
RETURN = '''
@ -165,12 +181,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -178,11 +198,11 @@ def login(data, fos):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_user_adgrp_data(json):
option_list = ['name', 'server-name']
option_list = ['name', 'server_name']
dictionary = {}
for attribute in option_list:
@ -192,48 +212,68 @@ def filter_user_adgrp_data(json):
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def user_adgrp(data, fos):
vdom = data['vdom']
state = data['state']
user_adgrp_data = data['user_adgrp']
filtered_data = filter_user_adgrp_data(user_adgrp_data)
filtered_data = underscore_to_hyphen(filter_user_adgrp_data(user_adgrp_data))
if user_adgrp_data['state'] == "present":
if state == "present":
return fos.set('user',
'adgrp',
data=filtered_data,
vdom=vdom)
elif user_adgrp_data['state'] == "absent":
elif state == "absent":
return fos.delete('user',
'adgrp',
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_user(data, fos):
login(data, fos)
if data['user_adgrp']:
resp = user_adgrp(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"]},
"user_adgrp": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"name": {"required": True, "type": "str"},
"server-name": {"required": False, "type": "str"}
"server_name": {"required": False, "type": "str"}
}
}
@ -241,14 +281,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_user(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_user(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_user(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -13,7 +13,7 @@ from __future__ import (absolute_import, division, print_function)
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>
__metaclass__ = type
@ -24,12 +24,12 @@ ANSIBLE_METADATA = {'status': ['preview'],
DOCUMENTATION = '''
---
module: fortios_user_device
short_description: Configure devices in Fortinet's FortiOS and FortiGate
short_description: Configure devices in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS device by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify user feature and device 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.9"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,12 +44,12 @@ options:
description:
- FortiOS or FortiGate IP address.
type: str
required: true
required: false
username:
description:
- FortiOS or FortiGate username.
type: str
required: true
required: false
password:
description:
- FortiOS or FortiGate password.
@ -64,14 +64,19 @@ options:
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
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
@ -85,12 +90,15 @@ options:
description:
- Device alias.
required: true
type: str
avatar:
description:
- Image file for avatar (maximum 4K base64 encoded).
type: str
category:
description:
- Device category.
type: str
choices:
- none
- amazon-device
@ -102,34 +110,43 @@ options:
comment:
description:
- Comment.
type: str
mac:
description:
- Device MAC address(es).
- Device MAC address.
type: str
master_device:
description:
- Master device (optional). Source user.device.alias.
type: str
tagging:
description:
- Config object tagging.
type: list
suboptions:
category:
description:
- Tag category. Source system.object-tagging.category.
type: str
name:
description:
- Tagging entry name.
required: true
type: str
tags:
description:
- Tags.
type: list
suboptions:
name:
description:
- Tag name. Source system.object-tagging.tags.name.
required: true
type: str
type:
description:
- Device type.
type: str
choices:
- unknown
- android-phone
@ -155,6 +172,7 @@ options:
user:
description:
- User name.
type: str
'''
EXAMPLES = '''
@ -164,6 +182,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure devices.
fortios_user_device:
@ -260,6 +279,7 @@ 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']:
@ -267,7 +287,7 @@ def login(data, fos):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_user_device_data(json):
@ -334,13 +354,14 @@ def main():
fields = {
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"user_device": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"alias": {"required": True, "type": "str"},
"avatar": {"required": False, "type": "str"},
@ -369,6 +390,7 @@ def main():
"printer", "router-nat-device", "windows-pc",
"windows-phone", "windows-tablet", "other-network-device"]},
"user": {"required": False, "type": "str"}
}
}
}
@ -376,6 +398,7 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
# 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

@ -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_user_radius
short_description: Configure RADIUS server entries 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 user feature and radius 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,84 +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
user_radius:
description:
- Configure RADIUS server entries.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
accounting-server:
accounting_server:
description:
- Additional accounting servers.
type: list
suboptions:
id:
description:
- ID (0 - 4294967295).
required: true
type: int
port:
description:
- RADIUS accounting port number.
type: int
secret:
description:
- Secret key.
type: str
server:
description:
- Server CN domain name or IP.
source-ip:
- name_str or ip_str Server CN domain name or IP.
type: str
source_ip:
description:
- Source IP address for communications to the RADIUS server.
type: str
status:
description:
- Status.
type: str
choices:
- enable
- disable
acct-all-servers:
acct_all_servers:
description:
- Enable/disable sending of accounting messages to all configured servers (default = disable).
- Enable/disable sending of accounting messages to all configured servers.
type: str
choices:
- enable
- disable
acct-interim-interval:
acct_interim_interval:
description:
- Time in seconds between each accounting interim update message.
all-usergroup:
type: int
all_usergroup:
description:
- Enable/disable automatically including this RADIUS server in all user groups.
type: str
choices:
- disable
- enable
auth-type:
auth_type:
description:
- Authentication methods/protocols permitted for this RADIUS server.
type: str
choices:
- auto
- ms_chap_v2
@ -131,14 +152,17 @@ options:
class:
description:
- Class attribute name(s).
type: list
suboptions:
name:
description:
- Class name.
required: true
h3c-compatibility:
type: str
h3c_compatibility:
description:
- Enable/disable compatibility with the H3C, a mechanism that performs security checking for authentication.
type: str
choices:
- enable
- disable
@ -146,43 +170,52 @@ options:
description:
- RADIUS server entry name.
required: true
nas-ip:
type: str
nas_ip:
description:
- IP address used to communicate with the RADIUS server and used as NAS-IP-Address and Called-Station-ID attributes.
password-encoding:
type: str
password_encoding:
description:
- Password encoding.
type: str
choices:
- auto
- ISO-8859-1
password-renewal:
password_renewal:
description:
- Enable/disable password renewal.
type: str
choices:
- enable
- disable
radius-coa:
radius_coa:
description:
- Enable to allow a mechanism to change the attributes of an authentication, authorization, and accounting session after it is
authenticated.
type: str
choices:
- enable
- disable
radius-port:
radius_port:
description:
- RADIUS service port number.
type: int
rsso:
description:
- Enable/disable RADIUS based single sign on feature.
type: str
choices:
- enable
- disable
rsso-context-timeout:
rsso_context_timeout:
description:
- Time in seconds before the logged out user is removed from the "user context list" of logged on users.
rsso-endpoint-attribute:
type: int
rsso_endpoint_attribute:
description:
- RADIUS attributes used to extract the user end point identifer from the RADIUS Start record.
type: str
choices:
- User-Name
- NAS-IP-Address
@ -206,9 +239,10 @@ options:
- Framed-AppleTalk-Zone
- Acct-Session-Id
- Acct-Multi-Session-Id
rsso-endpoint-block-attribute:
rsso_endpoint_block_attribute:
description:
- RADIUS attributes used to block a user.
type: str
choices:
- User-Name
- NAS-IP-Address
@ -232,21 +266,24 @@ options:
- Framed-AppleTalk-Zone
- Acct-Session-Id
- Acct-Multi-Session-Id
rsso-ep-one-ip-only:
rsso_ep_one_ip_only:
description:
- Enable/disable the replacement of old IP addresses with new ones for the same endpoint on RADIUS accounting Start messages.
type: str
choices:
- enable
- disable
rsso-flush-ip-session:
rsso_flush_ip_session:
description:
- Enable/disable flushing user IP sessions on RADIUS accounting Stop messages.
type: str
choices:
- enable
- disable
rsso-log-flags:
rsso_log_flags:
description:
- Events to log.
type: str
choices:
- protocol-error
- profile-missing
@ -255,45 +292,56 @@ options:
- endpoint-block
- radiusd-other
- none
rsso-log-period:
rsso_log_period:
description:
- Time interval in seconds that group event log messages will be generated for dynamic profile events.
rsso-radius-response:
type: int
rsso_radius_response:
description:
- Enable/disable sending RADIUS response packets after receiving Start and Stop records.
type: str
choices:
- enable
- disable
rsso-radius-server-port:
rsso_radius_server_port:
description:
- UDP port to listen on for RADIUS Start and Stop records.
rsso-secret:
type: int
rsso_secret:
description:
- RADIUS secret used by the RADIUS accounting server.
rsso-validate-request-secret:
type: str
rsso_validate_request_secret:
description:
- Enable/disable validating the RADIUS request shared secret in the Start or End record.
type: str
choices:
- enable
- disable
secondary-secret:
secondary_secret:
description:
- Secret key to access the secondary server.
secondary-server:
type: str
secondary_server:
description:
- Secondary RADIUS CN domain name or IP.
- name_str or ip_str secondary RADIUS CN domain name or IP.
type: str
secret:
description:
- Pre-shared secret key used to access the primary RADIUS server.
type: str
server:
description:
- Primary RADIUS server CN domain name or IP address.
source-ip:
type: str
source_ip:
description:
- Source IP address for communications to the RADIUS server.
sso-attribute:
type: str
sso_attribute:
description:
- RADIUS attribute that contains the profile group name to be extracted from the RADIUS Start record.
type: str
choices:
- User-Name
- NAS-IP-Address
@ -317,33 +365,40 @@ options:
- Framed-AppleTalk-Zone
- Acct-Session-Id
- Acct-Multi-Session-Id
sso-attribute-key:
sso_attribute_key:
description:
- Key prefix for SSO group value in the SSO attribute.
sso-attribute-value-override:
type: str
sso_attribute_value_override:
description:
- Enable/disable override old attribute value with new value for the same endpoint.
type: str
choices:
- enable
- disable
tertiary-secret:
tertiary_secret:
description:
- Secret key to access the tertiary server.
tertiary-server:
type: str
tertiary_server:
description:
- Tertiary RADIUS CN domain name or IP.
- name_str or ip_str tertiary RADIUS CN domain name or IP.
type: str
timeout:
description:
- Time in seconds between re-sending authentication requests.
use-management-vdom:
type: int
use_management_vdom:
description:
- Enable/disable using management VDOM to send requests.
type: str
choices:
- enable
- disable
username-case-sensitive:
username_case_sensitive:
description:
- Enable/disable case sensitive user names.
type: str
choices:
- enable
- disable
@ -356,6 +411,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure RADIUS server entries.
fortios_user_radius:
@ -364,55 +420,55 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
user_radius:
state: "present"
accounting-server:
accounting_server:
-
id: "4"
port: "5"
secret: "<your_own_value>"
server: "192.168.100.40"
source-ip: "84.230.14.43"
source_ip: "84.230.14.43"
status: "enable"
acct-all-servers: "enable"
acct-interim-interval: "11"
all-usergroup: "disable"
auth-type: "auto"
acct_all_servers: "enable"
acct_interim_interval: "11"
all_usergroup: "disable"
auth_type: "auto"
class:
-
name: "default_name_15"
h3c-compatibility: "enable"
h3c_compatibility: "enable"
name: "default_name_17"
nas-ip: "<your_own_value>"
password-encoding: "auto"
password-renewal: "enable"
radius-coa: "enable"
radius-port: "22"
nas_ip: "<your_own_value>"
password_encoding: "auto"
password_renewal: "enable"
radius_coa: "enable"
radius_port: "22"
rsso: "enable"
rsso-context-timeout: "24"
rsso-endpoint-attribute: "User-Name"
rsso-endpoint-block-attribute: "User-Name"
rsso-ep-one-ip-only: "enable"
rsso-flush-ip-session: "enable"
rsso-log-flags: "protocol-error"
rsso-log-period: "30"
rsso-radius-response: "enable"
rsso-radius-server-port: "32"
rsso-secret: "<your_own_value>"
rsso-validate-request-secret: "enable"
secondary-secret: "<your_own_value>"
secondary-server: "<your_own_value>"
rsso_context_timeout: "24"
rsso_endpoint_attribute: "User-Name"
rsso_endpoint_block_attribute: "User-Name"
rsso_ep_one_ip_only: "enable"
rsso_flush_ip_session: "enable"
rsso_log_flags: "protocol-error"
rsso_log_period: "30"
rsso_radius_response: "enable"
rsso_radius_server_port: "32"
rsso_secret: "<your_own_value>"
rsso_validate_request_secret: "enable"
secondary_secret: "<your_own_value>"
secondary_server: "<your_own_value>"
secret: "<your_own_value>"
server: "192.168.100.40"
source-ip: "84.230.14.43"
sso-attribute: "User-Name"
sso-attribute-key: "<your_own_value>"
sso-attribute-value-override: "enable"
tertiary-secret: "<your_own_value>"
tertiary-server: "<your_own_value>"
source_ip: "84.230.14.43"
sso_attribute: "User-Name"
sso_attribute_key: "<your_own_value>"
sso_attribute_value_override: "enable"
tertiary_secret: "<your_own_value>"
tertiary_server: "<your_own_value>"
timeout: "45"
use-management-vdom: "enable"
username-case-sensitive: "enable"
use_management_vdom: "enable"
username_case_sensitive: "enable"
'''
RETURN = '''
@ -475,14 +531,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']:
@ -490,23 +548,23 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_user_radius_data(json):
option_list = ['accounting-server', 'acct-all-servers', 'acct-interim-interval',
'all-usergroup', 'auth-type', 'class',
'h3c-compatibility', 'name', 'nas-ip',
'password-encoding', 'password-renewal', 'radius-coa',
'radius-port', 'rsso', 'rsso-context-timeout',
'rsso-endpoint-attribute', 'rsso-endpoint-block-attribute', 'rsso-ep-one-ip-only',
'rsso-flush-ip-session', 'rsso-log-flags', 'rsso-log-period',
'rsso-radius-response', 'rsso-radius-server-port', 'rsso-secret',
'rsso-validate-request-secret', 'secondary-secret', 'secondary-server',
'secret', 'server', 'source-ip',
'sso-attribute', 'sso-attribute-key', 'sso-attribute-value-override',
'tertiary-secret', 'tertiary-server', 'timeout',
'use-management-vdom', 'username-case-sensitive']
option_list = ['accounting_server', 'acct_all_servers', 'acct_interim_interval',
'all_usergroup', 'auth_type', 'class',
'h3c_compatibility', 'name', 'nas_ip',
'password_encoding', 'password_renewal', 'radius_coa',
'radius_port', 'rsso', 'rsso_context_timeout',
'rsso_endpoint_attribute', 'rsso_endpoint_block_attribute', 'rsso_ep_one_ip_only',
'rsso_flush_ip_session', 'rsso_log_flags', 'rsso_log_period',
'rsso_radius_response', 'rsso_radius_server_port', 'rsso_secret',
'rsso_validate_request_secret', 'secondary_secret', 'secondary_server',
'secret', 'server', 'source_ip',
'sso_attribute', 'sso_attribute_key', 'sso_attribute_value_override',
'tertiary_secret', 'tertiary_server', 'timeout',
'use_management_vdom', 'username_case_sensitive']
dictionary = {}
for attribute in option_list:
@ -516,98 +574,103 @@ def filter_user_radius_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 user_radius(data, fos):
vdom = data['vdom']
state = data['state']
user_radius_data = data['user_radius']
flattened_data = flatten_multilists_attributes(user_radius_data)
filtered_data = filter_user_radius_data(flattened_data)
if user_radius_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_user_radius_data(user_radius_data))
if state == "present":
return fos.set('user',
'radius',
data=filtered_data,
vdom=vdom)
elif user_radius_data['state'] == "absent":
elif state == "absent":
return fos.delete('user',
'radius',
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_user(data, fos):
login(data)
if data['user_radius']:
resp = user_radius(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"]},
"user_radius": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"accounting-server": {"required": False, "type": "list",
"accounting_server": {"required": False, "type": "list",
"options": {
"id": {"required": True, "type": "int"},
"port": {"required": False, "type": "int"},
"secret": {"required": False, "type": "str"},
"server": {"required": False, "type": "str"},
"source-ip": {"required": False, "type": "str"},
"source_ip": {"required": False, "type": "str"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}},
"acct-all-servers": {"required": False, "type": "str",
"acct_all_servers": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"acct-interim-interval": {"required": False, "type": "int"},
"all-usergroup": {"required": False, "type": "str",
"acct_interim_interval": {"required": False, "type": "int"},
"all_usergroup": {"required": False, "type": "str",
"choices": ["disable", "enable"]},
"auth-type": {"required": False, "type": "str",
"auth_type": {"required": False, "type": "str",
"choices": ["auto", "ms_chap_v2", "ms_chap",
"chap", "pap"]},
"class": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"h3c-compatibility": {"required": False, "type": "str",
"h3c_compatibility": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"name": {"required": True, "type": "str"},
"nas-ip": {"required": False, "type": "str"},
"password-encoding": {"required": False, "type": "str",
"nas_ip": {"required": False, "type": "str"},
"password_encoding": {"required": False, "type": "str",
"choices": ["auto", "ISO-8859-1"]},
"password-renewal": {"required": False, "type": "str",
"password_renewal": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"radius-coa": {"required": False, "type": "str",
"radius_coa": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"radius-port": {"required": False, "type": "int"},
"radius_port": {"required": False, "type": "int"},
"rsso": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"rsso-context-timeout": {"required": False, "type": "int"},
"rsso-endpoint-attribute": {"required": False, "type": "str",
"rsso_context_timeout": {"required": False, "type": "int"},
"rsso_endpoint_attribute": {"required": False, "type": "str",
"choices": ["User-Name", "NAS-IP-Address", "Framed-IP-Address",
"Framed-IP-Netmask", "Filter-Id", "Login-IP-Host",
"Reply-Message", "Callback-Number", "Callback-Id",
@ -616,7 +679,7 @@ def main():
"Proxy-State", "Login-LAT-Service", "Login-LAT-Node",
"Login-LAT-Group", "Framed-AppleTalk-Zone", "Acct-Session-Id",
"Acct-Multi-Session-Id"]},
"rsso-endpoint-block-attribute": {"required": False, "type": "str",
"rsso_endpoint_block_attribute": {"required": False, "type": "str",
"choices": ["User-Name", "NAS-IP-Address", "Framed-IP-Address",
"Framed-IP-Netmask", "Filter-Id", "Login-IP-Host",
"Reply-Message", "Callback-Number", "Callback-Id",
@ -625,27 +688,27 @@ def main():
"Proxy-State", "Login-LAT-Service", "Login-LAT-Node",
"Login-LAT-Group", "Framed-AppleTalk-Zone", "Acct-Session-Id",
"Acct-Multi-Session-Id"]},
"rsso-ep-one-ip-only": {"required": False, "type": "str",
"rsso_ep_one_ip_only": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"rsso-flush-ip-session": {"required": False, "type": "str",
"rsso_flush_ip_session": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"rsso-log-flags": {"required": False, "type": "str",
"rsso_log_flags": {"required": False, "type": "str",
"choices": ["protocol-error", "profile-missing", "accounting-stop-missed",
"accounting-event", "endpoint-block", "radiusd-other",
"none"]},
"rsso-log-period": {"required": False, "type": "int"},
"rsso-radius-response": {"required": False, "type": "str",
"rsso_log_period": {"required": False, "type": "int"},
"rsso_radius_response": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"rsso-radius-server-port": {"required": False, "type": "int"},
"rsso-secret": {"required": False, "type": "str"},
"rsso-validate-request-secret": {"required": False, "type": "str",
"rsso_radius_server_port": {"required": False, "type": "int"},
"rsso_secret": {"required": False, "type": "str"},
"rsso_validate_request_secret": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"secondary-secret": {"required": False, "type": "str"},
"secondary-server": {"required": False, "type": "str"},
"secondary_secret": {"required": False, "type": "str"},
"secondary_server": {"required": False, "type": "str"},
"secret": {"required": False, "type": "str"},
"server": {"required": False, "type": "str"},
"source-ip": {"required": False, "type": "str"},
"sso-attribute": {"required": False, "type": "str",
"source_ip": {"required": False, "type": "str"},
"sso_attribute": {"required": False, "type": "str",
"choices": ["User-Name", "NAS-IP-Address", "Framed-IP-Address",
"Framed-IP-Netmask", "Filter-Id", "Login-IP-Host",
"Reply-Message", "Callback-Number", "Callback-Id",
@ -654,15 +717,15 @@ def main():
"Proxy-State", "Login-LAT-Service", "Login-LAT-Node",
"Login-LAT-Group", "Framed-AppleTalk-Zone", "Acct-Session-Id",
"Acct-Multi-Session-Id"]},
"sso-attribute-key": {"required": False, "type": "str"},
"sso-attribute-value-override": {"required": False, "type": "str",
"sso_attribute_key": {"required": False, "type": "str"},
"sso_attribute_value_override": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tertiary-secret": {"required": False, "type": "str"},
"tertiary-server": {"required": False, "type": "str"},
"tertiary_secret": {"required": False, "type": "str"},
"tertiary_server": {"required": False, "type": "str"},
"timeout": {"required": False, "type": "int"},
"use-management-vdom": {"required": False, "type": "str",
"use_management_vdom": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"username-case-sensitive": {"required": False, "type": "str",
"username_case_sensitive": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}
@ -671,15 +734,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_user(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_user(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_user(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_user_tacacsplus
short_description: Configure TACACS+ server entries in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by
allowing the user to configure user feature and tacacsplus category.
Examples includes all options and need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify user feature and tacacsplus category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,43 +41,57 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip adress.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
user_tacacsplus:
description:
- Configure TACACS+ server entries.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
authen-type:
authen_type:
description:
- Allowed authentication protocols/methods.
type: str
choices:
- mschap
- chap
@ -90,37 +101,47 @@ options:
authorization:
description:
- Enable/disable TACACS+ authorization.
type: str
choices:
- enable
- disable
key:
description:
- Key to access the primary server.
type: str
name:
description:
- TACACS+ server entry name.
required: true
type: str
port:
description:
- Port number of the TACACS+ server.
secondary-key:
type: int
secondary_key:
description:
- Key to access the secondary server.
secondary-server:
type: str
secondary_server:
description:
- Secondary TACACS+ server CN domain name or IP address.
type: str
server:
description:
- Primary TACACS+ server CN domain name or IP address.
source-ip:
type: str
source_ip:
description:
- source IP for communications to TACACS+ server.
tertiary-key:
type: str
tertiary_key:
description:
- Key to access the tertiary server.
tertiary-server:
type: str
tertiary_server:
description:
- Tertiary TACACS+ server CN domain name or IP address.
type: str
'''
EXAMPLES = '''
@ -130,6 +151,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure TACACS+ server entries.
fortios_user_tacacsplus:
@ -138,19 +160,19 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
user_tacacsplus:
state: "present"
authen-type: "mschap"
authen_type: "mschap"
authorization: "enable"
key: "<your_own_value>"
name: "default_name_6"
port: "7"
secondary-key: "<your_own_value>"
secondary-server: "<your_own_value>"
secondary_key: "<your_own_value>"
secondary_server: "<your_own_value>"
server: "192.168.100.40"
source-ip: "84.230.14.43"
tertiary-key: "<your_own_value>"
tertiary-server: "<your_own_value>"
source_ip: "84.230.14.43"
tertiary_key: "<your_own_value>"
tertiary_server: "<your_own_value>"
'''
RETURN = '''
@ -213,14 +235,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
fos = None
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -228,14 +252,14 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_user_tacacsplus_data(json):
option_list = ['authen-type', 'authorization', 'key',
'name', 'port', 'secondary-key',
'secondary-server', 'server', 'source-ip',
'tertiary-key', 'tertiary-server']
option_list = ['authen_type', 'authorization', 'key',
'name', 'port', 'secondary_key',
'secondary_server', 'server', 'source_ip',
'tertiary_key', 'tertiary_server']
dictionary = {}
for attribute in option_list:
@ -245,49 +269,67 @@ def filter_user_tacacsplus_data(json):
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def user_tacacsplus(data, fos):
vdom = data['vdom']
state = data['state']
user_tacacsplus_data = data['user_tacacsplus']
filtered_data = filter_user_tacacsplus_data(user_tacacsplus_data)
if user_tacacsplus_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_user_tacacsplus_data(user_tacacsplus_data))
if state == "present":
return fos.set('user',
'tacacs+',
data=filtered_data,
vdom=vdom)
elif user_tacacsplus_data['state'] == "absent":
elif state == "absent":
return fos.delete('user',
'tacacs+',
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_user(data, fos):
login(data)
methodlist = ['user_tacacsplus']
for method in methodlist:
if data[method]:
resp = eval(method)(data, fos)
break
if data['user_tacacsplus']:
resp = user_tacacsplus(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"]},
"user_tacacsplus": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"authen-type": {"required": False, "type": "str",
"authen_type": {"required": False, "type": "str",
"choices": ["mschap", "chap", "pap",
"ascii", "auto"]},
"authorization": {"required": False, "type": "str",
@ -295,12 +337,12 @@ def main():
"key": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"port": {"required": False, "type": "int"},
"secondary-key": {"required": False, "type": "str"},
"secondary-server": {"required": False, "type": "str"},
"secondary_key": {"required": False, "type": "str"},
"secondary_server": {"required": False, "type": "str"},
"server": {"required": False, "type": "str"},
"source-ip": {"required": False, "type": "str"},
"tertiary-key": {"required": False, "type": "str"},
"tertiary-server": {"required": False, "type": "str"}
"source_ip": {"required": False, "type": "str"},
"tertiary_key": {"required": False, "type": "str"},
"tertiary_server": {"required": False, "type": "str"}
}
}
@ -308,15 +350,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
global fos
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_user(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_user(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_user(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_vpn_ipsec_concentrator
short_description: Concentrator 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 vpn_ipsec feature and concentrator 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,55 +41,72 @@ 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
vpn_ipsec_concentrator:
description:
- Concentrator configuration.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
member:
description:
- Names of up to 3 VPN tunnels to add to the concentrator.
type: list
suboptions:
name:
description:
- Member name. Source vpn.ipsec.manualkey.name vpn.ipsec.phase1.name.
required: true
type: str
name:
description:
- Concentrator name.
required: true
src-check:
type: str
src_check:
description:
- Enable to check source address of phase 2 selector. Disable to check only the destination selector.
type: str
choices:
- disable
- enable
@ -105,6 +119,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Concentrator configuration.
fortios_vpn_ipsec_concentrator:
@ -113,13 +128,13 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_concentrator:
state: "present"
member:
-
name: "default_name_4 (source vpn.ipsec.manualkey.name vpn.ipsec.phase1.name)"
name: "default_name_5"
src-check: "disable"
src_check: "disable"
'''
RETURN = '''
@ -182,14 +197,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,11 +214,11 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_concentrator_data(json):
option_list = ['member', 'name', 'src-check']
option_list = ['member', 'name', 'src_check']
dictionary = {}
for attribute in option_list:
@ -211,67 +228,72 @@ def filter_vpn_ipsec_concentrator_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 vpn_ipsec_concentrator(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_concentrator_data = data['vpn_ipsec_concentrator']
flattened_data = flatten_multilists_attributes(vpn_ipsec_concentrator_data)
filtered_data = filter_vpn_ipsec_concentrator_data(flattened_data)
if vpn_ipsec_concentrator_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_concentrator_data(vpn_ipsec_concentrator_data))
if state == "present":
return fos.set('vpn.ipsec',
'concentrator',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_concentrator_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'concentrator',
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_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_concentrator']:
resp = vpn_ipsec_concentrator(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"]},
"vpn_ipsec_concentrator": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"member": {"required": False, "type": "list",
"options": {
"name": {"required": True, "type": "str"}
}},
"name": {"required": True, "type": "str"},
"src-check": {"required": False, "type": "str",
"src_check": {"required": False, "type": "str",
"choices": ["disable", "enable"]}
}
@ -280,15 +302,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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_vpn_ipsec_forticlient
short_description: Configure FortiClient policy realm 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 vpn_ipsec feature and forticlient 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,57 +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
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
vpn_ipsec_forticlient:
description:
- Configure FortiClient policy realm.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
phase2name:
description:
- Phase 2 tunnel name that you defined in the FortiClient dialup configuration. Source vpn.ipsec.phase2.name vpn.ipsec.phase2-interface
.name.
type: str
realm:
description:
- FortiClient realm name.
required: true
type: str
status:
description:
- Enable/disable this FortiClient configuration.
type: str
choices:
- enable
- disable
usergroupname:
description:
- User group name for FortiClient users. Source user.group.name.
type: str
'''
EXAMPLES = '''
@ -104,6 +118,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure FortiClient policy realm.
fortios_vpn_ipsec_forticlient:
@ -112,8 +127,8 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_forticlient:
state: "present"
phase2name: "<your_own_value> (source vpn.ipsec.phase2.name vpn.ipsec.phase2-interface.name)"
realm: "<your_own_value>"
status: "enable"
@ -180,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']:
@ -195,7 +212,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_forticlient_data(json):
@ -210,61 +227,66 @@ def filter_vpn_ipsec_forticlient_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 vpn_ipsec_forticlient(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_forticlient_data = data['vpn_ipsec_forticlient']
flattened_data = flatten_multilists_attributes(vpn_ipsec_forticlient_data)
filtered_data = filter_vpn_ipsec_forticlient_data(flattened_data)
if vpn_ipsec_forticlient_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_forticlient_data(vpn_ipsec_forticlient_data))
if state == "present":
return fos.set('vpn.ipsec',
'forticlient',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_forticlient_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'forticlient',
mkey=filtered_data['realm'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_forticlient']:
resp = vpn_ipsec_forticlient(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"]},
"vpn_ipsec_forticlient": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"phase2name": {"required": False, "type": "str"},
"realm": {"required": True, "type": "str"},
"status": {"required": False, "type": "str",
@ -277,15 +299,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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_vpn_ipsec_manualkey
short_description: Configure IPsec manual keys 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 vpn_ipsec feature and manualkey category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,43 +41,57 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
vpn_ipsec_manualkey:
description:
- Configure IPsec manual keys.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
authentication:
description:
- Authentication algorithm. Must be the same for both ends of the tunnel.
type: str
choices:
- null
- md5
@ -91,40 +102,43 @@ options:
authkey:
description:
- Hexadecimal authentication key in 16-digit (8-byte) segments separated by hyphens.
type: str
enckey:
description:
- Hexadecimal encryption key in 16-digit (8-byte) segments separated by hyphens.
type: str
encryption:
description:
- Encryption algorithm. Must be the same for both ends of the tunnel.
type: str
choices:
- null
- des
interface:
description:
- Name of the physical, aggregate, or VLAN interface. Source system.interface.name.
local-gw:
type: str
local_gw:
description:
- Local gateway.
type: str
localspi:
description:
- Local SPI, a hexadecimal 8-digit (4-byte) tag. Discerns between two traffic streams with different encryption rules.
type: str
name:
description:
- IPsec tunnel name.
required: true
npu-offload:
description:
- Enable/disable NPU offloading.
choices:
- enable
- disable
remote-gw:
type: str
remote_gw:
description:
- Peer gateway.
type: str
remotespi:
description:
- Remote SPI, a hexadecimal 8-digit (4-byte) tag. Discerns between two traffic streams with different encryption rules.
type: str
'''
EXAMPLES = '''
@ -134,6 +148,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPsec manual keys.
fortios_vpn_ipsec_manualkey:
@ -142,18 +157,17 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_manualkey:
state: "present"
authentication: "null"
authkey: "<your_own_value>"
enckey: "<your_own_value>"
encryption: "null"
interface: "<your_own_value> (source system.interface.name)"
local-gw: "<your_own_value>"
local_gw: "<your_own_value>"
localspi: "<your_own_value>"
name: "default_name_10"
npu-offload: "enable"
remote-gw: "<your_own_value>"
remote_gw: "<your_own_value>"
remotespi: "<your_own_value>"
'''
@ -217,14 +231,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
fos = None
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -232,14 +248,14 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_manualkey_data(json):
option_list = ['authentication', 'authkey', 'enckey',
'encryption', 'interface', 'local-gw',
'localspi', 'name', 'npu-offload',
'remote-gw', 'remotespi']
'encryption', 'interface', 'local_gw',
'localspi', 'name', 'remote_gw',
'remotespi']
dictionary = {}
for attribute in option_list:
@ -249,61 +265,66 @@ def filter_vpn_ipsec_manualkey_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 vpn_ipsec_manualkey(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_manualkey_data = data['vpn_ipsec_manualkey']
flattened_data = flatten_multilists_attributes(vpn_ipsec_manualkey_data)
filtered_data = filter_vpn_ipsec_manualkey_data(flattened_data)
if vpn_ipsec_manualkey_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_manualkey_data(vpn_ipsec_manualkey_data))
if state == "present":
return fos.set('vpn.ipsec',
'manualkey',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_manualkey_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'manualkey',
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_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_manualkey']:
resp = vpn_ipsec_manualkey(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"]},
"vpn_ipsec_manualkey": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"authentication": {"required": False, "type": "str",
"choices": ["null", "md5", "sha1",
"sha256", "sha384", "sha512"]},
@ -312,12 +333,10 @@ def main():
"encryption": {"required": False, "type": "str",
"choices": ["null", "des"]},
"interface": {"required": False, "type": "str"},
"local-gw": {"required": False, "type": "str"},
"local_gw": {"required": False, "type": "str"},
"localspi": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"npu-offload": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"remote-gw": {"required": False, "type": "str"},
"remote_gw": {"required": False, "type": "str"},
"remotespi": {"required": False, "type": "str"}
}
@ -326,15 +345,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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_vpn_ipsec_manualkey_interface
short_description: Configure IPsec manual keys 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 vpn_ipsec feature and manualkey_interface category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,49 +41,64 @@ 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
vpn_ipsec_manualkey_interface:
description:
- Configure IPsec manual keys.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
addr-type:
addr_type:
description:
- IP version to use for IP packets.
type: str
choices:
- 4
- 6
auth-alg:
auth_alg:
description:
- Authentication algorithm. Must be the same for both ends of the tunnel.
type: str
choices:
- null
- md5
@ -94,55 +106,61 @@ options:
- sha256
- sha384
- sha512
auth-key:
auth_key:
description:
- Hexadecimal authentication key in 16-digit (8-byte) segments separated by hyphens.
enc-alg:
type: str
enc_alg:
description:
- Encryption algorithm. Must be the same for both ends of the tunnel.
type: str
choices:
- null
- des
enc-key:
enc_key:
description:
- Hexadecimal encryption key in 16-digit (8-byte) segments separated by hyphens.
type: str
interface:
description:
- Name of the physical, aggregate, or VLAN interface. Source system.interface.name.
ip-version:
type: str
ip_version:
description:
- IP version to use for VPN interface.
type: str
choices:
- 4
- 6
local-gw:
local_gw:
description:
- IPv4 address of the local gateway's external interface.
local-gw6:
type: str
local_gw6:
description:
- Local IPv6 address of VPN gateway.
local-spi:
type: str
local_spi:
description:
- Local SPI, a hexadecimal 8-digit (4-byte) tag. Discerns between two traffic streams with different encryption rules.
type: str
name:
description:
- IPsec tunnel name.
required: true
npu-offload:
description:
- Enable/disable offloading IPsec VPN manual key sessions to NPUs.
choices:
- enable
- disable
remote-gw:
type: str
remote_gw:
description:
- IPv4 address of the remote gateway's external interface.
remote-gw6:
type: str
remote_gw6:
description:
- Remote IPv6 address of VPN gateway.
remote-spi:
type: str
remote_spi:
description:
- Remote SPI, a hexadecimal 8-digit (4-byte) tag. Discerns between two traffic streams with different encryption rules.
type: str
'''
EXAMPLES = '''
@ -152,6 +170,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure IPsec manual keys.
fortios_vpn_ipsec_manualkey_interface:
@ -160,23 +179,22 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_manualkey_interface:
state: "present"
addr-type: "4"
auth-alg: "null"
auth-key: "<your_own_value>"
enc-alg: "null"
enc-key: "<your_own_value>"
addr_type: "4"
auth_alg: "null"
auth_key: "<your_own_value>"
enc_alg: "null"
enc_key: "<your_own_value>"
interface: "<your_own_value> (source system.interface.name)"
ip-version: "4"
local-gw: "<your_own_value>"
local-gw6: "<your_own_value>"
local-spi: "<your_own_value>"
ip_version: "4"
local_gw: "<your_own_value>"
local_gw6: "<your_own_value>"
local_spi: "<your_own_value>"
name: "default_name_13"
npu-offload: "enable"
remote-gw: "<your_own_value>"
remote-gw6: "<your_own_value>"
remote-spi: "<your_own_value>"
remote_gw: "<your_own_value>"
remote_gw6: "<your_own_value>"
remote_spi: "<your_own_value>"
'''
RETURN = '''
@ -239,14 +257,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
fos = None
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -254,15 +274,15 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_manualkey_interface_data(json):
option_list = ['addr-type', 'auth-alg', 'auth-key',
'enc-alg', 'enc-key', 'interface',
'ip-version', 'local-gw', 'local-gw6',
'local-spi', 'name', 'npu-offload',
'remote-gw', 'remote-gw6', 'remote-spi']
option_list = ['addr_type', 'auth_alg', 'auth_key',
'enc_alg', 'enc_key', 'interface',
'ip_version', 'local_gw', 'local_gw6',
'local_spi', 'name', 'remote_gw',
'remote_gw6', 'remote_spi']
dictionary = {}
for attribute in option_list:
@ -272,82 +292,85 @@ def filter_vpn_ipsec_manualkey_interface_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 vpn_ipsec_manualkey_interface(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_manualkey_interface_data = data['vpn_ipsec_manualkey_interface']
flattened_data = flatten_multilists_attributes(vpn_ipsec_manualkey_interface_data)
filtered_data = filter_vpn_ipsec_manualkey_interface_data(flattened_data)
if vpn_ipsec_manualkey_interface_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_manualkey_interface_data(vpn_ipsec_manualkey_interface_data))
if state == "present":
return fos.set('vpn.ipsec',
'manualkey-interface',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_manualkey_interface_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'manualkey-interface',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_manualkey_interface']:
resp = vpn_ipsec_manualkey_interface(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"vpn_ipsec_manualkey_interface": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"addr-type": {"required": False, "type": "str",
"addr_type": {"required": False, "type": "str",
"choices": ["4", "6"]},
"auth-alg": {"required": False, "type": "str",
"auth_alg": {"required": False, "type": "str",
"choices": ["null", "md5", "sha1",
"sha256", "sha384", "sha512"]},
"auth-key": {"required": False, "type": "str"},
"enc-alg": {"required": False, "type": "str",
"auth_key": {"required": False, "type": "str"},
"enc_alg": {"required": False, "type": "str",
"choices": ["null", "des"]},
"enc-key": {"required": False, "type": "str"},
"enc_key": {"required": False, "type": "str"},
"interface": {"required": False, "type": "str"},
"ip-version": {"required": False, "type": "str",
"ip_version": {"required": False, "type": "str",
"choices": ["4", "6"]},
"local-gw": {"required": False, "type": "str"},
"local-gw6": {"required": False, "type": "str"},
"local-spi": {"required": False, "type": "str"},
"local_gw": {"required": False, "type": "str"},
"local_gw6": {"required": False, "type": "str"},
"local_spi": {"required": False, "type": "str"},
"name": {"required": True, "type": "str"},
"npu-offload": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"remote-gw": {"required": False, "type": "str"},
"remote-gw6": {"required": False, "type": "str"},
"remote-spi": {"required": False, "type": "str"}
"remote_gw": {"required": False, "type": "str"},
"remote_gw6": {"required": False, "type": "str"},
"remote_spi": {"required": False, "type": "str"}
}
}
@ -355,15 +378,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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_vpn_ipsec_phase2
short_description: Configure VPN autokey tunnel 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 vpn_ipsec feature and phase2 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,65 +41,83 @@ 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
vpn_ipsec_phase2:
description:
- Configure VPN autokey tunnel.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
add-route:
add_route:
description:
- Enable/disable automatic route addition.
type: str
choices:
- phase1
- enable
- disable
auto-negotiate:
auto_negotiate:
description:
- Enable/disable IPsec SA auto-negotiation.
type: str
choices:
- enable
- disable
comments:
description:
- Comment.
dhcp-ipsec:
type: str
dhcp_ipsec:
description:
- Enable/disable DHCP-IPsec.
type: str
choices:
- enable
- disable
dhgrp:
description:
- Phase2 DH group.
type: str
choices:
- 1
- 2
@ -120,56 +135,69 @@ options:
- 29
- 30
- 31
dst-addr-type:
dst_addr_type:
description:
- Remote proxy ID type.
type: str
choices:
- subnet
- range
- ip
- name
dst-end-ip:
dst_end_ip:
description:
- Remote proxy ID IPv4 end.
dst-end-ip6:
type: str
dst_end_ip6:
description:
- Remote proxy ID IPv6 end.
dst-name:
type: str
dst_name:
description:
- Remote proxy ID name. Source firewall.address.name firewall.addrgrp.name.
dst-name6:
type: str
dst_name6:
description:
- Remote proxy ID name. Source firewall.address6.name firewall.addrgrp6.name.
dst-port:
type: str
dst_port:
description:
- Quick mode destination port (1 - 65535 or 0 for all).
dst-start-ip:
type: int
dst_start_ip:
description:
- Remote proxy ID IPv4 start.
dst-start-ip6:
type: str
dst_start_ip6:
description:
- Remote proxy ID IPv6 start.
dst-subnet:
type: str
dst_subnet:
description:
- Remote proxy ID IPv4 subnet.
dst-subnet6:
type: str
dst_subnet6:
description:
- Remote proxy ID IPv6 subnet.
type: str
encapsulation:
description:
- ESP encapsulation mode.
type: str
choices:
- tunnel-mode
- transport-mode
keepalive:
description:
- Enable/disable keep alive.
type: str
choices:
- enable
- disable
keylife-type:
keylife_type:
description:
- Keylife type.
type: str
choices:
- seconds
- kbs
@ -177,12 +205,15 @@ options:
keylifekbs:
description:
- Phase2 key life in number of bytes of traffic (5120 - 4294967295).
type: int
keylifeseconds:
description:
- Phase2 key life in time in seconds (120 - 172800).
type: int
l2tp:
description:
- Enable/disable L2TP over IPsec.
type: str
choices:
- enable
- disable
@ -190,18 +221,22 @@ options:
description:
- IPsec tunnel name.
required: true
type: str
pfs:
description:
- Enable/disable PFS feature.
type: str
choices:
- enable
- disable
phase1name:
description:
- Phase 1 determines the options required for phase 2. Source vpn.ipsec.phase1.name.
type: str
proposal:
description:
- Phase2 proposal.
type: str
choices:
- null-md5
- null-sha1
@ -217,70 +252,86 @@ options:
protocol:
description:
- Quick mode protocol selector (1 - 255 or 0 for all).
type: int
replay:
description:
- Enable/disable replay detection.
type: str
choices:
- enable
- disable
route-overlap:
route_overlap:
description:
- Action for overlapping routes.
type: str
choices:
- use-old
- use-new
- allow
selector-match:
selector_match:
description:
- Match type to use when comparing selectors.
type: str
choices:
- exact
- subset
- auto
single-source:
single_source:
description:
- Enable/disable single source IP restriction.
type: str
choices:
- enable
- disable
src-addr-type:
src_addr_type:
description:
- Local proxy ID type.
type: str
choices:
- subnet
- range
- ip
- name
src-end-ip:
src_end_ip:
description:
- Local proxy ID end.
src-end-ip6:
type: str
src_end_ip6:
description:
- Local proxy ID IPv6 end.
src-name:
type: str
src_name:
description:
- Local proxy ID name. Source firewall.address.name firewall.addrgrp.name.
src-name6:
type: str
src_name6:
description:
- Local proxy ID name. Source firewall.address6.name firewall.addrgrp6.name.
src-port:
type: str
src_port:
description:
- Quick mode source port (1 - 65535 or 0 for all).
src-start-ip:
type: int
src_start_ip:
description:
- Local proxy ID start.
src-start-ip6:
type: str
src_start_ip6:
description:
- Local proxy ID IPv6 start.
src-subnet:
type: str
src_subnet:
description:
- Local proxy ID subnet.
src-subnet6:
type: str
src_subnet6:
description:
- Local proxy ID IPv6 subnet.
use-natip:
type: str
use_natip:
description:
- Enable to use the FortiGate public IP as the source selector when outbound NAT is used.
type: str
choices:
- enable
- disable
@ -293,6 +344,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure VPN autokey tunnel.
fortios_vpn_ipsec_phase2:
@ -301,26 +353,26 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_phase2:
state: "present"
add-route: "phase1"
auto-negotiate: "enable"
add_route: "phase1"
auto_negotiate: "enable"
comments: "<your_own_value>"
dhcp-ipsec: "enable"
dhcp_ipsec: "enable"
dhgrp: "1"
dst-addr-type: "subnet"
dst-end-ip: "<your_own_value>"
dst-end-ip6: "<your_own_value>"
dst-name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
dst-name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
dst-port: "13"
dst-start-ip: "<your_own_value>"
dst-start-ip6: "<your_own_value>"
dst-subnet: "<your_own_value>"
dst-subnet6: "<your_own_value>"
dst_addr_type: "subnet"
dst_end_ip: "<your_own_value>"
dst_end_ip6: "<your_own_value>"
dst_name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
dst_name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
dst_port: "13"
dst_start_ip: "<your_own_value>"
dst_start_ip6: "<your_own_value>"
dst_subnet: "<your_own_value>"
dst_subnet6: "<your_own_value>"
encapsulation: "tunnel-mode"
keepalive: "enable"
keylife-type: "seconds"
keylife_type: "seconds"
keylifekbs: "21"
keylifeseconds: "22"
l2tp: "enable"
@ -330,20 +382,20 @@ EXAMPLES = '''
proposal: "null-md5"
protocol: "28"
replay: "enable"
route-overlap: "use-old"
selector-match: "exact"
single-source: "enable"
src-addr-type: "subnet"
src-end-ip: "<your_own_value>"
src-end-ip6: "<your_own_value>"
src-name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
src-name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
src-port: "38"
src-start-ip: "<your_own_value>"
src-start-ip6: "<your_own_value>"
src-subnet: "<your_own_value>"
src-subnet6: "<your_own_value>"
use-natip: "enable"
route_overlap: "use-old"
selector_match: "exact"
single_source: "enable"
src_addr_type: "subnet"
src_end_ip: "<your_own_value>"
src_end_ip6: "<your_own_value>"
src_name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
src_name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
src_port: "38"
src_start_ip: "<your_own_value>"
src_start_ip6: "<your_own_value>"
src_subnet: "<your_own_value>"
src_subnet6: "<your_own_value>"
use_natip: "enable"
'''
RETURN = '''
@ -406,14 +458,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']:
@ -421,24 +475,24 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_phase2_data(json):
option_list = ['add-route', 'auto-negotiate', 'comments',
'dhcp-ipsec', 'dhgrp', 'dst-addr-type',
'dst-end-ip', 'dst-end-ip6', 'dst-name',
'dst-name6', 'dst-port', 'dst-start-ip',
'dst-start-ip6', 'dst-subnet', 'dst-subnet6',
'encapsulation', 'keepalive', 'keylife-type',
option_list = ['add_route', 'auto_negotiate', 'comments',
'dhcp_ipsec', 'dhgrp', 'dst_addr_type',
'dst_end_ip', 'dst_end_ip6', 'dst_name',
'dst_name6', 'dst_port', 'dst_start_ip',
'dst_start_ip6', 'dst_subnet', 'dst_subnet6',
'encapsulation', 'keepalive', 'keylife_type',
'keylifekbs', 'keylifeseconds', 'l2tp',
'name', 'pfs', 'phase1name',
'proposal', 'protocol', 'replay',
'route-overlap', 'selector-match', 'single-source',
'src-addr-type', 'src-end-ip', 'src-end-ip6',
'src-name', 'src-name6', 'src-port',
'src-start-ip', 'src-start-ip6', 'src-subnet',
'src-subnet6', 'use-natip']
'route_overlap', 'selector_match', 'single_source',
'src_addr_type', 'src_end_ip', 'src_end_ip6',
'src_name', 'src_name6', 'src_port',
'src_start_ip', 'src_start_ip6', 'src_subnet',
'src_subnet6', 'use_natip']
dictionary = {}
for attribute in option_list:
@ -448,67 +502,72 @@ def filter_vpn_ipsec_phase2_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 vpn_ipsec_phase2(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_phase2_data = data['vpn_ipsec_phase2']
flattened_data = flatten_multilists_attributes(vpn_ipsec_phase2_data)
filtered_data = filter_vpn_ipsec_phase2_data(flattened_data)
if vpn_ipsec_phase2_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_phase2_data(vpn_ipsec_phase2_data))
if state == "present":
return fos.set('vpn.ipsec',
'phase2',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_phase2_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'phase2',
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_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_phase2']:
resp = vpn_ipsec_phase2(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"]},
"vpn_ipsec_phase2": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"add-route": {"required": False, "type": "str",
"add_route": {"required": False, "type": "str",
"choices": ["phase1", "enable", "disable"]},
"auto-negotiate": {"required": False, "type": "str",
"auto_negotiate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"comments": {"required": False, "type": "str"},
"dhcp-ipsec": {"required": False, "type": "str",
"dhcp_ipsec": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"dhgrp": {"required": False, "type": "str",
"choices": ["1", "2", "5",
@ -517,23 +576,23 @@ def main():
"20", "21", "27",
"28", "29", "30",
"31"]},
"dst-addr-type": {"required": False, "type": "str",
"dst_addr_type": {"required": False, "type": "str",
"choices": ["subnet", "range", "ip",
"name"]},
"dst-end-ip": {"required": False, "type": "str"},
"dst-end-ip6": {"required": False, "type": "str"},
"dst-name": {"required": False, "type": "str"},
"dst-name6": {"required": False, "type": "str"},
"dst-port": {"required": False, "type": "int"},
"dst-start-ip": {"required": False, "type": "str"},
"dst-start-ip6": {"required": False, "type": "str"},
"dst-subnet": {"required": False, "type": "str"},
"dst-subnet6": {"required": False, "type": "str"},
"dst_end_ip": {"required": False, "type": "str"},
"dst_end_ip6": {"required": False, "type": "str"},
"dst_name": {"required": False, "type": "str"},
"dst_name6": {"required": False, "type": "str"},
"dst_port": {"required": False, "type": "int"},
"dst_start_ip": {"required": False, "type": "str"},
"dst_start_ip6": {"required": False, "type": "str"},
"dst_subnet": {"required": False, "type": "str"},
"dst_subnet6": {"required": False, "type": "str"},
"encapsulation": {"required": False, "type": "str",
"choices": ["tunnel-mode", "transport-mode"]},
"keepalive": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"keylife-type": {"required": False, "type": "str",
"keylife_type": {"required": False, "type": "str",
"choices": ["seconds", "kbs", "both"]},
"keylifekbs": {"required": False, "type": "int"},
"keylifeseconds": {"required": False, "type": "int"},
@ -551,25 +610,25 @@ def main():
"protocol": {"required": False, "type": "int"},
"replay": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"route-overlap": {"required": False, "type": "str",
"route_overlap": {"required": False, "type": "str",
"choices": ["use-old", "use-new", "allow"]},
"selector-match": {"required": False, "type": "str",
"selector_match": {"required": False, "type": "str",
"choices": ["exact", "subset", "auto"]},
"single-source": {"required": False, "type": "str",
"single_source": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"src-addr-type": {"required": False, "type": "str",
"src_addr_type": {"required": False, "type": "str",
"choices": ["subnet", "range", "ip",
"name"]},
"src-end-ip": {"required": False, "type": "str"},
"src-end-ip6": {"required": False, "type": "str"},
"src-name": {"required": False, "type": "str"},
"src-name6": {"required": False, "type": "str"},
"src-port": {"required": False, "type": "int"},
"src-start-ip": {"required": False, "type": "str"},
"src-start-ip6": {"required": False, "type": "str"},
"src-subnet": {"required": False, "type": "str"},
"src-subnet6": {"required": False, "type": "str"},
"use-natip": {"required": False, "type": "str",
"src_end_ip": {"required": False, "type": "str"},
"src_end_ip6": {"required": False, "type": "str"},
"src_name": {"required": False, "type": "str"},
"src_name6": {"required": False, "type": "str"},
"src_port": {"required": False, "type": "int"},
"src_start_ip": {"required": False, "type": "str"},
"src_start_ip6": {"required": False, "type": "str"},
"src_subnet": {"required": False, "type": "str"},
"src_subnet6": {"required": False, "type": "str"},
"use_natip": {"required": False, "type": "str",
"choices": ["enable", "disable"]}
}
@ -578,15 +637,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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_vpn_ipsec_phase2_interface
short_description: Configure VPN autokey tunnel 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 vpn_ipsec feature and phase2_interface category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,79 +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
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
vpn_ipsec_phase2_interface:
description:
- Configure VPN autokey tunnel.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
add-route:
add_route:
description:
- Enable/disable automatic route addition.
type: str
choices:
- phase1
- enable
- disable
auto-discovery-forwarder:
auto_discovery_forwarder:
description:
- Enable/disable forwarding short-cut messages.
type: str
choices:
- phase1
- enable
- disable
auto-discovery-sender:
auto_discovery_sender:
description:
- Enable/disable sending short-cut messages.
type: str
choices:
- phase1
- enable
- disable
auto-negotiate:
auto_negotiate:
description:
- Enable/disable IPsec SA auto-negotiation.
type: str
choices:
- enable
- disable
comments:
description:
- Comment.
dhcp-ipsec:
type: str
dhcp_ipsec:
description:
- Enable/disable DHCP-IPsec.
type: str
choices:
- enable
- disable
dhgrp:
description:
- Phase2 DH group.
type: str
choices:
- 1
- 2
@ -134,9 +151,10 @@ options:
- 29
- 30
- 31
dst-addr-type:
dst_addr_type:
description:
- Remote proxy ID type.
type: str
choices:
- subnet
- range
@ -146,48 +164,60 @@ options:
- range6
- ip6
- name6
dst-end-ip:
dst_end_ip:
description:
- Remote proxy ID IPv4 end.
dst-end-ip6:
type: str
dst_end_ip6:
description:
- Remote proxy ID IPv6 end.
dst-name:
type: str
dst_name:
description:
- Remote proxy ID name. Source firewall.address.name firewall.addrgrp.name.
dst-name6:
type: str
dst_name6:
description:
- Remote proxy ID name. Source firewall.address6.name firewall.addrgrp6.name.
dst-port:
type: str
dst_port:
description:
- Quick mode destination port (1 - 65535 or 0 for all).
dst-start-ip:
type: int
dst_start_ip:
description:
- Remote proxy ID IPv4 start.
dst-start-ip6:
type: str
dst_start_ip6:
description:
- Remote proxy ID IPv6 start.
dst-subnet:
type: str
dst_subnet:
description:
- Remote proxy ID IPv4 subnet.
dst-subnet6:
type: str
dst_subnet6:
description:
- Remote proxy ID IPv6 subnet.
type: str
encapsulation:
description:
- ESP encapsulation mode.
type: str
choices:
- tunnel-mode
- transport-mode
keepalive:
description:
- Enable/disable keep alive.
type: str
choices:
- enable
- disable
keylife-type:
keylife_type:
description:
- Keylife type.
type: str
choices:
- seconds
- kbs
@ -195,12 +225,15 @@ options:
keylifekbs:
description:
- Phase2 key life in number of bytes of traffic (5120 - 4294967295).
type: int
keylifeseconds:
description:
- Phase2 key life in time in seconds (120 - 172800).
type: int
l2tp:
description:
- Enable/disable L2TP over IPsec.
type: str
choices:
- enable
- disable
@ -208,18 +241,22 @@ options:
description:
- IPsec tunnel name.
required: true
type: str
pfs:
description:
- Enable/disable PFS feature.
type: str
choices:
- enable
- disable
phase1name:
description:
- Phase 1 determines the options required for phase 2. Source vpn.ipsec.phase1-interface.name.
type: str
proposal:
description:
- Phase2 proposal.
type: str
choices:
- null-md5
- null-sha1
@ -235,28 +272,33 @@ options:
protocol:
description:
- Quick mode protocol selector (1 - 255 or 0 for all).
type: int
replay:
description:
- Enable/disable replay detection.
type: str
choices:
- enable
- disable
route-overlap:
route_overlap:
description:
- Action for overlapping routes.
type: str
choices:
- use-old
- use-new
- allow
single-source:
single_source:
description:
- Enable/disable single source IP restriction.
type: str
choices:
- enable
- disable
src-addr-type:
src_addr_type:
description:
- Local proxy ID type.
type: str
choices:
- subnet
- range
@ -266,33 +308,42 @@ options:
- range6
- ip6
- name6
src-end-ip:
src_end_ip:
description:
- Local proxy ID end.
src-end-ip6:
type: str
src_end_ip6:
description:
- Local proxy ID IPv6 end.
src-name:
type: str
src_name:
description:
- Local proxy ID name. Source firewall.address.name firewall.addrgrp.name.
src-name6:
type: str
src_name6:
description:
- Local proxy ID name. Source firewall.address6.name firewall.addrgrp6.name.
src-port:
type: str
src_port:
description:
- Quick mode source port (1 - 65535 or 0 for all).
src-start-ip:
type: int
src_start_ip:
description:
- Local proxy ID start.
src-start-ip6:
type: str
src_start_ip6:
description:
- Local proxy ID IPv6 start.
src-subnet:
type: str
src_subnet:
description:
- Local proxy ID subnet.
src-subnet6:
type: str
src_subnet6:
description:
- Local proxy ID IPv6 subnet.
type: str
'''
EXAMPLES = '''
@ -302,6 +353,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure VPN autokey tunnel.
fortios_vpn_ipsec_phase2_interface:
@ -310,28 +362,28 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
vpn_ipsec_phase2_interface:
state: "present"
add-route: "phase1"
auto-discovery-forwarder: "phase1"
auto-discovery-sender: "phase1"
auto-negotiate: "enable"
add_route: "phase1"
auto_discovery_forwarder: "phase1"
auto_discovery_sender: "phase1"
auto_negotiate: "enable"
comments: "<your_own_value>"
dhcp-ipsec: "enable"
dhcp_ipsec: "enable"
dhgrp: "1"
dst-addr-type: "subnet"
dst-end-ip: "<your_own_value>"
dst-end-ip6: "<your_own_value>"
dst-name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
dst-name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
dst-port: "15"
dst-start-ip: "<your_own_value>"
dst-start-ip6: "<your_own_value>"
dst-subnet: "<your_own_value>"
dst-subnet6: "<your_own_value>"
dst_addr_type: "subnet"
dst_end_ip: "<your_own_value>"
dst_end_ip6: "<your_own_value>"
dst_name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
dst_name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
dst_port: "15"
dst_start_ip: "<your_own_value>"
dst_start_ip6: "<your_own_value>"
dst_subnet: "<your_own_value>"
dst_subnet6: "<your_own_value>"
encapsulation: "tunnel-mode"
keepalive: "enable"
keylife-type: "seconds"
keylife_type: "seconds"
keylifekbs: "23"
keylifeseconds: "24"
l2tp: "enable"
@ -341,18 +393,18 @@ EXAMPLES = '''
proposal: "null-md5"
protocol: "30"
replay: "enable"
route-overlap: "use-old"
single-source: "enable"
src-addr-type: "subnet"
src-end-ip: "<your_own_value>"
src-end-ip6: "<your_own_value>"
src-name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
src-name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
src-port: "39"
src-start-ip: "<your_own_value>"
src-start-ip6: "<your_own_value>"
src-subnet: "<your_own_value>"
src-subnet6: "<your_own_value>"
route_overlap: "use-old"
single_source: "enable"
src_addr_type: "subnet"
src_end_ip: "<your_own_value>"
src_end_ip6: "<your_own_value>"
src_name: "<your_own_value> (source firewall.address.name firewall.addrgrp.name)"
src_name6: "<your_own_value> (source firewall.address6.name firewall.addrgrp6.name)"
src_port: "39"
src_start_ip: "<your_own_value>"
src_start_ip6: "<your_own_value>"
src_subnet: "<your_own_value>"
src_subnet6: "<your_own_value>"
'''
RETURN = '''
@ -415,14 +467,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']:
@ -430,24 +484,24 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_vpn_ipsec_phase2_interface_data(json):
option_list = ['add-route', 'auto-discovery-forwarder', 'auto-discovery-sender',
'auto-negotiate', 'comments', 'dhcp-ipsec',
'dhgrp', 'dst-addr-type', 'dst-end-ip',
'dst-end-ip6', 'dst-name', 'dst-name6',
'dst-port', 'dst-start-ip', 'dst-start-ip6',
'dst-subnet', 'dst-subnet6', 'encapsulation',
'keepalive', 'keylife-type', 'keylifekbs',
option_list = ['add_route', 'auto_discovery_forwarder', 'auto_discovery_sender',
'auto_negotiate', 'comments', 'dhcp_ipsec',
'dhgrp', 'dst_addr_type', 'dst_end_ip',
'dst_end_ip6', 'dst_name', 'dst_name6',
'dst_port', 'dst_start_ip', 'dst_start_ip6',
'dst_subnet', 'dst_subnet6', 'encapsulation',
'keepalive', 'keylife_type', 'keylifekbs',
'keylifeseconds', 'l2tp', 'name',
'pfs', 'phase1name', 'proposal',
'protocol', 'replay', 'route-overlap',
'single-source', 'src-addr-type', 'src-end-ip',
'src-end-ip6', 'src-name', 'src-name6',
'src-port', 'src-start-ip', 'src-start-ip6',
'src-subnet', 'src-subnet6']
'protocol', 'replay', 'route_overlap',
'single_source', 'src_addr_type', 'src_end_ip',
'src_end_ip6', 'src_name', 'src_name6',
'src_port', 'src_start_ip', 'src_start_ip6',
'src_subnet', 'src_subnet6']
dictionary = {}
for attribute in option_list:
@ -457,71 +511,76 @@ def filter_vpn_ipsec_phase2_interface_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 vpn_ipsec_phase2_interface(data, fos):
vdom = data['vdom']
state = data['state']
vpn_ipsec_phase2_interface_data = data['vpn_ipsec_phase2_interface']
flattened_data = flatten_multilists_attributes(vpn_ipsec_phase2_interface_data)
filtered_data = filter_vpn_ipsec_phase2_interface_data(flattened_data)
if vpn_ipsec_phase2_interface_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_vpn_ipsec_phase2_interface_data(vpn_ipsec_phase2_interface_data))
if state == "present":
return fos.set('vpn.ipsec',
'phase2-interface',
data=filtered_data,
vdom=vdom)
elif vpn_ipsec_phase2_interface_data['state'] == "absent":
elif state == "absent":
return fos.delete('vpn.ipsec',
'phase2-interface',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_vpn_ipsec(data, fos):
login(data)
if data['vpn_ipsec_phase2_interface']:
resp = vpn_ipsec_phase2_interface(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"vpn_ipsec_phase2_interface": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"add-route": {"required": False, "type": "str",
"add_route": {"required": False, "type": "str",
"choices": ["phase1", "enable", "disable"]},
"auto-discovery-forwarder": {"required": False, "type": "str",
"auto_discovery_forwarder": {"required": False, "type": "str",
"choices": ["phase1", "enable", "disable"]},
"auto-discovery-sender": {"required": False, "type": "str",
"auto_discovery_sender": {"required": False, "type": "str",
"choices": ["phase1", "enable", "disable"]},
"auto-negotiate": {"required": False, "type": "str",
"auto_negotiate": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"comments": {"required": False, "type": "str"},
"dhcp-ipsec": {"required": False, "type": "str",
"dhcp_ipsec": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"dhgrp": {"required": False, "type": "str",
"choices": ["1", "2", "5",
@ -530,24 +589,24 @@ def main():
"20", "21", "27",
"28", "29", "30",
"31"]},
"dst-addr-type": {"required": False, "type": "str",
"dst_addr_type": {"required": False, "type": "str",
"choices": ["subnet", "range", "ip",
"name", "subnet6", "range6",
"ip6", "name6"]},
"dst-end-ip": {"required": False, "type": "str"},
"dst-end-ip6": {"required": False, "type": "str"},
"dst-name": {"required": False, "type": "str"},
"dst-name6": {"required": False, "type": "str"},
"dst-port": {"required": False, "type": "int"},
"dst-start-ip": {"required": False, "type": "str"},
"dst-start-ip6": {"required": False, "type": "str"},
"dst-subnet": {"required": False, "type": "str"},
"dst-subnet6": {"required": False, "type": "str"},
"dst_end_ip": {"required": False, "type": "str"},
"dst_end_ip6": {"required": False, "type": "str"},
"dst_name": {"required": False, "type": "str"},
"dst_name6": {"required": False, "type": "str"},
"dst_port": {"required": False, "type": "int"},
"dst_start_ip": {"required": False, "type": "str"},
"dst_start_ip6": {"required": False, "type": "str"},
"dst_subnet": {"required": False, "type": "str"},
"dst_subnet6": {"required": False, "type": "str"},
"encapsulation": {"required": False, "type": "str",
"choices": ["tunnel-mode", "transport-mode"]},
"keepalive": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"keylife-type": {"required": False, "type": "str",
"keylife_type": {"required": False, "type": "str",
"choices": ["seconds", "kbs", "both"]},
"keylifekbs": {"required": False, "type": "int"},
"keylifeseconds": {"required": False, "type": "int"},
@ -565,23 +624,23 @@ def main():
"protocol": {"required": False, "type": "int"},
"replay": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"route-overlap": {"required": False, "type": "str",
"route_overlap": {"required": False, "type": "str",
"choices": ["use-old", "use-new", "allow"]},
"single-source": {"required": False, "type": "str",
"single_source": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"src-addr-type": {"required": False, "type": "str",
"src_addr_type": {"required": False, "type": "str",
"choices": ["subnet", "range", "ip",
"name", "subnet6", "range6",
"ip6", "name6"]},
"src-end-ip": {"required": False, "type": "str"},
"src-end-ip6": {"required": False, "type": "str"},
"src-name": {"required": False, "type": "str"},
"src-name6": {"required": False, "type": "str"},
"src-port": {"required": False, "type": "int"},
"src-start-ip": {"required": False, "type": "str"},
"src-start-ip6": {"required": False, "type": "str"},
"src-subnet": {"required": False, "type": "str"},
"src-subnet6": {"required": False, "type": "str"}
"src_end_ip": {"required": False, "type": "str"},
"src_end_ip6": {"required": False, "type": "str"},
"src_name": {"required": False, "type": "str"},
"src_name6": {"required": False, "type": "str"},
"src_port": {"required": False, "type": "int"},
"src_start_ip": {"required": False, "type": "str"},
"src_start_ip6": {"required": False, "type": "str"},
"src_subnet": {"required": False, "type": "str"},
"src_subnet6": {"required": False, "type": "str"}
}
}
@ -589,15 +648,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_vpn_ipsec(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_vpn_ipsec(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_vpn_ipsec(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

@ -26,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_wanopt_profile
short_description: Configure WAN optimization profiles in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by allowing the
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify wanopt feature and profile category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -41,58 +41,75 @@ 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
wanopt_profile:
description:
- Configure WAN optimization profiles.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
auth-group:
auth_group:
description:
- Optionally add an authentication group to restrict access to the WAN Optimization tunnel to peers in the authentication group. Source
wanopt.auth-group.name.
type: str
cifs:
description:
- Enable/disable CIFS (Windows sharing) WAN Optimization and configure CIFS WAN Optimization features.
type: dict
suboptions:
byte-caching:
byte_caching:
description:
- Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching file data sent across the WAN and in
future serving if from the cache.
type: str
choices:
- enable
- disable
log-traffic:
log_traffic:
description:
- Enable/disable logging.
type: str
choices:
- enable
- disable
@ -100,27 +117,32 @@ options:
description:
- Single port number or port number range for CIFS. Only packets with a destination port number that matches this port number or
range are accepted by this profile.
prefer-chunking:
type: int
prefer_chunking:
description:
- Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
type: str
choices:
- dynamic
- fix
secure-tunnel:
secure_tunnel:
description:
- Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
type: str
choices:
- enable
- disable
status:
description:
- Enable/disable HTTP WAN Optimization.
type: str
choices:
- enable
- disable
tunnel-sharing:
tunnel_sharing:
description:
- Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
type: str
choices:
- private
- shared
@ -128,20 +150,24 @@ options:
comments:
description:
- Comment.
type: str
ftp:
description:
- Enable/disable FTP WAN Optimization and configure FTP WAN Optimization features.
type: dict
suboptions:
byte-caching:
byte_caching:
description:
- Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching file data sent across the WAN and in
future serving if from the cache.
type: str
choices:
- enable
- disable
log-traffic:
log_traffic:
description:
- Enable/disable logging.
type: str
choices:
- enable
- disable
@ -149,27 +175,32 @@ options:
description:
- Single port number or port number range for FTP. Only packets with a destination port number that matches this port number or
range are accepted by this profile.
prefer-chunking:
type: int
prefer_chunking:
description:
- Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
type: str
choices:
- dynamic
- fix
secure-tunnel:
secure_tunnel:
description:
- Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
type: str
choices:
- enable
- disable
status:
description:
- Enable/disable HTTP WAN Optimization.
type: str
choices:
- enable
- disable
tunnel-sharing:
tunnel_sharing:
description:
- Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
type: str
choices:
- private
- shared
@ -177,17 +208,20 @@ options:
http:
description:
- Enable/disable HTTP WAN Optimization and configure HTTP WAN Optimization features.
type: dict
suboptions:
byte-caching:
byte_caching:
description:
- Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching file data sent across the WAN and in
future serving if from the cache.
type: str
choices:
- enable
- disable
log-traffic:
log_traffic:
description:
- Enable/disable logging.
type: str
choices:
- enable
- disable
@ -195,50 +229,59 @@ options:
description:
- Single port number or port number range for HTTP. Only packets with a destination port number that matches this port number or
range are accepted by this profile.
prefer-chunking:
type: int
prefer_chunking:
description:
- Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
type: str
choices:
- dynamic
- fix
secure-tunnel:
secure_tunnel:
description:
- Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
type: str
choices:
- enable
- disable
ssl:
description:
- Enable/disable SSL/TLS offloading (hardware acceleration) for HTTPS traffic in this tunnel.
type: str
choices:
- enable
- disable
ssl-port:
ssl_port:
description:
- Port on which to expect HTTPS traffic for SSL/TLS offloading.
type: int
status:
description:
- Enable/disable HTTP WAN Optimization.
type: str
choices:
- enable
- disable
tunnel-non-http:
tunnel_non_http:
description:
- Configure how to process non-HTTP traffic when a profile configured for HTTP traffic accepts a non-HTTP session. Can occur if an
application sends non-HTTP traffic using an HTTP destination port.
type: str
choices:
- enable
- disable
tunnel-sharing:
tunnel_sharing:
description:
- Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
type: str
choices:
- private
- shared
- express-shared
unknown-http-version:
unknown_http_version:
description:
- How to handle HTTP sessions that do not comply with HTTP 0.9, 1.0, or 1.1.
type: str
choices:
- reject
- tunnel
@ -246,17 +289,20 @@ options:
mapi:
description:
- Enable/disable MAPI email WAN Optimization and configure MAPI WAN Optimization features.
type: dict
suboptions:
byte-caching:
byte_caching:
description:
- Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching file data sent across the WAN and in
future serving if from the cache.
type: str
choices:
- enable
- disable
log-traffic:
log_traffic:
description:
- Enable/disable logging.
type: str
choices:
- enable
- disable
@ -264,21 +310,25 @@ options:
description:
- Single port number or port number range for MAPI. Only packets with a destination port number that matches this port number or
range are accepted by this profile.
secure-tunnel:
type: int
secure_tunnel:
description:
- Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
type: str
choices:
- enable
- disable
status:
description:
- Enable/disable HTTP WAN Optimization.
type: str
choices:
- enable
- disable
tunnel-sharing:
tunnel_sharing:
description:
- Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
type: str
choices:
- private
- shared
@ -287,26 +337,31 @@ options:
description:
- Profile name.
required: true
type: str
tcp:
description:
- Enable/disable TCP WAN Optimization and configure TCP WAN Optimization features.
type: dict
suboptions:
byte-caching:
byte_caching:
description:
- Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching file data sent across the WAN and in
future serving if from the cache.
type: str
choices:
- enable
- disable
byte-caching-opt:
byte_caching_opt:
description:
- Select whether TCP byte-caching uses system memory only or both memory and disk space.
type: str
choices:
- mem-only
- mem-disk
log-traffic:
log_traffic:
description:
- Enable/disable logging.
type: str
choices:
- enable
- disable
@ -314,30 +369,36 @@ options:
description:
- Single port number or port number range for TCP. Only packets with a destination port number that matches this port number or
range are accepted by this profile.
secure-tunnel:
type: str
secure_tunnel:
description:
- Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
type: str
choices:
- enable
- disable
ssl:
description:
- Enable/disable SSL/TLS offloading.
type: str
choices:
- enable
- disable
ssl-port:
ssl_port:
description:
- Port on which to expect HTTPS traffic for SSL/TLS offloading.
type: int
status:
description:
- Enable/disable HTTP WAN Optimization.
type: str
choices:
- enable
- disable
tunnel-sharing:
tunnel_sharing:
description:
- Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
type: str
choices:
- private
- shared
@ -345,6 +406,7 @@ options:
transparent:
description:
- Enable/disable transparent mode.
type: str
choices:
- enable
- disable
@ -357,6 +419,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure WAN optimization profiles.
fortios_wanopt_profile:
@ -365,56 +428,56 @@ EXAMPLES = '''
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
wanopt_profile:
state: "present"
auth-group: "<your_own_value> (source wanopt.auth-group.name)"
auth_group: "<your_own_value> (source wanopt.auth-group.name)"
cifs:
byte-caching: "enable"
log-traffic: "enable"
byte_caching: "enable"
log_traffic: "enable"
port: "7"
prefer-chunking: "dynamic"
secure-tunnel: "enable"
prefer_chunking: "dynamic"
secure_tunnel: "enable"
status: "enable"
tunnel-sharing: "private"
tunnel_sharing: "private"
comments: "<your_own_value>"
ftp:
byte-caching: "enable"
log-traffic: "enable"
byte_caching: "enable"
log_traffic: "enable"
port: "16"
prefer-chunking: "dynamic"
secure-tunnel: "enable"
prefer_chunking: "dynamic"
secure_tunnel: "enable"
status: "enable"
tunnel-sharing: "private"
tunnel_sharing: "private"
http:
byte-caching: "enable"
log-traffic: "enable"
byte_caching: "enable"
log_traffic: "enable"
port: "24"
prefer-chunking: "dynamic"
secure-tunnel: "enable"
prefer_chunking: "dynamic"
secure_tunnel: "enable"
ssl: "enable"
ssl-port: "28"
ssl_port: "28"
status: "enable"
tunnel-non-http: "enable"
tunnel-sharing: "private"
unknown-http-version: "reject"
tunnel_non_http: "enable"
tunnel_sharing: "private"
unknown_http_version: "reject"
mapi:
byte-caching: "enable"
log-traffic: "enable"
byte_caching: "enable"
log_traffic: "enable"
port: "36"
secure-tunnel: "enable"
secure_tunnel: "enable"
status: "enable"
tunnel-sharing: "private"
tunnel_sharing: "private"
name: "default_name_40"
tcp:
byte-caching: "enable"
byte-caching-opt: "mem-only"
log-traffic: "enable"
byte_caching: "enable"
byte_caching_opt: "mem-only"
log_traffic: "enable"
port: "<your_own_value>"
secure-tunnel: "enable"
secure_tunnel: "enable"
ssl: "enable"
ssl-port: "48"
ssl_port: "48"
status: "enable"
tunnel-sharing: "private"
tunnel_sharing: "private"
transparent: "enable"
'''
@ -478,12 +541,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -491,11 +558,11 @@ def login(data, fos):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_wanopt_profile_data(json):
option_list = ['auth-group', 'cifs', 'comments',
option_list = ['auth_group', 'cifs', 'comments',
'ftp', 'http', 'mapi',
'name', 'tcp', 'transparent']
dictionary = {}
@ -507,135 +574,155 @@ def filter_wanopt_profile_data(json):
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def wanopt_profile(data, fos):
vdom = data['vdom']
state = data['state']
wanopt_profile_data = data['wanopt_profile']
filtered_data = filter_wanopt_profile_data(wanopt_profile_data)
filtered_data = underscore_to_hyphen(filter_wanopt_profile_data(wanopt_profile_data))
if wanopt_profile_data['state'] == "present":
if state == "present":
return fos.set('wanopt',
'profile',
data=filtered_data,
vdom=vdom)
elif wanopt_profile_data['state'] == "absent":
elif state == "absent":
return fos.delete('wanopt',
'profile',
mkey=filtered_data['name'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_wanopt(data, fos):
login(data, fos)
if data['wanopt_profile']:
resp = wanopt_profile(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"wanopt_profile": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"auth-group": {"required": False, "type": "str"},
"auth_group": {"required": False, "type": "str"},
"cifs": {"required": False, "type": "dict",
"options": {
"byte-caching": {"required": False, "type": "str",
"byte_caching": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"log-traffic": {"required": False, "type": "str",
"log_traffic": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"port": {"required": False, "type": "int"},
"prefer-chunking": {"required": False, "type": "str",
"prefer_chunking": {"required": False, "type": "str",
"choices": ["dynamic", "fix"]},
"secure-tunnel": {"required": False, "type": "str",
"secure_tunnel": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-sharing": {"required": False, "type": "str",
"tunnel_sharing": {"required": False, "type": "str",
"choices": ["private", "shared", "express-shared"]}
}},
"comments": {"required": False, "type": "str"},
"ftp": {"required": False, "type": "dict",
"options": {
"byte-caching": {"required": False, "type": "str",
"byte_caching": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"log-traffic": {"required": False, "type": "str",
"log_traffic": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"port": {"required": False, "type": "int"},
"prefer-chunking": {"required": False, "type": "str",
"prefer_chunking": {"required": False, "type": "str",
"choices": ["dynamic", "fix"]},
"secure-tunnel": {"required": False, "type": "str",
"secure_tunnel": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-sharing": {"required": False, "type": "str",
"tunnel_sharing": {"required": False, "type": "str",
"choices": ["private", "shared", "express-shared"]}
}},
"http": {"required": False, "type": "dict",
"options": {
"byte-caching": {"required": False, "type": "str",
"byte_caching": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"log-traffic": {"required": False, "type": "str",
"log_traffic": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"port": {"required": False, "type": "int"},
"prefer-chunking": {"required": False, "type": "str",
"prefer_chunking": {"required": False, "type": "str",
"choices": ["dynamic", "fix"]},
"secure-tunnel": {"required": False, "type": "str",
"secure_tunnel": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ssl": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ssl-port": {"required": False, "type": "int"},
"ssl_port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-non-http": {"required": False, "type": "str",
"tunnel_non_http": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-sharing": {"required": False, "type": "str",
"tunnel_sharing": {"required": False, "type": "str",
"choices": ["private", "shared", "express-shared"]},
"unknown-http-version": {"required": False, "type": "str",
"unknown_http_version": {"required": False, "type": "str",
"choices": ["reject", "tunnel", "best-effort"]}
}},
"mapi": {"required": False, "type": "dict",
"options": {
"byte-caching": {"required": False, "type": "str",
"byte_caching": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"log-traffic": {"required": False, "type": "str",
"log_traffic": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"port": {"required": False, "type": "int"},
"secure-tunnel": {"required": False, "type": "str",
"secure_tunnel": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-sharing": {"required": False, "type": "str",
"tunnel_sharing": {"required": False, "type": "str",
"choices": ["private", "shared", "express-shared"]}
}},
"name": {"required": True, "type": "str"},
"tcp": {"required": False, "type": "dict",
"options": {
"byte-caching": {"required": False, "type": "str",
"byte_caching": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"byte-caching-opt": {"required": False, "type": "str",
"byte_caching_opt": {"required": False, "type": "str",
"choices": ["mem-only", "mem-disk"]},
"log-traffic": {"required": False, "type": "str",
"log_traffic": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"port": {"required": False, "type": "str"},
"secure-tunnel": {"required": False, "type": "str",
"secure_tunnel": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ssl": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"ssl-port": {"required": False, "type": "int"},
"ssl_port": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
"choices": ["enable", "disable"]},
"tunnel-sharing": {"required": False, "type": "str",
"tunnel_sharing": {"required": False, "type": "str",
"choices": ["private", "shared", "express-shared"]}
}},
"transparent": {"required": False, "type": "str",
@ -647,14 +734,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_wanopt(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_wanopt(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_wanopt(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -26,10 +26,10 @@ DOCUMENTATION = '''
module: fortios_wanopt_settings
short_description: Configure WAN optimization 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 wanopt feature and settings category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -41,46 +41,59 @@ 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
wanopt_settings:
description:
- Configure WAN optimization settings.
default: null
type: dict
suboptions:
auto-detect-algorithm:
auto_detect_algorithm:
description:
- Auto detection algorithms used in tunnel negotiations.
type: str
choices:
- simple
- diff-req-resp
host-id:
host_id:
description:
- Local host ID (must also be entered in the remote FortiGate's peer list).
tunnel-ssl-algorithm:
type: str
tunnel_ssl_algorithm:
description:
- Relative strength of encryption algorithms accepted during tunnel negotiation.
type: str
choices:
- low
'''
@ -92,6 +105,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure WAN optimization settings.
fortios_wanopt_settings:
@ -101,9 +115,9 @@ EXAMPLES = '''
vdom: "{{ vdom }}"
https: "False"
wanopt_settings:
auto-detect-algorithm: "simple"
host-id: "myhostname"
tunnel-ssl-algorithm: "low"
auto_detect_algorithm: "simple"
host_id: "myhostname"
tunnel_ssl_algorithm: "low"
'''
RETURN = '''
@ -166,12 +180,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -179,11 +197,11 @@ def login(data, fos):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_wanopt_settings_data(json):
option_list = ['auto-detect-algorithm', 'host-id', 'tunnel-ssl-algorithm']
option_list = ['auto_detect_algorithm', 'host_id', 'tunnel_ssl_algorithm']
dictionary = {}
for attribute in option_list:
@ -193,10 +211,23 @@ def filter_wanopt_settings_data(json):
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def wanopt_settings(data, fos):
vdom = data['vdom']
wanopt_settings_data = data['wanopt_settings']
filtered_data = filter_wanopt_settings_data(wanopt_settings_data)
filtered_data = underscore_to_hyphen(filter_wanopt_settings_data(wanopt_settings_data))
return fos.set('wanopt',
'settings',
@ -204,30 +235,36 @@ def wanopt_settings(data, fos):
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_wanopt(data, fos):
login(data, fos)
if data['wanopt_settings']:
resp = wanopt_settings(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"wanopt_settings": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"auto-detect-algorithm": {"required": False, "type": "str",
"auto_detect_algorithm": {"required": False, "type": "str",
"choices": ["simple", "diff-req-resp"]},
"host-id": {"required": False, "type": "str"},
"tunnel-ssl-algorithm": {"required": False, "type": "str",
"host_id": {"required": False, "type": "str"},
"tunnel_ssl_algorithm": {"required": False, "type": "str",
"choices": ["low"]}
}
@ -236,14 +273,31 @@ def main():
module = AnsibleModule(argument_spec=fields,
supports_check_mode=False)
try:
from fortiosapi import FortiOSAPI
except ImportError:
module.fail_json(msg="fortiosapi module is required")
fos = FortiOSAPI()
# legacy_mode refers to using fortiosapi instead of HTTPAPI
legacy_mode = 'host' in module.params and module.params['host'] is not None and \
'username' in module.params and module.params['username'] is not None and \
'password' in module.params and module.params['password'] is not None
if not legacy_mode:
if module._socket_path:
connection = Connection(module._socket_path)
fos = FortiOSHandler(connection)
is_error, has_changed, result = fortios_wanopt(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_wanopt(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_wanopt(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
# Copyright 2018 Fortinet, Inc.
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <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_webfilter_content
short_description: Configure Web filter banned word table in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by
allowing the user to configure webfilter feature and content category.
Examples includes all options and need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify webfilter feature and content category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,56 +41,73 @@ requirements:
- fortiosapi>=0.9.8
options:
host:
description:
- FortiOS or FortiGate ip address.
required: true
description:
- FortiOS or FortiGate IP address.
type: str
required: false
username:
description:
- FortiOS or FortiGate username.
required: true
type: str
required: false
password:
description:
- FortiOS or FortiGate password.
type: str
default: ""
vdom:
description:
- Virtual domain, among those defined previously. A vdom is a
virtual instance of the FortiGate that can be configured and
used as a different unit.
type: str
default: root
https:
description:
- Indicates if the requests towards FortiGate must use HTTPS
protocol
- Indicates if the requests towards FortiGate must use HTTPS protocol.
type: bool
default: true
ssl_verify:
description:
- Ensures FortiGate certificate must be verified by a proper CA.
type: bool
default: false
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
webfilter_content:
description:
- Configure Web filter banned word table.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comment:
description:
- Optional comments.
type: str
entries:
description:
- Configure banned word entries.
type: list
suboptions:
action:
description:
- Block or exempt word when a match is found.
type: str
choices:
- block
- exempt
lang:
description:
- Language of banned word.
type: str
choices:
- western
- simch
@ -108,18 +122,22 @@ options:
description:
- Banned word.
required: true
pattern-type:
type: str
pattern_type:
description:
- "Banned word pattern type: wildcard pattern or Perl regular expression."
type: str
choices:
- wildcard
- regexp
score:
description:
- Score, to be applied every time the word appears on a web page (0 - 4294967295, default = 10).
- Score, to be applied every time the word appears on a web page (0 - 4294967295).
type: int
status:
description:
- Enable/disable banned word.
type: str
choices:
- enable
- disable
@ -127,9 +145,11 @@ options:
description:
- ID.
required: true
type: int
name:
description:
- Name of table.
type: str
'''
EXAMPLES = '''
@ -139,6 +159,7 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure Web filter banned word table.
fortios_webfilter_content:
@ -146,15 +167,16 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
webfilter_content:
state: "present"
comment: "Optional comments."
entries:
-
action: "block"
lang: "western"
name: "default_name_7"
pattern-type: "wildcard"
pattern_type: "wildcard"
score: "9"
status: "enable"
id: "11"
@ -221,14 +243,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
fos = None
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -236,7 +260,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_webfilter_content_data(json):
@ -251,48 +275,66 @@ def filter_webfilter_content_data(json):
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def webfilter_content(data, fos):
vdom = data['vdom']
state = data['state']
webfilter_content_data = data['webfilter_content']
filtered_data = filter_webfilter_content_data(webfilter_content_data)
if webfilter_content_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_webfilter_content_data(webfilter_content_data))
if state == "present":
return fos.set('webfilter',
'content',
data=filtered_data,
vdom=vdom)
elif webfilter_content_data['state'] == "absent":
elif state == "absent":
return fos.delete('webfilter',
'content',
mkey=filtered_data['id'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_webfilter(data, fos):
login(data)
methodlist = ['webfilter_content']
for method in methodlist:
if data[method]:
resp = eval(method)(data, fos)
break
if data['webfilter_content']:
resp = webfilter_content(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": "False"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"webfilter_content": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comment": {"required": False, "type": "str"},
"entries": {"required": False, "type": "list",
"options": {
@ -303,7 +345,7 @@ def main():
"japanese", "korean", "french",
"thai", "spanish", "cyrillic"]},
"name": {"required": True, "type": "str"},
"pattern-type": {"required": False, "type": "str",
"pattern_type": {"required": False, "type": "str",
"choices": ["wildcard", "regexp"]},
"score": {"required": False, "type": "int"},
"status": {"required": False, "type": "str",
@ -318,15 +360,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_webfilter(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_webfilter(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_webfilter(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -1,6 +1,6 @@
#!/usr/bin/python
from __future__ import (absolute_import, division, print_function)
# Copyright 2018 Fortinet, Inc.
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -14,9 +14,6 @@ from __future__ import (absolute_import, division, print_function)
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# the lib use python logging can get it if the following is set in your
# Ansible config.
__metaclass__ = type
@ -27,12 +24,12 @@ ANSIBLE_METADATA = {'status': ['preview'],
DOCUMENTATION = '''
---
module: fortios_webfilter_content_header
short_description: Configure content types used by Web filter.
short_description: Configure content types used by Web filter in Fortinet's FortiOS and FortiGate.
description:
- This module is able to configure a FortiGate or FortiOS by
allowing the user to configure webfilter feature and content_header category.
Examples includes all options and need to be adjusted to datasources before usage.
Tested with FOS v6.0.2
- This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
user to set and modify webfilter feature and content_header category.
Examples include all parameters and values need to be adjusted to datasources before usage.
Tested with FOS v6.0.5
version_added: "2.8"
author:
- Miguel Angel Munoz (@mamunozgonzalez)
@ -44,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: false
default: true
version_added: 2.9
state:
description:
- Indicates whether to create or remove the object.
type: str
required: true
choices:
- present
- absent
version_added: 2.9
webfilter_content_header:
description:
- Configure content types used by Web filter.
default: null
type: dict
suboptions:
state:
description:
- Indicates whether to create or remove the object
choices:
- present
- absent
comment:
description:
- Optional comments.
type: str
entries:
description:
- Configure content types used by web filter.
type: list
suboptions:
action:
description:
- Action to take for this content type.
type: str
choices:
- block
- allow
@ -95,17 +108,21 @@ options:
category:
description:
- Categories that this content type applies to.
type: str
pattern:
description:
- Content type (regular expression).
required: true
type: str
id:
description:
- ID.
required: true
type: int
name:
description:
- Name of table.
type: str
'''
EXAMPLES = '''
@ -115,15 +132,17 @@ EXAMPLES = '''
username: "admin"
password: ""
vdom: "root"
ssl_verify: "False"
tasks:
- name: Configure content types used by Web filter.
fortios_webfilter_content_header:
host: "{{ host }}"
host: "{{ host }}"
username: "{{ username }}"
password: "{{ password }}"
vdom: "{{ vdom }}"
vdom: "{{ vdom }}"
https: "False"
state: "present"
webfilter_content_header:
state: "present"
comment: "Optional comments."
entries:
-
@ -154,7 +173,7 @@ mkey:
description: Master key (id) used in the last call to FortiGate
returned: success
type: str
sample: "key1"
sample: "id"
name:
description: Name of the table used to fulfill the request
returned: always
@ -194,14 +213,16 @@ version:
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
fos = None
def login(data):
def login(data, fos):
host = data['host']
username = data['username']
password = data['password']
ssl_verify = data['ssl_verify']
fos.debug('on')
if 'https' in data and not data['https']:
@ -209,7 +230,7 @@ def login(data):
else:
fos.https('on')
fos.login(host, username, password)
fos.login(host, username, password, verify=ssl_verify)
def filter_webfilter_content_header_data(json):
@ -218,55 +239,72 @@ def filter_webfilter_content_header_data(json):
dictionary = {}
for attribute in option_list:
if attribute in json:
if attribute in json and json[attribute] is not None:
dictionary[attribute] = json[attribute]
return dictionary
def underscore_to_hyphen(data):
if isinstance(data, list):
for elem in data:
elem = underscore_to_hyphen(elem)
elif isinstance(data, dict):
new_data = {}
for k, v in data.items():
new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
data = new_data
return data
def webfilter_content_header(data, fos):
vdom = data['vdom']
state = data['state']
webfilter_content_header_data = data['webfilter_content_header']
filtered_data = filter_webfilter_content_header_data(
webfilter_content_header_data)
if webfilter_content_header_data['state'] == "present":
filtered_data = underscore_to_hyphen(filter_webfilter_content_header_data(webfilter_content_header_data))
if state == "present":
return fos.set('webfilter',
'content-header',
data=filtered_data,
vdom=vdom)
elif webfilter_content_header_data['state'] == "absent":
elif state == "absent":
return fos.delete('webfilter',
'content-header',
mkey=filtered_data['id'],
vdom=vdom)
def is_successful_status(status):
return status['status'] == "success" or \
status['http_method'] == "DELETE" and status['http_status'] == 404
def fortios_webfilter(data, fos):
login(data)
methodlist = ['webfilter_content_header']
for method in methodlist:
if data[method]:
resp = eval(method)(data, fos)
break
if data['webfilter_content_header']:
resp = webfilter_content_header(data, fos)
fos.logout()
return not resp['status'] == "success", resp['status'] == "success", resp
return not is_successful_status(resp), \
resp['status'] == "success", \
resp
def main():
fields = {
"host": {"required": True, "type": "str"},
"username": {"required": True, "type": "str"},
"password": {"required": False, "type": "str", "no_log": True},
"host": {"required": False, "type": "str"},
"username": {"required": False, "type": "str"},
"password": {"required": False, "type": "str", "default": "", "no_log": True},
"vdom": {"required": False, "type": "str", "default": "root"},
"https": {"required": False, "type": "bool", "default": "False"},
"https": {"required": False, "type": "bool", "default": True},
"ssl_verify": {"required": False, "type": "bool", "default": True},
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"webfilter_content_header": {
"required": False, "type": "dict",
"required": False, "type": "dict", "default": None,
"options": {
"state": {"required": True, "type": "str",
"choices": ["present", "absent"]},
"comment": {"required": False, "type": "str"},
"entries": {"required": False, "type": "list",
"options": {
@ -284,15 +322,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_webfilter(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_webfilter(module.params, fos)
login(module.params, fos)
is_error, has_changed, result = fortios_webfilter(module.params, fos)
fos.logout()
if not is_error:
module.exit_json(changed=has_changed, meta=result)

@ -3697,43 +3697,9 @@ lib/ansible/modules/network/fortios/fortios_switch_controller_lldp_profile.py va
lib/ansible/modules/network/fortios/fortios_switch_controller_managed_switch.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_system_dhcp_server.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_system_global.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_user_adgrp.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_user_device.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_user_radius.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_user_radius.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_user_tacacsplus.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_user_tacacsplus.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_voip_profile.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_voip_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_voip_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_concentrator.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_concentrator.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_forticlient.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey_interface.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey_interface.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_manualkey_interface.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase1.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase1.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase1_interface.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase1_interface.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase2.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase2.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase2_interface.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ipsec_phase2_interface.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ssl_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ssl_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_vpn_ssl_web_portal.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_vpn_ssl_web_portal.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_waf_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_waf_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_wanopt_profile.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_wanopt_profile.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_wanopt_settings.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_wanopt_settings.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_web_proxy_explicit.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_web_proxy_explicit.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_web_proxy_global.py validate-modules:E336
@ -3744,9 +3710,6 @@ lib/ansible/modules/network/fortios/fortios_webfilter.py validate-modules:E326
lib/ansible/modules/network/fortios/fortios_webfilter.py validate-modules:E328
lib/ansible/modules/network/fortios/fortios_webfilter.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_webfilter.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_webfilter_content.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_webfilter_content.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_webfilter_content_header.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_webfilter_fortiguard.py validate-modules:E336
lib/ansible/modules/network/fortios/fortios_webfilter_fortiguard.py validate-modules:E337
lib/ansible/modules/network/fortios/fortios_webfilter_ftgd_local_cat.py validate-modules:E337

@ -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_user_adgrp
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_user_adgrp.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_user_adgrp_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',
'user_adgrp': {
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'server-name': 'test_value_4'
}
set_method_mock.assert_called_with('user', 'adgrp', 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_user_adgrp_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',
'user_adgrp': {
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'server-name': 'test_value_4'
}
set_method_mock.assert_called_with('user', 'adgrp', 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_user_adgrp_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',
'user_adgrp': {
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'adgrp', 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_user_adgrp_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',
'user_adgrp': {
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'adgrp', 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_user_adgrp_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',
'user_adgrp': {
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'server-name': 'test_value_4'
}
set_method_mock.assert_called_with('user', 'adgrp', 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_user_adgrp_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',
'user_adgrp': {
'random_attribute_not_valid': 'tag',
'name': 'default_name_3',
'server_name': 'test_value_4'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_adgrp.fortios_user(input_data, fos_instance)
expected_data = {
'name': 'default_name_3',
'server-name': 'test_value_4'
}
set_method_mock.assert_called_with('user', 'adgrp', 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

@ -17,7 +17,10 @@
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:
@ -45,30 +48,28 @@ def test_user_device_creation(mocker):
'username': 'admin',
'state': 'present',
'user_device': {
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
expected_data = {
'alias': 'myuser',
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'mac': '00:01:04:03:ab:c3:32',
'mac': 'test_value_7',
'master-device': 'test_value_8',
'type': 'unknown',
'user': 'myuser',
'tagging': 'tag',
'avatar': 'avatar1',
'master-device': 'master'
'user': 'test_value_10'
}
set_method_mock.assert_called_with('user', 'device', data=expected_data, vdom='root')
@ -89,30 +90,28 @@ def test_user_device_creation_fails(mocker):
'username': 'admin',
'state': 'present',
'user_device': {
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
expected_data = {
'alias': 'myuser',
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'mac': '00:01:04:03:ab:c3:32',
'mac': 'test_value_7',
'master-device': 'test_value_8',
'type': 'unknown',
'user': 'myuser',
'tagging': 'tag',
'avatar': 'avatar1',
'master-device': 'master'
'user': 'test_value_10'
}
set_method_mock.assert_called_with('user', 'device', data=expected_data, vdom='root')
@ -123,7 +122,7 @@ def test_user_device_creation_fails(mocker):
assert response['http_status'] == 500
def test_users_device_removal(mocker):
def test_user_device_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}
@ -133,21 +132,20 @@ def test_users_device_removal(mocker):
'username': 'admin',
'state': 'absent',
'user_device': {
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'device', mkey='myuser', vdom='root')
delete_method_mock.assert_called_with('user', 'device', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
@ -165,21 +163,20 @@ def test_user_device_deletion_fails(mocker):
'username': 'admin',
'state': 'absent',
'user_device': {
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'device', mkey='myuser', vdom='root')
delete_method_mock.assert_called_with('user', 'device', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
@ -197,30 +194,28 @@ def test_user_device_idempotent(mocker):
'username': 'admin',
'state': 'present',
'user_device': {
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
expected_data = {
'alias': 'myuser',
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'mac': '00:01:04:03:ab:c3:32',
'mac': 'test_value_7',
'master-device': 'test_value_8',
'type': 'unknown',
'user': 'myuser',
'tagging': 'tag',
'avatar': 'avatar1',
'master-device': 'master'
'user': 'test_value_10'
}
set_method_mock.assert_called_with('user', 'device', data=expected_data, vdom='root')
@ -231,49 +226,6 @@ def test_user_device_idempotent(mocker):
assert response['http_status'] == 404
def test_user_device_filter_null_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',
'user_device': {
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'type': 'unknown',
'tagging': 'tag',
'avatar': None
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
expected_data = {
'alias': 'myuser',
'category': 'none',
'comment': 'Comment.',
'mac': '00:01:04:03:ab:c3:32',
'type': 'unknown',
'user': 'myuser',
'tagging': 'tag',
'master-device': 'master'
}
set_method_mock.assert_called_with('user', 'device', 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_user_device_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
@ -284,31 +236,29 @@ def test_user_device_filter_foreign_attributes(mocker):
'username': 'admin',
'state': 'present',
'user_device': {
'random_attribute_not_valid': 'tag',
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'master_device': 'master',
'alias': 'myuser',
'mac': '00:01:04:03:ab:c3:32',
'user': 'myuser',
'mac': 'test_value_7',
'master_device': 'test_value_8',
'type': 'unknown',
'tagging': 'tag',
'avatar': 'avatar1',
'random_attribute_not_valid': 'tag'
'user': 'test_value_10'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_device.fortios_user(input_data, fos_instance)
expected_data = {
'alias': 'myuser',
'alias': 'test_value_3',
'avatar': 'test_value_4',
'category': 'none',
'comment': 'Comment.',
'mac': '00:01:04:03:ab:c3:32',
'mac': 'test_value_7',
'master-device': 'test_value_8',
'type': 'unknown',
'user': 'myuser',
'tagging': 'tag',
'avatar': 'avatar1',
'master-device': 'master'
'user': 'test_value_10'
}
set_method_mock.assert_called_with('user', 'device', data=expected_data, vdom='root')

@ -0,0 +1,539 @@
# 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_user_radius
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_user_radius.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_user_radius_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',
'user_radius': {'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
expected_data = {'acct-all-servers': 'enable',
'acct-interim-interval': '4',
'all-usergroup': 'disable',
'auth-type': 'auto',
'h3c-compatibility': 'enable',
'name': 'default_name_8',
'nas-ip': 'test_value_9',
'password-encoding': 'auto',
'password-renewal': 'enable',
'radius-coa': 'enable',
'radius-port': '13',
'rsso': 'enable',
'rsso-context-timeout': '15',
'rsso-endpoint-attribute': 'User-Name',
'rsso-endpoint-block-attribute': 'User-Name',
'rsso-ep-one-ip-only': 'enable',
'rsso-flush-ip-session': 'enable',
'rsso-log-flags': 'protocol-error',
'rsso-log-period': '21',
'rsso-radius-response': 'enable',
'rsso-radius-server-port': '23',
'rsso-secret': 'test_value_24',
'rsso-validate-request-secret': 'enable',
'secondary-secret': 'test_value_26',
'secondary-server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source-ip': '84.230.14.30',
'sso-attribute': 'User-Name',
'sso-attribute-key': 'test_value_32',
'sso-attribute-value-override': 'enable',
'tertiary-secret': 'test_value_34',
'tertiary-server': 'test_value_35',
'timeout': '36',
'use-management-vdom': 'enable',
'username-case-sensitive': 'enable'
}
set_method_mock.assert_called_with('user', 'radius', 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_user_radius_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',
'user_radius': {'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
expected_data = {'acct-all-servers': 'enable',
'acct-interim-interval': '4',
'all-usergroup': 'disable',
'auth-type': 'auto',
'h3c-compatibility': 'enable',
'name': 'default_name_8',
'nas-ip': 'test_value_9',
'password-encoding': 'auto',
'password-renewal': 'enable',
'radius-coa': 'enable',
'radius-port': '13',
'rsso': 'enable',
'rsso-context-timeout': '15',
'rsso-endpoint-attribute': 'User-Name',
'rsso-endpoint-block-attribute': 'User-Name',
'rsso-ep-one-ip-only': 'enable',
'rsso-flush-ip-session': 'enable',
'rsso-log-flags': 'protocol-error',
'rsso-log-period': '21',
'rsso-radius-response': 'enable',
'rsso-radius-server-port': '23',
'rsso-secret': 'test_value_24',
'rsso-validate-request-secret': 'enable',
'secondary-secret': 'test_value_26',
'secondary-server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source-ip': '84.230.14.30',
'sso-attribute': 'User-Name',
'sso-attribute-key': 'test_value_32',
'sso-attribute-value-override': 'enable',
'tertiary-secret': 'test_value_34',
'tertiary-server': 'test_value_35',
'timeout': '36',
'use-management-vdom': 'enable',
'username-case-sensitive': 'enable'
}
set_method_mock.assert_called_with('user', 'radius', 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_user_radius_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',
'user_radius': {'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'radius', 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_user_radius_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',
'user_radius': {'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'radius', 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_user_radius_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',
'user_radius': {'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
expected_data = {'acct-all-servers': 'enable',
'acct-interim-interval': '4',
'all-usergroup': 'disable',
'auth-type': 'auto',
'h3c-compatibility': 'enable',
'name': 'default_name_8',
'nas-ip': 'test_value_9',
'password-encoding': 'auto',
'password-renewal': 'enable',
'radius-coa': 'enable',
'radius-port': '13',
'rsso': 'enable',
'rsso-context-timeout': '15',
'rsso-endpoint-attribute': 'User-Name',
'rsso-endpoint-block-attribute': 'User-Name',
'rsso-ep-one-ip-only': 'enable',
'rsso-flush-ip-session': 'enable',
'rsso-log-flags': 'protocol-error',
'rsso-log-period': '21',
'rsso-radius-response': 'enable',
'rsso-radius-server-port': '23',
'rsso-secret': 'test_value_24',
'rsso-validate-request-secret': 'enable',
'secondary-secret': 'test_value_26',
'secondary-server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source-ip': '84.230.14.30',
'sso-attribute': 'User-Name',
'sso-attribute-key': 'test_value_32',
'sso-attribute-value-override': 'enable',
'tertiary-secret': 'test_value_34',
'tertiary-server': 'test_value_35',
'timeout': '36',
'use-management-vdom': 'enable',
'username-case-sensitive': 'enable'
}
set_method_mock.assert_called_with('user', 'radius', 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_user_radius_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',
'user_radius': {
'random_attribute_not_valid': 'tag', 'acct_all_servers': 'enable',
'acct_interim_interval': '4',
'all_usergroup': 'disable',
'auth_type': 'auto',
'h3c_compatibility': 'enable',
'name': 'default_name_8',
'nas_ip': 'test_value_9',
'password_encoding': 'auto',
'password_renewal': 'enable',
'radius_coa': 'enable',
'radius_port': '13',
'rsso': 'enable',
'rsso_context_timeout': '15',
'rsso_endpoint_attribute': 'User-Name',
'rsso_endpoint_block_attribute': 'User-Name',
'rsso_ep_one_ip_only': 'enable',
'rsso_flush_ip_session': 'enable',
'rsso_log_flags': 'protocol-error',
'rsso_log_period': '21',
'rsso_radius_response': 'enable',
'rsso_radius_server_port': '23',
'rsso_secret': 'test_value_24',
'rsso_validate_request_secret': 'enable',
'secondary_secret': 'test_value_26',
'secondary_server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source_ip': '84.230.14.30',
'sso_attribute': 'User-Name',
'sso_attribute_key': 'test_value_32',
'sso_attribute_value_override': 'enable',
'tertiary_secret': 'test_value_34',
'tertiary_server': 'test_value_35',
'timeout': '36',
'use_management_vdom': 'enable',
'username_case_sensitive': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_radius.fortios_user(input_data, fos_instance)
expected_data = {'acct-all-servers': 'enable',
'acct-interim-interval': '4',
'all-usergroup': 'disable',
'auth-type': 'auto',
'h3c-compatibility': 'enable',
'name': 'default_name_8',
'nas-ip': 'test_value_9',
'password-encoding': 'auto',
'password-renewal': 'enable',
'radius-coa': 'enable',
'radius-port': '13',
'rsso': 'enable',
'rsso-context-timeout': '15',
'rsso-endpoint-attribute': 'User-Name',
'rsso-endpoint-block-attribute': 'User-Name',
'rsso-ep-one-ip-only': 'enable',
'rsso-flush-ip-session': 'enable',
'rsso-log-flags': 'protocol-error',
'rsso-log-period': '21',
'rsso-radius-response': 'enable',
'rsso-radius-server-port': '23',
'rsso-secret': 'test_value_24',
'rsso-validate-request-secret': 'enable',
'secondary-secret': 'test_value_26',
'secondary-server': 'test_value_27',
'secret': 'test_value_28',
'server': '192.168.100.29',
'source-ip': '84.230.14.30',
'sso-attribute': 'User-Name',
'sso-attribute-key': 'test_value_32',
'sso-attribute-value-override': 'enable',
'tertiary-secret': 'test_value_34',
'tertiary-server': 'test_value_35',
'timeout': '36',
'use-management-vdom': 'enable',
'username-case-sensitive': 'enable'
}
set_method_mock.assert_called_with('user', 'radius', 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,299 @@
# 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_user_tacacsplus
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_user_tacacsplus.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_user_tacacsplus_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',
'user_tacacsplus': {
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
expected_data = {
'authen-type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary-key': 'test_value_8',
'secondary-server': 'test_value_9',
'server': '192.168.100.10',
'source-ip': '84.230.14.11',
'tertiary-key': 'test_value_12',
'tertiary-server': 'test_value_13'
}
set_method_mock.assert_called_with('user', 'tacacs+', 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_user_tacacsplus_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',
'user_tacacsplus': {
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
expected_data = {
'authen-type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary-key': 'test_value_8',
'secondary-server': 'test_value_9',
'server': '192.168.100.10',
'source-ip': '84.230.14.11',
'tertiary-key': 'test_value_12',
'tertiary-server': 'test_value_13'
}
set_method_mock.assert_called_with('user', 'tacacs+', 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_user_tacacsplus_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',
'user_tacacsplus': {
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'tacacs+', 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_user_tacacsplus_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',
'user_tacacsplus': {
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
delete_method_mock.assert_called_with('user', 'tacacs+', 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_user_tacacsplus_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',
'user_tacacsplus': {
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
expected_data = {
'authen-type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary-key': 'test_value_8',
'secondary-server': 'test_value_9',
'server': '192.168.100.10',
'source-ip': '84.230.14.11',
'tertiary-key': 'test_value_12',
'tertiary-server': 'test_value_13'
}
set_method_mock.assert_called_with('user', 'tacacs+', 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_user_tacacsplus_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',
'user_tacacsplus': {
'random_attribute_not_valid': 'tag',
'authen_type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary_key': 'test_value_8',
'secondary_server': 'test_value_9',
'server': '192.168.100.10',
'source_ip': '84.230.14.11',
'tertiary_key': 'test_value_12',
'tertiary_server': 'test_value_13'
},
'vdom': 'root'}
is_error, changed, response = fortios_user_tacacsplus.fortios_user(input_data, fos_instance)
expected_data = {
'authen-type': 'mschap',
'authorization': 'enable',
'key': 'test_value_5',
'name': 'default_name_6',
'port': '7',
'secondary-key': 'test_value_8',
'secondary-server': 'test_value_9',
'server': '192.168.100.10',
'source-ip': '84.230.14.11',
'tertiary-key': 'test_value_12',
'tertiary-server': 'test_value_13'
}
set_method_mock.assert_called_with('user', 'tacacs+', 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_voip_profile
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_voip_profile.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_voip_profile_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'voip_profile': {
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('voip', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_voip_profile_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'voip_profile': {
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('voip', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_voip_profile_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'voip_profile': {
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
delete_method_mock.assert_called_with('voip', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_voip_profile_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'voip_profile': {
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
delete_method_mock.assert_called_with('voip', 'profile', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_voip_profile_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'voip_profile': {
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('voip', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_voip_profile_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'voip_profile': {
'random_attribute_not_valid': 'tag',
'comment': 'Comment.',
'name': 'default_name_4',
},
'vdom': 'root'}
is_error, changed, response = fortios_voip_profile.fortios_voip(input_data, fos_instance)
expected_data = {
'comment': 'Comment.',
'name': 'default_name_4',
}
set_method_mock.assert_called_with('voip', 'profile', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,199 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_vpn_ipsec_concentrator
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_vpn_ipsec_concentrator.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {'name': 'default_name_3',
'src-check': 'disable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'concentrator', 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_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {'name': 'default_name_3',
'src-check': 'disable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'concentrator', 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_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'concentrator', 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_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'concentrator', 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_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {'name': 'default_name_3',
'src-check': 'disable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'concentrator', 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_vpn_ipsec_concentrator_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',
'vpn_ipsec_concentrator': {
'random_attribute_not_valid': 'tag', 'name': 'default_name_3',
'src_check': 'disable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_concentrator.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {'name': 'default_name_3',
'src-check': 'disable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'concentrator', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,229 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_vpn_ipsec_forticlient
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_vpn_ipsec_forticlient.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
}
set_method_mock.assert_called_with('vpn.ipsec', 'forticlient', 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_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
}
set_method_mock.assert_called_with('vpn.ipsec', 'forticlient', 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_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'forticlient', 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_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'forticlient', 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_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
}
set_method_mock.assert_called_with('vpn.ipsec', 'forticlient', 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_vpn_ipsec_forticlient_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',
'vpn_ipsec_forticlient': {
'random_attribute_not_valid': 'tag',
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_forticlient.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'phase2name': 'test_value_3',
'realm': 'test_value_4',
'status': 'enable',
'usergroupname': 'test_value_6'
}
set_method_mock.assert_called_with('vpn.ipsec', 'forticlient', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,289 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_vpn_ipsec_manualkey
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_vpn_ipsec_manualkey.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local-gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote-gw': 'test_value_11',
'remotespi': 'test_value_12'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local-gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote-gw': 'test_value_11',
'remotespi': 'test_value_12'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local-gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote-gw': 'test_value_11',
'remotespi': 'test_value_12'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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_vpn_ipsec_manualkey_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',
'vpn_ipsec_manualkey': {
'random_attribute_not_valid': 'tag',
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local_gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote_gw': 'test_value_11',
'remotespi': 'test_value_12'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'authentication': 'null',
'authkey': 'test_value_4',
'enckey': 'test_value_5',
'encryption': 'null',
'interface': 'test_value_7',
'local-gw': 'test_value_8',
'localspi': 'test_value_9',
'name': 'default_name_10',
'remote-gw': 'test_value_11',
'remotespi': 'test_value_12'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey', 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,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_vpn_ipsec_manualkey_interface
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_vpn_ipsec_manualkey_interface.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_manualkey_interface_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_manualkey_interface': {
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'addr-type': '4',
'auth-alg': 'null',
'auth-key': 'test_value_5',
'enc-alg': 'null',
'enc-key': 'test_value_7',
'interface': 'test_value_8',
'ip-version': '4',
'local-gw': 'test_value_10',
'local-gw6': 'test_value_11',
'local-spi': 'test_value_12',
'name': 'default_name_13',
'remote-gw': 'test_value_14',
'remote-gw6': 'test_value_15',
'remote-spi': 'test_value_16'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_vpn_ipsec_manualkey_interface_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_manualkey_interface': {
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'addr-type': '4',
'auth-alg': 'null',
'auth-key': 'test_value_5',
'enc-alg': 'null',
'enc-key': 'test_value_7',
'interface': 'test_value_8',
'ip-version': '4',
'local-gw': 'test_value_10',
'local-gw6': 'test_value_11',
'local-spi': 'test_value_12',
'name': 'default_name_13',
'remote-gw': 'test_value_14',
'remote-gw6': 'test_value_15',
'remote-spi': 'test_value_16'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_vpn_ipsec_manualkey_interface_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'vpn_ipsec_manualkey_interface': {
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_vpn_ipsec_manualkey_interface_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'vpn_ipsec_manualkey_interface': {
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_vpn_ipsec_manualkey_interface_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_manualkey_interface': {
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'addr-type': '4',
'auth-alg': 'null',
'auth-key': 'test_value_5',
'enc-alg': 'null',
'enc-key': 'test_value_7',
'interface': 'test_value_8',
'ip-version': '4',
'local-gw': 'test_value_10',
'local-gw6': 'test_value_11',
'local-spi': 'test_value_12',
'name': 'default_name_13',
'remote-gw': 'test_value_14',
'remote-gw6': 'test_value_15',
'remote-spi': 'test_value_16'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_vpn_ipsec_manualkey_interface_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_manualkey_interface': {
'random_attribute_not_valid': 'tag',
'addr_type': '4',
'auth_alg': 'null',
'auth_key': 'test_value_5',
'enc_alg': 'null',
'enc_key': 'test_value_7',
'interface': 'test_value_8',
'ip_version': '4',
'local_gw': 'test_value_10',
'local_gw6': 'test_value_11',
'local_spi': 'test_value_12',
'name': 'default_name_13',
'remote_gw': 'test_value_14',
'remote_gw6': 'test_value_15',
'remote_spi': 'test_value_16'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_manualkey_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'addr-type': '4',
'auth-alg': 'null',
'auth-key': 'test_value_5',
'enc-alg': 'null',
'enc-key': 'test_value_7',
'interface': 'test_value_8',
'ip-version': '4',
'local-gw': 'test_value_10',
'local-gw6': 'test_value_11',
'local-spi': 'test_value_12',
'name': 'default_name_13',
'remote-gw': 'test_value_14',
'remote-gw6': 'test_value_15',
'remote-spi': 'test_value_16'
}
set_method_mock.assert_called_with('vpn.ipsec', 'manualkey-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,599 @@
# 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_vpn_ipsec_phase2
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_vpn_ipsec_phase2.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_5',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_9',
'dst-end-ip6': 'test_value_10',
'dst-name': 'test_value_11',
'dst-name6': 'test_value_12',
'dst-port': '13',
'dst-start-ip': 'test_value_14',
'dst-start-ip6': 'test_value_15',
'dst-subnet': 'test_value_16',
'dst-subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route-overlap': 'use-old',
'selector-match': 'exact',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_34',
'src-end-ip6': 'test_value_35',
'src-name': 'test_value_36',
'src-name6': 'test_value_37',
'src-port': '38',
'src-start-ip': 'test_value_39',
'src-start-ip6': 'test_value_40',
'src-subnet': 'test_value_41',
'src-subnet6': 'test_value_42',
'use-natip': 'enable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_5',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_9',
'dst-end-ip6': 'test_value_10',
'dst-name': 'test_value_11',
'dst-name6': 'test_value_12',
'dst-port': '13',
'dst-start-ip': 'test_value_14',
'dst-start-ip6': 'test_value_15',
'dst-subnet': 'test_value_16',
'dst-subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route-overlap': 'use-old',
'selector-match': 'exact',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_34',
'src-end-ip6': 'test_value_35',
'src-name': 'test_value_36',
'src-name6': 'test_value_37',
'src-port': '38',
'src-start-ip': 'test_value_39',
'src-start-ip6': 'test_value_40',
'src-subnet': 'test_value_41',
'src-subnet6': 'test_value_42',
'use-natip': 'enable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_5',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_9',
'dst-end-ip6': 'test_value_10',
'dst-name': 'test_value_11',
'dst-name6': 'test_value_12',
'dst-port': '13',
'dst-start-ip': 'test_value_14',
'dst-start-ip6': 'test_value_15',
'dst-subnet': 'test_value_16',
'dst-subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route-overlap': 'use-old',
'selector-match': 'exact',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_34',
'src-end-ip6': 'test_value_35',
'src-name': 'test_value_36',
'src-name6': 'test_value_37',
'src-port': '38',
'src-start-ip': 'test_value_39',
'src-start-ip6': 'test_value_40',
'src-subnet': 'test_value_41',
'src-subnet6': 'test_value_42',
'use-natip': 'enable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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_vpn_ipsec_phase2_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',
'vpn_ipsec_phase2': {
'random_attribute_not_valid': 'tag',
'add_route': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_5',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_9',
'dst_end_ip6': 'test_value_10',
'dst_name': 'test_value_11',
'dst_name6': 'test_value_12',
'dst_port': '13',
'dst_start_ip': 'test_value_14',
'dst_start_ip6': 'test_value_15',
'dst_subnet': 'test_value_16',
'dst_subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route_overlap': 'use-old',
'selector_match': 'exact',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_34',
'src_end_ip6': 'test_value_35',
'src_name': 'test_value_36',
'src_name6': 'test_value_37',
'src_port': '38',
'src_start_ip': 'test_value_39',
'src_start_ip6': 'test_value_40',
'src_subnet': 'test_value_41',
'src_subnet6': 'test_value_42',
'use_natip': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_5',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_9',
'dst-end-ip6': 'test_value_10',
'dst-name': 'test_value_11',
'dst-name6': 'test_value_12',
'dst-port': '13',
'dst-start-ip': 'test_value_14',
'dst-start-ip6': 'test_value_15',
'dst-subnet': 'test_value_16',
'dst-subnet6': 'test_value_17',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '21',
'keylifeseconds': '22',
'l2tp': 'enable',
'name': 'default_name_24',
'pfs': 'enable',
'phase1name': 'test_value_26',
'proposal': 'null-md5',
'protocol': '28',
'replay': 'enable',
'route-overlap': 'use-old',
'selector-match': 'exact',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_34',
'src-end-ip6': 'test_value_35',
'src-name': 'test_value_36',
'src-name6': 'test_value_37',
'src-port': '38',
'src-start-ip': 'test_value_39',
'src-start-ip6': 'test_value_40',
'src-subnet': 'test_value_41',
'src-subnet6': 'test_value_42',
'use-natip': 'enable'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2', 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,599 @@
# 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_vpn_ipsec_phase2_interface
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_vpn_ipsec_phase2_interface.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ipsec_phase2_interface_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_phase2_interface': {
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-discovery-forwarder': 'phase1',
'auto-discovery-sender': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_7',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_11',
'dst-end-ip6': 'test_value_12',
'dst-name': 'test_value_13',
'dst-name6': 'test_value_14',
'dst-port': '15',
'dst-start-ip': 'test_value_16',
'dst-start-ip6': 'test_value_17',
'dst-subnet': 'test_value_18',
'dst-subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route-overlap': 'use-old',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_35',
'src-end-ip6': 'test_value_36',
'src-name': 'test_value_37',
'src-name6': 'test_value_38',
'src-port': '39',
'src-start-ip': 'test_value_40',
'src-start-ip6': 'test_value_41',
'src-subnet': 'test_value_42',
'src-subnet6': 'test_value_43'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_vpn_ipsec_phase2_interface_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_phase2_interface': {
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-discovery-forwarder': 'phase1',
'auto-discovery-sender': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_7',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_11',
'dst-end-ip6': 'test_value_12',
'dst-name': 'test_value_13',
'dst-name6': 'test_value_14',
'dst-port': '15',
'dst-start-ip': 'test_value_16',
'dst-start-ip6': 'test_value_17',
'dst-subnet': 'test_value_18',
'dst-subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route-overlap': 'use-old',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_35',
'src-end-ip6': 'test_value_36',
'src-name': 'test_value_37',
'src-name6': 'test_value_38',
'src-port': '39',
'src-start-ip': 'test_value_40',
'src-start-ip6': 'test_value_41',
'src-subnet': 'test_value_42',
'src-subnet6': 'test_value_43'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_vpn_ipsec_phase2_interface_removal(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'vpn_ipsec_phase2_interface': {
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_vpn_ipsec_phase2_interface_deletion_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
delete_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
delete_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.delete', return_value=delete_method_result)
input_data = {
'username': 'admin',
'state': 'absent',
'vpn_ipsec_phase2_interface': {
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', mkey=ANY, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_vpn_ipsec_phase2_interface_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_phase2_interface': {
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-discovery-forwarder': 'phase1',
'auto-discovery-sender': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_7',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_11',
'dst-end-ip6': 'test_value_12',
'dst-name': 'test_value_13',
'dst-name6': 'test_value_14',
'dst-port': '15',
'dst-start-ip': 'test_value_16',
'dst-start-ip6': 'test_value_17',
'dst-subnet': 'test_value_18',
'dst-subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route-overlap': 'use-old',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_35',
'src-end-ip6': 'test_value_36',
'src-name': 'test_value_37',
'src-name6': 'test_value_38',
'src-port': '39',
'src-start-ip': 'test_value_40',
'src-start-ip6': 'test_value_41',
'src-subnet': 'test_value_42',
'src-subnet6': 'test_value_43'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_vpn_ipsec_phase2_interface_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ipsec_phase2_interface': {
'random_attribute_not_valid': 'tag',
'add_route': 'phase1',
'auto_discovery_forwarder': 'phase1',
'auto_discovery_sender': 'phase1',
'auto_negotiate': 'enable',
'comments': 'test_value_7',
'dhcp_ipsec': 'enable',
'dhgrp': '1',
'dst_addr_type': 'subnet',
'dst_end_ip': 'test_value_11',
'dst_end_ip6': 'test_value_12',
'dst_name': 'test_value_13',
'dst_name6': 'test_value_14',
'dst_port': '15',
'dst_start_ip': 'test_value_16',
'dst_start_ip6': 'test_value_17',
'dst_subnet': 'test_value_18',
'dst_subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife_type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route_overlap': 'use-old',
'single_source': 'enable',
'src_addr_type': 'subnet',
'src_end_ip': 'test_value_35',
'src_end_ip6': 'test_value_36',
'src_name': 'test_value_37',
'src_name6': 'test_value_38',
'src_port': '39',
'src_start_ip': 'test_value_40',
'src_start_ip6': 'test_value_41',
'src_subnet': 'test_value_42',
'src_subnet6': 'test_value_43'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ipsec_phase2_interface.fortios_vpn_ipsec(input_data, fos_instance)
expected_data = {
'add-route': 'phase1',
'auto-discovery-forwarder': 'phase1',
'auto-discovery-sender': 'phase1',
'auto-negotiate': 'enable',
'comments': 'test_value_7',
'dhcp-ipsec': 'enable',
'dhgrp': '1',
'dst-addr-type': 'subnet',
'dst-end-ip': 'test_value_11',
'dst-end-ip6': 'test_value_12',
'dst-name': 'test_value_13',
'dst-name6': 'test_value_14',
'dst-port': '15',
'dst-start-ip': 'test_value_16',
'dst-start-ip6': 'test_value_17',
'dst-subnet': 'test_value_18',
'dst-subnet6': 'test_value_19',
'encapsulation': 'tunnel-mode',
'keepalive': 'enable',
'keylife-type': 'seconds',
'keylifekbs': '23',
'keylifeseconds': '24',
'l2tp': 'enable',
'name': 'default_name_26',
'pfs': 'enable',
'phase1name': 'test_value_28',
'proposal': 'null-md5',
'protocol': '30',
'replay': 'enable',
'route-overlap': 'use-old',
'single-source': 'enable',
'src-addr-type': 'subnet',
'src-end-ip': 'test_value_35',
'src-end-ip6': 'test_value_36',
'src-name': 'test_value_37',
'src-name6': 'test_value_38',
'src-port': '39',
'src-start-ip': 'test_value_40',
'src-start-ip6': 'test_value_41',
'src-subnet': 'test_value_42',
'src-subnet6': 'test_value_43'
}
set_method_mock.assert_called_with('vpn.ipsec', 'phase2-interface', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,495 @@
# 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_vpn_ssl_settings
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_vpn_ssl_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ssl_settings_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ssl_settings': {
'auth_timeout': '3',
'auto_tunnel_static_route': 'enable',
'banned_cipher': 'RSA',
'check_referer': 'enable',
'default_portal': 'test_value_7',
'deflate_compression_level': '8',
'deflate_min_data_size': '9',
'dns_server1': 'test_value_10',
'dns_server2': 'test_value_11',
'dns_suffix': 'test_value_12',
'dtls_hello_timeout': '13',
'dtls_tunnel': 'enable',
'force_two_factor_auth': 'enable',
'header_x_forwarded_for': 'pass',
'http_compression': 'enable',
'http_only_cookie': 'enable',
'http_request_body_timeout': '19',
'http_request_header_timeout': '20',
'https_redirect': 'enable',
'idle_timeout': '22',
'ipv6_dns_server1': 'test_value_23',
'ipv6_dns_server2': 'test_value_24',
'ipv6_wins_server1': 'test_value_25',
'ipv6_wins_server2': 'test_value_26',
'login_attempt_limit': '27',
'login_block_time': '28',
'login_timeout': '29',
'port': '30',
'port_precedence': 'enable',
'reqclientcert': 'enable',
'route_source_interface': 'enable',
'servercert': 'test_value_34',
'source_address_negate': 'enable',
'source_address6_negate': 'enable',
'ssl_client_renegotiation': 'disable',
'ssl_insert_empty_fragment': 'enable',
'tlsv1_0': 'enable',
'tlsv1_1': 'enable',
'tlsv1_2': 'enable',
'unsafe_legacy_renegotiation': 'enable',
'url_obscuration': 'enable',
'wins_server1': 'test_value_44',
'wins_server2': 'test_value_45',
'x_content_type_options': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_settings.fortios_vpn_ssl(input_data, fos_instance)
expected_data = {
'auth-timeout': '3',
'auto-tunnel-static-route': 'enable',
'banned-cipher': 'RSA',
'check-referer': 'enable',
'default-portal': 'test_value_7',
'deflate-compression-level': '8',
'deflate-min-data-size': '9',
'dns-server1': 'test_value_10',
'dns-server2': 'test_value_11',
'dns-suffix': 'test_value_12',
'dtls-hello-timeout': '13',
'dtls-tunnel': 'enable',
'force-two-factor-auth': 'enable',
'header-x-forwarded-for': 'pass',
'http-compression': 'enable',
'http-only-cookie': 'enable',
'http-request-body-timeout': '19',
'http-request-header-timeout': '20',
'https-redirect': 'enable',
'idle-timeout': '22',
'ipv6-dns-server1': 'test_value_23',
'ipv6-dns-server2': 'test_value_24',
'ipv6-wins-server1': 'test_value_25',
'ipv6-wins-server2': 'test_value_26',
'login-attempt-limit': '27',
'login-block-time': '28',
'login-timeout': '29',
'port': '30',
'port-precedence': 'enable',
'reqclientcert': 'enable',
'route-source-interface': 'enable',
'servercert': 'test_value_34',
'source-address-negate': 'enable',
'source-address6-negate': 'enable',
'ssl-client-renegotiation': 'disable',
'ssl-insert-empty-fragment': 'enable',
'tlsv1-0': 'enable',
'tlsv1-1': 'enable',
'tlsv1-2': 'enable',
'unsafe-legacy-renegotiation': 'enable',
'url-obscuration': 'enable',
'wins-server1': 'test_value_44',
'wins-server2': 'test_value_45',
'x-content-type-options': 'enable'
}
set_method_mock.assert_called_with('vpn.ssl', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_vpn_ssl_settings_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ssl_settings': {
'auth_timeout': '3',
'auto_tunnel_static_route': 'enable',
'banned_cipher': 'RSA',
'check_referer': 'enable',
'default_portal': 'test_value_7',
'deflate_compression_level': '8',
'deflate_min_data_size': '9',
'dns_server1': 'test_value_10',
'dns_server2': 'test_value_11',
'dns_suffix': 'test_value_12',
'dtls_hello_timeout': '13',
'dtls_tunnel': 'enable',
'force_two_factor_auth': 'enable',
'header_x_forwarded_for': 'pass',
'http_compression': 'enable',
'http_only_cookie': 'enable',
'http_request_body_timeout': '19',
'http_request_header_timeout': '20',
'https_redirect': 'enable',
'idle_timeout': '22',
'ipv6_dns_server1': 'test_value_23',
'ipv6_dns_server2': 'test_value_24',
'ipv6_wins_server1': 'test_value_25',
'ipv6_wins_server2': 'test_value_26',
'login_attempt_limit': '27',
'login_block_time': '28',
'login_timeout': '29',
'port': '30',
'port_precedence': 'enable',
'reqclientcert': 'enable',
'route_source_interface': 'enable',
'servercert': 'test_value_34',
'source_address_negate': 'enable',
'source_address6_negate': 'enable',
'ssl_client_renegotiation': 'disable',
'ssl_insert_empty_fragment': 'enable',
'tlsv1_0': 'enable',
'tlsv1_1': 'enable',
'tlsv1_2': 'enable',
'unsafe_legacy_renegotiation': 'enable',
'url_obscuration': 'enable',
'wins_server1': 'test_value_44',
'wins_server2': 'test_value_45',
'x_content_type_options': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_settings.fortios_vpn_ssl(input_data, fos_instance)
expected_data = {
'auth-timeout': '3',
'auto-tunnel-static-route': 'enable',
'banned-cipher': 'RSA',
'check-referer': 'enable',
'default-portal': 'test_value_7',
'deflate-compression-level': '8',
'deflate-min-data-size': '9',
'dns-server1': 'test_value_10',
'dns-server2': 'test_value_11',
'dns-suffix': 'test_value_12',
'dtls-hello-timeout': '13',
'dtls-tunnel': 'enable',
'force-two-factor-auth': 'enable',
'header-x-forwarded-for': 'pass',
'http-compression': 'enable',
'http-only-cookie': 'enable',
'http-request-body-timeout': '19',
'http-request-header-timeout': '20',
'https-redirect': 'enable',
'idle-timeout': '22',
'ipv6-dns-server1': 'test_value_23',
'ipv6-dns-server2': 'test_value_24',
'ipv6-wins-server1': 'test_value_25',
'ipv6-wins-server2': 'test_value_26',
'login-attempt-limit': '27',
'login-block-time': '28',
'login-timeout': '29',
'port': '30',
'port-precedence': 'enable',
'reqclientcert': 'enable',
'route-source-interface': 'enable',
'servercert': 'test_value_34',
'source-address-negate': 'enable',
'source-address6-negate': 'enable',
'ssl-client-renegotiation': 'disable',
'ssl-insert-empty-fragment': 'enable',
'tlsv1-0': 'enable',
'tlsv1-1': 'enable',
'tlsv1-2': 'enable',
'unsafe-legacy-renegotiation': 'enable',
'url-obscuration': 'enable',
'wins-server1': 'test_value_44',
'wins-server2': 'test_value_45',
'x-content-type-options': 'enable'
}
set_method_mock.assert_called_with('vpn.ssl', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_vpn_ssl_settings_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ssl_settings': {
'auth_timeout': '3',
'auto_tunnel_static_route': 'enable',
'banned_cipher': 'RSA',
'check_referer': 'enable',
'default_portal': 'test_value_7',
'deflate_compression_level': '8',
'deflate_min_data_size': '9',
'dns_server1': 'test_value_10',
'dns_server2': 'test_value_11',
'dns_suffix': 'test_value_12',
'dtls_hello_timeout': '13',
'dtls_tunnel': 'enable',
'force_two_factor_auth': 'enable',
'header_x_forwarded_for': 'pass',
'http_compression': 'enable',
'http_only_cookie': 'enable',
'http_request_body_timeout': '19',
'http_request_header_timeout': '20',
'https_redirect': 'enable',
'idle_timeout': '22',
'ipv6_dns_server1': 'test_value_23',
'ipv6_dns_server2': 'test_value_24',
'ipv6_wins_server1': 'test_value_25',
'ipv6_wins_server2': 'test_value_26',
'login_attempt_limit': '27',
'login_block_time': '28',
'login_timeout': '29',
'port': '30',
'port_precedence': 'enable',
'reqclientcert': 'enable',
'route_source_interface': 'enable',
'servercert': 'test_value_34',
'source_address_negate': 'enable',
'source_address6_negate': 'enable',
'ssl_client_renegotiation': 'disable',
'ssl_insert_empty_fragment': 'enable',
'tlsv1_0': 'enable',
'tlsv1_1': 'enable',
'tlsv1_2': 'enable',
'unsafe_legacy_renegotiation': 'enable',
'url_obscuration': 'enable',
'wins_server1': 'test_value_44',
'wins_server2': 'test_value_45',
'x_content_type_options': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_settings.fortios_vpn_ssl(input_data, fos_instance)
expected_data = {
'auth-timeout': '3',
'auto-tunnel-static-route': 'enable',
'banned-cipher': 'RSA',
'check-referer': 'enable',
'default-portal': 'test_value_7',
'deflate-compression-level': '8',
'deflate-min-data-size': '9',
'dns-server1': 'test_value_10',
'dns-server2': 'test_value_11',
'dns-suffix': 'test_value_12',
'dtls-hello-timeout': '13',
'dtls-tunnel': 'enable',
'force-two-factor-auth': 'enable',
'header-x-forwarded-for': 'pass',
'http-compression': 'enable',
'http-only-cookie': 'enable',
'http-request-body-timeout': '19',
'http-request-header-timeout': '20',
'https-redirect': 'enable',
'idle-timeout': '22',
'ipv6-dns-server1': 'test_value_23',
'ipv6-dns-server2': 'test_value_24',
'ipv6-wins-server1': 'test_value_25',
'ipv6-wins-server2': 'test_value_26',
'login-attempt-limit': '27',
'login-block-time': '28',
'login-timeout': '29',
'port': '30',
'port-precedence': 'enable',
'reqclientcert': 'enable',
'route-source-interface': 'enable',
'servercert': 'test_value_34',
'source-address-negate': 'enable',
'source-address6-negate': 'enable',
'ssl-client-renegotiation': 'disable',
'ssl-insert-empty-fragment': 'enable',
'tlsv1-0': 'enable',
'tlsv1-1': 'enable',
'tlsv1-2': 'enable',
'unsafe-legacy-renegotiation': 'enable',
'url-obscuration': 'enable',
'wins-server1': 'test_value_44',
'wins-server2': 'test_value_45',
'x-content-type-options': 'enable'
}
set_method_mock.assert_called_with('vpn.ssl', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_vpn_ssl_settings_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'vpn_ssl_settings': {
'random_attribute_not_valid': 'tag',
'auth_timeout': '3',
'auto_tunnel_static_route': 'enable',
'banned_cipher': 'RSA',
'check_referer': 'enable',
'default_portal': 'test_value_7',
'deflate_compression_level': '8',
'deflate_min_data_size': '9',
'dns_server1': 'test_value_10',
'dns_server2': 'test_value_11',
'dns_suffix': 'test_value_12',
'dtls_hello_timeout': '13',
'dtls_tunnel': 'enable',
'force_two_factor_auth': 'enable',
'header_x_forwarded_for': 'pass',
'http_compression': 'enable',
'http_only_cookie': 'enable',
'http_request_body_timeout': '19',
'http_request_header_timeout': '20',
'https_redirect': 'enable',
'idle_timeout': '22',
'ipv6_dns_server1': 'test_value_23',
'ipv6_dns_server2': 'test_value_24',
'ipv6_wins_server1': 'test_value_25',
'ipv6_wins_server2': 'test_value_26',
'login_attempt_limit': '27',
'login_block_time': '28',
'login_timeout': '29',
'port': '30',
'port_precedence': 'enable',
'reqclientcert': 'enable',
'route_source_interface': 'enable',
'servercert': 'test_value_34',
'source_address_negate': 'enable',
'source_address6_negate': 'enable',
'ssl_client_renegotiation': 'disable',
'ssl_insert_empty_fragment': 'enable',
'tlsv1_0': 'enable',
'tlsv1_1': 'enable',
'tlsv1_2': 'enable',
'unsafe_legacy_renegotiation': 'enable',
'url_obscuration': 'enable',
'wins_server1': 'test_value_44',
'wins_server2': 'test_value_45',
'x_content_type_options': 'enable'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_settings.fortios_vpn_ssl(input_data, fos_instance)
expected_data = {
'auth-timeout': '3',
'auto-tunnel-static-route': 'enable',
'banned-cipher': 'RSA',
'check-referer': 'enable',
'default-portal': 'test_value_7',
'deflate-compression-level': '8',
'deflate-min-data-size': '9',
'dns-server1': 'test_value_10',
'dns-server2': 'test_value_11',
'dns-suffix': 'test_value_12',
'dtls-hello-timeout': '13',
'dtls-tunnel': 'enable',
'force-two-factor-auth': 'enable',
'header-x-forwarded-for': 'pass',
'http-compression': 'enable',
'http-only-cookie': 'enable',
'http-request-body-timeout': '19',
'http-request-header-timeout': '20',
'https-redirect': 'enable',
'idle-timeout': '22',
'ipv6-dns-server1': 'test_value_23',
'ipv6-dns-server2': 'test_value_24',
'ipv6-wins-server1': 'test_value_25',
'ipv6-wins-server2': 'test_value_26',
'login-attempt-limit': '27',
'login-block-time': '28',
'login-timeout': '29',
'port': '30',
'port-precedence': 'enable',
'reqclientcert': 'enable',
'route-source-interface': 'enable',
'servercert': 'test_value_34',
'source-address-negate': 'enable',
'source-address6-negate': 'enable',
'ssl-client-renegotiation': 'disable',
'ssl-insert-empty-fragment': 'enable',
'tlsv1-0': 'enable',
'tlsv1-1': 'enable',
'tlsv1-2': 'enable',
'unsafe-legacy-renegotiation': 'enable',
'url-obscuration': 'enable',
'wins-server1': 'test_value_44',
'wins-server2': 'test_value_45',
'x-content-type-options': 'enable'
}
set_method_mock.assert_called_with('vpn.ssl', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,689 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_vpn_ssl_web_portal
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_vpn_ssl_web_portal.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
expected_data = {
'allow-user-access': 'web',
'auto-connect': 'enable',
'custom-lang': 'test_value_5',
'customize-forticlient-download-url': 'enable',
'display-bookmark': 'enable',
'display-connection-tools': 'enable',
'display-history': 'enable',
'display-status': 'enable',
'dns-server1': 'test_value_11',
'dns-server2': 'test_value_12',
'dns-suffix': 'test_value_13',
'exclusive-routing': 'enable',
'forticlient-download': 'enable',
'forticlient-download-method': 'direct',
'heading': 'test_value_17',
'hide-sso-credential': 'enable',
'host-check': 'none',
'host-check-interval': '20',
'ip-mode': 'range',
'ipv6-dns-server1': 'test_value_22',
'ipv6-dns-server2': 'test_value_23',
'ipv6-exclusive-routing': 'enable',
'ipv6-service-restriction': 'enable',
'ipv6-split-tunneling': 'enable',
'ipv6-tunnel-mode': 'enable',
'ipv6-wins-server1': 'test_value_28',
'ipv6-wins-server2': 'test_value_29',
'keep-alive': 'enable',
'limit-user-logins': 'enable',
'mac-addr-action': 'allow',
'mac-addr-check': 'enable',
'macos-forticlient-download-url': 'test_value_34',
'name': 'default_name_35',
'os-check': 'enable',
'redir-url': 'test_value_37',
'save-password': 'enable',
'service-restriction': 'enable',
'skip-check-for-unsupported-browser': 'enable',
'skip-check-for-unsupported-os': 'enable',
'smb-ntlmv1-auth': 'enable',
'smbv1': 'enable',
'split-tunneling': 'enable',
'theme': 'blue',
'tunnel-mode': 'enable',
'user-bookmark': 'enable',
'user-group-bookmark': 'enable',
'web-mode': 'enable',
'windows-forticlient-download-url': 'test_value_50',
'wins-server1': 'test_value_51',
'wins-server2': 'test_value_52'
}
set_method_mock.assert_called_with('vpn.ssl.web', 'portal', 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_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
expected_data = {
'allow-user-access': 'web',
'auto-connect': 'enable',
'custom-lang': 'test_value_5',
'customize-forticlient-download-url': 'enable',
'display-bookmark': 'enable',
'display-connection-tools': 'enable',
'display-history': 'enable',
'display-status': 'enable',
'dns-server1': 'test_value_11',
'dns-server2': 'test_value_12',
'dns-suffix': 'test_value_13',
'exclusive-routing': 'enable',
'forticlient-download': 'enable',
'forticlient-download-method': 'direct',
'heading': 'test_value_17',
'hide-sso-credential': 'enable',
'host-check': 'none',
'host-check-interval': '20',
'ip-mode': 'range',
'ipv6-dns-server1': 'test_value_22',
'ipv6-dns-server2': 'test_value_23',
'ipv6-exclusive-routing': 'enable',
'ipv6-service-restriction': 'enable',
'ipv6-split-tunneling': 'enable',
'ipv6-tunnel-mode': 'enable',
'ipv6-wins-server1': 'test_value_28',
'ipv6-wins-server2': 'test_value_29',
'keep-alive': 'enable',
'limit-user-logins': 'enable',
'mac-addr-action': 'allow',
'mac-addr-check': 'enable',
'macos-forticlient-download-url': 'test_value_34',
'name': 'default_name_35',
'os-check': 'enable',
'redir-url': 'test_value_37',
'save-password': 'enable',
'service-restriction': 'enable',
'skip-check-for-unsupported-browser': 'enable',
'skip-check-for-unsupported-os': 'enable',
'smb-ntlmv1-auth': 'enable',
'smbv1': 'enable',
'split-tunneling': 'enable',
'theme': 'blue',
'tunnel-mode': 'enable',
'user-bookmark': 'enable',
'user-group-bookmark': 'enable',
'web-mode': 'enable',
'windows-forticlient-download-url': 'test_value_50',
'wins-server1': 'test_value_51',
'wins-server2': 'test_value_52'
}
set_method_mock.assert_called_with('vpn.ssl.web', 'portal', 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_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ssl.web', 'portal', 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_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
delete_method_mock.assert_called_with('vpn.ssl.web', 'portal', 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_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
expected_data = {
'allow-user-access': 'web',
'auto-connect': 'enable',
'custom-lang': 'test_value_5',
'customize-forticlient-download-url': 'enable',
'display-bookmark': 'enable',
'display-connection-tools': 'enable',
'display-history': 'enable',
'display-status': 'enable',
'dns-server1': 'test_value_11',
'dns-server2': 'test_value_12',
'dns-suffix': 'test_value_13',
'exclusive-routing': 'enable',
'forticlient-download': 'enable',
'forticlient-download-method': 'direct',
'heading': 'test_value_17',
'hide-sso-credential': 'enable',
'host-check': 'none',
'host-check-interval': '20',
'ip-mode': 'range',
'ipv6-dns-server1': 'test_value_22',
'ipv6-dns-server2': 'test_value_23',
'ipv6-exclusive-routing': 'enable',
'ipv6-service-restriction': 'enable',
'ipv6-split-tunneling': 'enable',
'ipv6-tunnel-mode': 'enable',
'ipv6-wins-server1': 'test_value_28',
'ipv6-wins-server2': 'test_value_29',
'keep-alive': 'enable',
'limit-user-logins': 'enable',
'mac-addr-action': 'allow',
'mac-addr-check': 'enable',
'macos-forticlient-download-url': 'test_value_34',
'name': 'default_name_35',
'os-check': 'enable',
'redir-url': 'test_value_37',
'save-password': 'enable',
'service-restriction': 'enable',
'skip-check-for-unsupported-browser': 'enable',
'skip-check-for-unsupported-os': 'enable',
'smb-ntlmv1-auth': 'enable',
'smbv1': 'enable',
'split-tunneling': 'enable',
'theme': 'blue',
'tunnel-mode': 'enable',
'user-bookmark': 'enable',
'user-group-bookmark': 'enable',
'web-mode': 'enable',
'windows-forticlient-download-url': 'test_value_50',
'wins-server1': 'test_value_51',
'wins-server2': 'test_value_52'
}
set_method_mock.assert_called_with('vpn.ssl.web', 'portal', 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_vpn_ssl_web_portal_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',
'vpn_ssl_web_portal': {
'random_attribute_not_valid': 'tag',
'allow_user_access': 'web',
'auto_connect': 'enable',
'custom_lang': 'test_value_5',
'customize_forticlient_download_url': 'enable',
'display_bookmark': 'enable',
'display_connection_tools': 'enable',
'display_history': 'enable',
'display_status': 'enable',
'dns_server1': 'test_value_11',
'dns_server2': 'test_value_12',
'dns_suffix': 'test_value_13',
'exclusive_routing': 'enable',
'forticlient_download': 'enable',
'forticlient_download_method': 'direct',
'heading': 'test_value_17',
'hide_sso_credential': 'enable',
'host_check': 'none',
'host_check_interval': '20',
'ip_mode': 'range',
'ipv6_dns_server1': 'test_value_22',
'ipv6_dns_server2': 'test_value_23',
'ipv6_exclusive_routing': 'enable',
'ipv6_service_restriction': 'enable',
'ipv6_split_tunneling': 'enable',
'ipv6_tunnel_mode': 'enable',
'ipv6_wins_server1': 'test_value_28',
'ipv6_wins_server2': 'test_value_29',
'keep_alive': 'enable',
'limit_user_logins': 'enable',
'mac_addr_action': 'allow',
'mac_addr_check': 'enable',
'macos_forticlient_download_url': 'test_value_34',
'name': 'default_name_35',
'os_check': 'enable',
'redir_url': 'test_value_37',
'save_password': 'enable',
'service_restriction': 'enable',
'skip_check_for_unsupported_browser': 'enable',
'skip_check_for_unsupported_os': 'enable',
'smb_ntlmv1_auth': 'enable',
'smbv1': 'enable',
'split_tunneling': 'enable',
'theme': 'blue',
'tunnel_mode': 'enable',
'user_bookmark': 'enable',
'user_group_bookmark': 'enable',
'web_mode': 'enable',
'windows_forticlient_download_url': 'test_value_50',
'wins_server1': 'test_value_51',
'wins_server2': 'test_value_52'
},
'vdom': 'root'}
is_error, changed, response = fortios_vpn_ssl_web_portal.fortios_vpn_ssl_web(input_data, fos_instance)
expected_data = {
'allow-user-access': 'web',
'auto-connect': 'enable',
'custom-lang': 'test_value_5',
'customize-forticlient-download-url': 'enable',
'display-bookmark': 'enable',
'display-connection-tools': 'enable',
'display-history': 'enable',
'display-status': 'enable',
'dns-server1': 'test_value_11',
'dns-server2': 'test_value_12',
'dns-suffix': 'test_value_13',
'exclusive-routing': 'enable',
'forticlient-download': 'enable',
'forticlient-download-method': 'direct',
'heading': 'test_value_17',
'hide-sso-credential': 'enable',
'host-check': 'none',
'host-check-interval': '20',
'ip-mode': 'range',
'ipv6-dns-server1': 'test_value_22',
'ipv6-dns-server2': 'test_value_23',
'ipv6-exclusive-routing': 'enable',
'ipv6-service-restriction': 'enable',
'ipv6-split-tunneling': 'enable',
'ipv6-tunnel-mode': 'enable',
'ipv6-wins-server1': 'test_value_28',
'ipv6-wins-server2': 'test_value_29',
'keep-alive': 'enable',
'limit-user-logins': 'enable',
'mac-addr-action': 'allow',
'mac-addr-check': 'enable',
'macos-forticlient-download-url': 'test_value_34',
'name': 'default_name_35',
'os-check': 'enable',
'redir-url': 'test_value_37',
'save-password': 'enable',
'service-restriction': 'enable',
'skip-check-for-unsupported-browser': 'enable',
'skip-check-for-unsupported-os': 'enable',
'smb-ntlmv1-auth': 'enable',
'smbv1': 'enable',
'split-tunneling': 'enable',
'theme': 'blue',
'tunnel-mode': 'enable',
'user-bookmark': 'enable',
'user-group-bookmark': 'enable',
'web-mode': 'enable',
'windows-forticlient-download-url': 'test_value_50',
'wins-server1': 'test_value_51',
'wins-server2': 'test_value_52'
}
set_method_mock.assert_called_with('vpn.ssl.web', 'portal', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

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

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

@ -0,0 +1,167 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_wanopt_settings
except ImportError:
pytest.skip("Could not load required modules for testing", allow_module_level=True)
@pytest.fixture(autouse=True)
def connection_mock(mocker):
connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_wanopt_settings.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_wanopt_settings_creation(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'wanopt_settings': {
'auto_detect_algorithm': 'simple',
'host_id': 'myhostname4',
'tunnel_ssl_algorithm': 'low'
},
'vdom': 'root'}
is_error, changed, response = fortios_wanopt_settings.fortios_wanopt(input_data, fos_instance)
expected_data = {
'auto-detect-algorithm': 'simple',
'host-id': 'myhostname4',
'tunnel-ssl-algorithm': 'low'
}
set_method_mock.assert_called_with('wanopt', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200
def test_wanopt_settings_creation_fails(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'wanopt_settings': {
'auto_detect_algorithm': 'simple',
'host_id': 'myhostname4',
'tunnel_ssl_algorithm': 'low'
},
'vdom': 'root'}
is_error, changed, response = fortios_wanopt_settings.fortios_wanopt(input_data, fos_instance)
expected_data = {
'auto-detect-algorithm': 'simple',
'host-id': 'myhostname4',
'tunnel-ssl-algorithm': 'low'
}
set_method_mock.assert_called_with('wanopt', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 500
def test_wanopt_settings_idempotent(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'wanopt_settings': {
'auto_detect_algorithm': 'simple',
'host_id': 'myhostname4',
'tunnel_ssl_algorithm': 'low'
},
'vdom': 'root'}
is_error, changed, response = fortios_wanopt_settings.fortios_wanopt(input_data, fos_instance)
expected_data = {
'auto-detect-algorithm': 'simple',
'host-id': 'myhostname4',
'tunnel-ssl-algorithm': 'low'
}
set_method_mock.assert_called_with('wanopt', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert not changed
assert response['status'] == 'error'
assert response['http_status'] == 404
def test_wanopt_settings_filter_foreign_attributes(mocker):
schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema')
set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200}
set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result)
input_data = {
'username': 'admin',
'state': 'present',
'wanopt_settings': {
'random_attribute_not_valid': 'tag',
'auto_detect_algorithm': 'simple',
'host_id': 'myhostname4',
'tunnel_ssl_algorithm': 'low'
},
'vdom': 'root'}
is_error, changed, response = fortios_wanopt_settings.fortios_wanopt(input_data, fos_instance)
expected_data = {
'auto-detect-algorithm': 'simple',
'host-id': 'myhostname4',
'tunnel-ssl-algorithm': 'low'
}
set_method_mock.assert_called_with('wanopt', 'settings', data=expected_data, vdom='root')
schema_method_mock.assert_not_called()
assert not is_error
assert changed
assert response['status'] == 'success'
assert response['http_status'] == 200

@ -0,0 +1,219 @@
# Copyright 2019 Fortinet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
import pytest
from mock import ANY
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
try:
from ansible.modules.network.fortios import fortios_webfilter_content
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_webfilter_content.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_webfilter_content_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',
'webfilter_content': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_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',
'webfilter_content': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_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',
'webfilter_content': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_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',
'webfilter_content': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_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',
'webfilter_content': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_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',
'webfilter_content': {
'random_attribute_not_valid': 'tag',
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content', 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_webfilter_content_header
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_webfilter_content_header.Connection')
return connection_class_mock
fos_instance = FortiOSHandler(connection_mock)
def test_webfilter_content_header_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',
'webfilter_content_header': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content-header', 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_webfilter_content_header_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',
'webfilter_content_header': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content-header', 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_webfilter_content_header_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',
'webfilter_content_header': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('webfilter', 'content-header', 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_webfilter_content_header_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',
'webfilter_content_header': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
delete_method_mock.assert_called_with('webfilter', 'content-header', 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_webfilter_content_header_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',
'webfilter_content_header': {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content-header', 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_webfilter_content_header_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',
'webfilter_content_header': {
'random_attribute_not_valid': 'tag',
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
},
'vdom': 'root'}
is_error, changed, response = fortios_webfilter_content_header.fortios_webfilter(input_data, fos_instance)
expected_data = {
'comment': 'Optional comments.',
'id': '4',
'name': 'default_name_5'
}
set_method_mock.assert_called_with('webfilter', 'content-header', 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