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
This commit is contained in:
parent
d29aaffb16
commit
5e4e32b45e
41 changed files with 12932 additions and 2994 deletions
|
@ -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)
|
||||
|
@ -42,46 +42,61 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
user_adgrp:
|
||||
state: "present"
|
||||
user_adgrp:
|
||||
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},
|
||||
"user_adgrp": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"user_adgrp": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"name": {"required": True, "type": "str"},
|
||||
"server-name": {"required": False, "type": "str"}
|
||||
"server_name": {"required": False, "type": "str"}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +281,21 @@ 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
|
||||
|
||||
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:
|
||||
|
@ -248,7 +303,9 @@ def main():
|
|||
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,83 +42,107 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
user_radius:
|
||||
state: "present"
|
||||
accounting-server:
|
||||
user_radius:
|
||||
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},
|
||||
"user_radius": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"accounting-server": {"required": False, "type": "list",
|
||||
"user_radius": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,42 +42,56 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip adress.
|
||||
required: true
|
||||
- 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"
|
||||
user_tacacsplus:
|
||||
state: "present"
|
||||
authen-type: "mschap"
|
||||
user_tacacsplus:
|
||||
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},
|
||||
"user_tacacsplus": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"authen-type": {"required": False, "type": "str",
|
||||
"user_tacacsplus": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,54 +42,71 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
vpn_ipsec_concentrator:
|
||||
state: "present"
|
||||
vpn_ipsec_concentrator:
|
||||
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},
|
||||
"vpn_ipsec_concentrator": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"vpn_ipsec_concentrator": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,56 +42,73 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
vpn_ipsec_forticlient:
|
||||
state: "present"
|
||||
vpn_ipsec_forticlient:
|
||||
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},
|
||||
"vpn_ipsec_forticlient": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"vpn_ipsec_forticlient": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,42 +42,56 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
vpn_ipsec_manualkey:
|
||||
state: "present"
|
||||
vpn_ipsec_manualkey:
|
||||
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
|
||||
|
||||
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']:
|
||||
|
@ -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},
|
||||
"vpn_ipsec_manualkey": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"vpn_ipsec_manualkey": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,48 +42,63 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
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>"
|
||||
vpn_ipsec_manualkey_interface:
|
||||
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
|
||||
|
||||
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']:
|
||||
|
@ -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},
|
||||
"vpn_ipsec_manualkey_interface": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"addr-type": {"required": False, "type": "str",
|
||||
"vpn_ipsec_manualkey_interface": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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
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_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)
|
||||
|
@ -45,64 +42,82 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
vpn_ipsec_phase2:
|
||||
state: "present"
|
||||
add-route: "phase1"
|
||||
auto-negotiate: "enable"
|
||||
vpn_ipsec_phase2:
|
||||
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},
|
||||
"vpn_ipsec_phase2": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"add-route": {"required": False, "type": "str",
|
||||
"vpn_ipsec_phase2": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,78 +42,98 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
vpn_ipsec_phase2_interface:
|
||||
state: "present"
|
||||
add-route: "phase1"
|
||||
auto-discovery-forwarder: "phase1"
|
||||
auto-discovery-sender: "phase1"
|
||||
auto-negotiate: "enable"
|
||||
vpn_ipsec_phase2_interface:
|
||||
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},
|
||||
"vpn_ipsec_phase2_interface": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"add-route": {"required": False, "type": "str",
|
||||
"vpn_ipsec_phase2_interface": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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
File diff suppressed because it is too large
Load diff
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)
|
||||
|
@ -42,57 +42,74 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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"
|
||||
wanopt_profile:
|
||||
state: "present"
|
||||
auth-group: "<your_own_value> (source wanopt.auth-group.name)"
|
||||
wanopt_profile:
|
||||
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},
|
||||
"wanopt_profile": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"ssl_verify": {"required": False, "type": "bool", "default": True},
|
||||
"state": {"required": True, "type": "str",
|
||||
"choices": ["present", "absent"]},
|
||||
"auth-group": {"required": False, "type": "str"},
|
||||
"wanopt_profile": {
|
||||
"required": False, "type": "dict", "default": None,
|
||||
"options": {
|
||||
"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,6 +734,21 @@ 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
|
||||
|
||||
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:
|
||||
|
@ -654,7 +756,9 @@ def main():
|
|||
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -42,45 +42,58 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- 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,6 +273,21 @@ 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
|
||||
|
||||
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:
|
||||
|
@ -243,7 +295,9 @@ def main():
|
|||
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,55 +42,72 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- FortiOS or FortiGate IP address.
|
||||
type: str
|
||||
required: false
|
||||
username:
|
||||
description:
|
||||
- FortiOS or FortiGate username.
|
||||
required: true
|
||||
type: str
|
||||
required: false
|
||||
password:
|
||||
description:
|
||||
- FortiOS or FortiGate password.
|
||||
type: str
|
||||
default: ""
|
||||
vdom:
|
||||
description:
|
||||
- Virtual domain, among those defined previously. A vdom is a
|
||||
virtual instance of the FortiGate that can be configured and
|
||||
used as a different unit.
|
||||
type: str
|
||||
default: root
|
||||
https:
|
||||
description:
|
||||
- Indicates if the requests towards FortiGate must use HTTPS
|
||||
protocol
|
||||
- Indicates if the requests towards FortiGate must use HTTPS protocol.
|
||||
type: bool
|
||||
default: false
|
||||
default: true
|
||||
ssl_verify:
|
||||
description:
|
||||
- Ensures FortiGate certificate must be verified by a proper CA.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 2.9
|
||||
state:
|
||||
description:
|
||||
- Indicates whether to create or remove the object.
|
||||
type: str
|
||||
required: true
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
version_added: 2.9
|
||||
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 }}"
|
||||
webfilter_content:
|
||||
https: "False"
|
||||
state: "present"
|
||||
webfilter_content:
|
||||
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
|
||||
|
||||
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']:
|
||||
|
@ -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"},
|
||||
"webfilter_content": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"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", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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)
|
||||
|
@ -45,49 +42,65 @@ requirements:
|
|||
options:
|
||||
host:
|
||||
description:
|
||||
- FortiOS or FortiGate ip address.
|
||||
required: true
|
||||
- FortiOS or FortiGate IP address.
|
||||
type: str
|
||||
required: false
|
||||
username:
|
||||
description:
|
||||
- FortiOS or FortiGate username.
|
||||
required: true
|
||||
type: str
|
||||
required: false
|
||||
password:
|
||||
description:
|
||||
- FortiOS or FortiGate password.
|
||||
type: str
|
||||
default: ""
|
||||
vdom:
|
||||
description:
|
||||
- Virtual domain, among those defined previously. A vdom is a
|
||||
virtual instance of the FortiGate that can be configured and
|
||||
used as a different unit.
|
||||
type: str
|
||||
default: root
|
||||
https:
|
||||
description:
|
||||
- Indicates if the requests towards FortiGate must use HTTPS
|
||||
protocol
|
||||
- Indicates if the requests towards FortiGate must use HTTPS protocol.
|
||||
type: bool
|
||||
default: false
|
||||
default: true
|
||||
ssl_verify:
|
||||
description:
|
||||
- Ensures FortiGate certificate must be verified by a proper CA.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 2.9
|
||||
state:
|
||||
description:
|
||||
- Indicates whether to create or remove the object.
|
||||
type: str
|
||||
required: true
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
version_added: 2.9
|
||||
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,6 +132,7 @@ EXAMPLES = '''
|
|||
username: "admin"
|
||||
password: ""
|
||||
vdom: "root"
|
||||
ssl_verify: "False"
|
||||
tasks:
|
||||
- name: Configure content types used by Web filter.
|
||||
fortios_webfilter_content_header:
|
||||
|
@ -122,8 +140,9 @@ EXAMPLES = '''
|
|||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
vdom: "{{ vdom }}"
|
||||
webfilter_content_header:
|
||||
https: "False"
|
||||
state: "present"
|
||||
webfilter_content_header:
|
||||
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
|
||||
|
||||
fos = None
|
||||
from ansible.module_utils.connection import Connection
|
||||
from ansible.module_utils.network.fortios.fortios import FortiOSHandler
|
||||
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
|
||||
|
||||
|
||||
def login(data):
|
||||
def login(data, fos):
|
||||
host = data['host']
|
||||
username = data['username']
|
||||
password = data['password']
|
||||
ssl_verify = data['ssl_verify']
|
||||
|
||||
fos.debug('on')
|
||||
if 'https' in data and not data['https']:
|
||||
|
@ -209,7 +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"},
|
||||
"webfilter_content_header": {
|
||||
"required": False, "type": "dict",
|
||||
"options": {
|
||||
"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", "default": None,
|
||||
"options": {
|
||||
"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)
|
||||
|
||||
# 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")
|
||||
|
||||
global fos
|
||||
fos = FortiOSAPI()
|
||||
|
||||
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
|
||||
|
|
209
test/units/modules/network/fortios/test_fortios_user_adgrp.py
Normal file
209
test/units/modules/network/fortios/test_fortios_user_adgrp.py
Normal file
|
@ -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')
|
||||
|
|
539
test/units/modules/network/fortios/test_fortios_user_radius.py
Normal file
539
test/units/modules/network/fortios/test_fortios_user_radius.py
Normal file
|
@ -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
|
219
test/units/modules/network/fortios/test_fortios_voip_profile.py
Normal file
219
test/units/modules/network/fortios/test_fortios_voip_profile.py
Normal file
|
@ -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
|
1149
test/units/modules/network/fortios/test_fortios_vpn_ipsec_phase1.py
Normal file
1149
test/units/modules/network/fortios/test_fortios_vpn_ipsec_phase1.py
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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
|
229
test/units/modules/network/fortios/test_fortios_waf_profile.py
Normal file
229
test/units/modules/network/fortios/test_fortios_waf_profile.py
Normal file
|
@ -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…
Reference in a new issue