diff --git a/lib/ansible/modules/network/fortios/fortios_system_ha.py b/lib/ansible/modules/network/fortios/fortios_system_ha.py new file mode 100644 index 00000000000..dfd3bc384db --- /dev/null +++ b/lib/ansible/modules/network/fortios/fortios_system_ha.py @@ -0,0 +1,902 @@ +#!/usr/bin/python +from __future__ import (absolute_import, division, print_function) +# 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 this program. If not, see <https://www.gnu.org/licenses/> + +__metaclass__ = type + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.1'} + +DOCUMENTATION = ''' +--- +module: fortios_system_ha +short_description: Configure HA in Fortinet's FortiOS and FortiGate. +description: + - This module is able to configure a FortiGate or FortiOS device by allowing the + user to set and modify system feature and ha category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.5 +version_added: "2.9" +author: + - Miguel Angel Munoz (@mamunozgonzalez) + - Nicolas Thomas (@thomnico) +notes: + - Requires fortiosapi library developed by Fortinet + - Run as a local_action in your playbook +requirements: + - fortiosapi>=0.9.8 +options: + host: + description: + - FortiOS or FortiGate IP address. + type: str + required: false + username: + description: + - FortiOS or FortiGate username. + 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. + type: bool + default: true + ssl_verify: + description: + - Ensures FortiGate certificate must be verified by a proper CA. + type: bool + default: true + system_ha: + description: + - Configure HA. + default: null + type: dict + suboptions: + arps: + description: + - Number of gratuitous ARPs (1 - 60). Lower to reduce traffic. Higher to reduce failover time. + type: int + arps_interval: + description: + - Time between gratuitous ARPs (1 - 20 sec). Lower to reduce failover time. Higher to reduce traffic. + type: int + authentication: + description: + - Enable/disable heartbeat message authentication. + type: str + choices: + - enable + - disable + cpu_threshold: + description: + - Dynamic weighted load balancing CPU usage weight and high and low thresholds. + type: str + encryption: + description: + - Enable/disable heartbeat message encryption. + type: str + choices: + - enable + - disable + ftp_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of FTP proxy sessions. + type: str + gratuitous_arps: + description: + - Enable/disable gratuitous ARPs. Disable if link-failed-signal enabled. + type: str + choices: + - enable + - disable + group_id: + description: + - Cluster group ID (0 - 255). Must be the same for all members. + type: int + group_name: + description: + - Cluster group name. Must be the same for all members. + type: str + ha_direct: + description: + - Enable/disable using ha-mgmt interface for syslog, SNMP, remote authentication (RADIUS), FortiAnalyzer, and FortiSandbox. + type: str + choices: + - enable + - disable + ha_eth_type: + description: + - HA heartbeat packet Ethertype (4-digit hex). + type: str + ha_mgmt_interfaces: + description: + - Reserve interfaces to manage individual cluster units. + type: list + suboptions: + dst: + description: + - Default route destination for reserved HA management interface. + type: str + gateway: + description: + - Default route gateway for reserved HA management interface. + type: str + gateway6: + description: + - Default IPv6 gateway for reserved HA management interface. + type: str + id: + description: + - Table ID. + required: true + type: int + interface: + description: + - Interface to reserve for HA management. Source system.interface.name. + type: str + ha_mgmt_status: + description: + - Enable to reserve interfaces to manage individual cluster units. + type: str + choices: + - enable + - disable + ha_uptime_diff_margin: + description: + - Normally you would only reduce this value for failover testing. + type: int + hb_interval: + description: + - Time between sending heartbeat packets (1 - 20 (100*ms)). Increase to reduce false positives. + type: int + hb_lost_threshold: + description: + - Number of lost heartbeats to signal a failure (1 - 60). Increase to reduce false positives. + type: int + hbdev: + description: + - Heartbeat interfaces. Must be the same for all members. + type: str + hc_eth_type: + description: + - Transparent mode HA heartbeat packet Ethertype (4-digit hex). + type: str + hello_holddown: + description: + - Time to wait before changing from hello to work state (5 - 300 sec). + type: int + http_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of HTTP proxy sessions. + type: str + imap_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of IMAP proxy sessions. + type: str + inter_cluster_session_sync: + description: + - Enable/disable synchronization of sessions among HA clusters. + type: str + choices: + - enable + - disable + key: + description: + - key + type: str + l2ep_eth_type: + description: + - Telnet session HA heartbeat packet Ethertype (4-digit hex). + type: str + link_failed_signal: + description: + - Enable to shut down all interfaces for 1 sec after a failover. Use if gratuitous ARPs do not update network. + type: str + choices: + - enable + - disable + load_balance_all: + description: + - Enable to load balance TCP sessions. Disable to load balance proxy sessions only. + type: str + choices: + - enable + - disable + memory_compatible_mode: + description: + - Enable/disable memory compatible mode. + type: str + choices: + - enable + - disable + memory_threshold: + description: + - Dynamic weighted load balancing memory usage weight and high and low thresholds. + type: str + mode: + description: + - HA mode. Must be the same for all members. FGSP requires standalone. + type: str + choices: + - standalone + - a-a + - a-p + monitor: + description: + - Interfaces to check for port monitoring (or link failure). Source system.interface.name. + type: str + multicast_ttl: + description: + - HA multicast TTL on master (5 - 3600 sec). + type: int + nntp_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of NNTP proxy sessions. + type: str + override: + description: + - Enable and increase the priority of the unit that should always be primary (master). + type: str + choices: + - enable + - disable + override_wait_time: + description: + - Delay negotiating if override is enabled (0 - 3600 sec). Reduces how often the cluster negotiates. + type: int + password: + description: + - Cluster password. Must be the same for all members. + type: str + pingserver_failover_threshold: + description: + - Remote IP monitoring failover threshold (0 - 50). + type: int + pingserver_flip_timeout: + description: + - Time to wait in minutes before renegotiating after a remote IP monitoring failover. + type: int + pingserver_monitor_interface: + description: + - Interfaces to check for remote IP monitoring. Source system.interface.name. + type: str + pingserver_slave_force_reset: + description: + - Enable to force the cluster to negotiate after a remote IP monitoring failover. + type: str + choices: + - enable + - disable + pop3_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of POP3 proxy sessions. + type: str + priority: + description: + - Increase the priority to select the primary unit (0 - 255). + type: int + route_hold: + description: + - Time to wait between routing table updates to the cluster (0 - 3600 sec). + type: int + route_ttl: + description: + - TTL for primary unit routes (5 - 3600 sec). Increase to maintain active routes during failover. + type: int + route_wait: + description: + - Time to wait before sending new routes to the cluster (0 - 3600 sec). + type: int + schedule: + description: + - Type of A-A load balancing. Use none if you have external load balancers. + type: str + choices: + - none + - hub + - leastconnection + - round-robin + - weight-round-robin + - random + - ip + - ipport + secondary_vcluster: + description: + - Configure virtual cluster 2. + type: dict + suboptions: + monitor: + description: + - Interfaces to check for port monitoring (or link failure). Source system.interface.name. + type: str + override: + description: + - Enable and increase the priority of the unit that should always be primary (master). + type: str + choices: + - enable + - disable + override_wait_time: + description: + - Delay negotiating if override is enabled (0 - 3600 sec). Reduces how often the cluster negotiates. + type: int + pingserver_failover_threshold: + description: + - Remote IP monitoring failover threshold (0 - 50). + type: int + pingserver_monitor_interface: + description: + - Interfaces to check for remote IP monitoring. Source system.interface.name. + type: str + pingserver_slave_force_reset: + description: + - Enable to force the cluster to negotiate after a remote IP monitoring failover. + type: str + choices: + - enable + - disable + priority: + description: + - Increase the priority to select the primary unit (0 - 255). + type: int + vcluster_id: + description: + - Cluster ID. + type: int + vdom: + description: + - VDOMs in virtual cluster 2. + type: str + session_pickup: + description: + - Enable/disable session pickup. Enabling it can reduce session down time when fail over happens. + type: str + choices: + - enable + - disable + session_pickup_connectionless: + description: + - Enable/disable UDP and ICMP session sync for FGSP. + type: str + choices: + - enable + - disable + session_pickup_delay: + description: + - Enable to sync sessions longer than 30 sec. Only longer lived sessions need to be synced. + type: str + choices: + - enable + - disable + session_pickup_expectation: + description: + - Enable/disable session helper expectation session sync for FGSP. + type: str + choices: + - enable + - disable + session_pickup_nat: + description: + - Enable/disable NAT session sync for FGSP. + type: str + choices: + - enable + - disable + session_sync_dev: + description: + - Offload session sync to one or more interfaces to distribute traffic and prevent delays if needed. Source system.interface.name. + type: str + smtp_proxy_threshold: + description: + - Dynamic weighted load balancing weight and high and low number of SMTP proxy sessions. + type: str + standalone_config_sync: + description: + - Enable/disable FGSP configuration synchronization. + type: str + choices: + - enable + - disable + standalone_mgmt_vdom: + description: + - Enable/disable standalone management VDOM. + type: str + choices: + - enable + - disable + sync_config: + description: + - Enable/disable configuration synchronization. + type: str + choices: + - enable + - disable + sync_packet_balance: + description: + - Enable/disable HA packet distribution to multiple CPUs. + type: str + choices: + - enable + - disable + unicast_hb: + description: + - Enable/disable unicast heartbeat. + type: str + choices: + - enable + - disable + unicast_hb_netmask: + description: + - Unicast heartbeat netmask. + type: str + unicast_hb_peerip: + description: + - Unicast heartbeat peer IP. + type: str + uninterruptible_upgrade: + description: + - Enable to upgrade a cluster without blocking network traffic. + type: str + choices: + - enable + - disable + vcluster_id: + description: + - Cluster ID. + type: int + vcluster2: + description: + - Enable/disable virtual cluster 2 for virtual clustering. + type: str + choices: + - enable + - disable + vdom: + description: + - VDOMs in virtual cluster 1. + type: str + weight: + description: + - Weight-round-robin weight for each cluster unit. Syntax <priority> <weight>. + type: str +''' + +EXAMPLES = ''' +- hosts: localhost + vars: + host: "192.168.122.40" + username: "admin" + password: "" + vdom: "root" + ssl_verify: "False" + tasks: + - name: Configure HA. + fortios_system_ha: + host: "{{ host }}" + username: "{{ username }}" + password: "{{ password }}" + vdom: "{{ vdom }}" + https: "False" + system_ha: + arps: "3" + arps_interval: "4" + authentication: "enable" + cpu_threshold: "<your_own_value>" + encryption: "enable" + ftp_proxy_threshold: "<your_own_value>" + gratuitous_arps: "enable" + group_id: "10" + group_name: "<your_own_value>" + ha_direct: "enable" + ha_eth_type: "<your_own_value>" + ha_mgmt_interfaces: + - + dst: "<your_own_value>" + gateway: "<your_own_value>" + gateway6: "<your_own_value>" + id: "18" + interface: "<your_own_value> (source system.interface.name)" + ha_mgmt_status: "enable" + ha_uptime_diff_margin: "21" + hb_interval: "22" + hb_lost_threshold: "23" + hbdev: "<your_own_value>" + hc_eth_type: "<your_own_value>" + hello_holddown: "26" + http_proxy_threshold: "<your_own_value>" + imap_proxy_threshold: "<your_own_value>" + inter_cluster_session_sync: "enable" + key: "<your_own_value>" + l2ep_eth_type: "<your_own_value>" + link_failed_signal: "enable" + load_balance_all: "enable" + memory_compatible_mode: "enable" + memory_threshold: "<your_own_value>" + mode: "standalone" + monitor: "<your_own_value> (source system.interface.name)" + multicast_ttl: "38" + nntp_proxy_threshold: "<your_own_value>" + override: "enable" + override_wait_time: "41" + password: "<your_own_value>" + pingserver_failover_threshold: "43" + pingserver_flip_timeout: "44" + pingserver_monitor_interface: "<your_own_value> (source system.interface.name)" + pingserver_slave_force_reset: "enable" + pop3_proxy_threshold: "<your_own_value>" + priority: "48" + route_hold: "49" + route_ttl: "50" + route_wait: "51" + schedule: "none" + secondary_vcluster: + monitor: "<your_own_value> (source system.interface.name)" + override: "enable" + override_wait_time: "56" + pingserver_failover_threshold: "57" + pingserver_monitor_interface: "<your_own_value> (source system.interface.name)" + pingserver_slave_force_reset: "enable" + priority: "60" + vcluster_id: "61" + vdom: "<your_own_value>" + session_pickup: "enable" + session_pickup_connectionless: "enable" + session_pickup_delay: "enable" + session_pickup_expectation: "enable" + session_pickup_nat: "enable" + session_sync_dev: "<your_own_value> (source system.interface.name)" + smtp_proxy_threshold: "<your_own_value>" + standalone_config_sync: "enable" + standalone_mgmt_vdom: "enable" + sync_config: "enable" + sync_packet_balance: "enable" + unicast_hb: "enable" + unicast_hb_netmask: "<your_own_value>" + unicast_hb_peerip: "<your_own_value>" + uninterruptible_upgrade: "enable" + vcluster_id: "78" + vcluster2: "enable" + vdom: "<your_own_value>" + weight: "<your_own_value>" +''' + +RETURN = ''' +build: + description: Build number of the fortigate image + returned: always + type: str + sample: '1547' +http_method: + description: Last method used to provision the content into FortiGate + returned: always + type: str + sample: 'PUT' +http_status: + description: Last result given by FortiGate on last operation applied + returned: always + type: str + sample: "200" +mkey: + description: Master key (id) used in the last call to FortiGate + returned: success + type: str + sample: "id" +name: + description: Name of the table used to fulfill the request + returned: always + type: str + sample: "urlfilter" +path: + description: Path of the table used to fulfill the request + returned: always + type: str + sample: "webfilter" +revision: + description: Internal revision number + returned: always + type: str + sample: "17.0.2.10658" +serial: + description: Serial number of the unit + returned: always + type: str + sample: "FGVMEVYYQT3AB5352" +status: + description: Indication of the operation's result + returned: always + type: str + sample: "success" +vdom: + description: Virtual domain used + returned: always + type: str + sample: "root" +version: + description: Version of the FortiGate + returned: always + type: str + sample: "v5.6.3" + +''' + +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']: + fos.https('off') + else: + fos.https('on') + + fos.login(host, username, password, verify=ssl_verify) + + +def filter_system_ha_data(json): + option_list = ['arps', 'arps_interval', 'authentication', + 'cpu_threshold', 'encryption', 'ftp_proxy_threshold', + 'gratuitous_arps', 'group_id', 'group_name', + 'ha_direct', 'ha_eth_type', 'ha_mgmt_interfaces', + 'ha_mgmt_status', 'ha_uptime_diff_margin', 'hb_interval', + 'hb_lost_threshold', 'hbdev', 'hc_eth_type', + 'hello_holddown', 'http_proxy_threshold', 'imap_proxy_threshold', + 'inter_cluster_session_sync', 'key', 'l2ep_eth_type', + 'link_failed_signal', 'load_balance_all', 'memory_compatible_mode', + 'memory_threshold', 'mode', 'monitor', + 'multicast_ttl', 'nntp_proxy_threshold', 'override', + 'override_wait_time', 'password', 'pingserver_failover_threshold', + 'pingserver_flip_timeout', 'pingserver_monitor_interface', 'pingserver_slave_force_reset', + 'pop3_proxy_threshold', 'priority', 'route_hold', + 'route_ttl', 'route_wait', 'schedule', + 'secondary_vcluster', 'session_pickup', 'session_pickup_connectionless', + 'session_pickup_delay', 'session_pickup_expectation', 'session_pickup_nat', + 'session_sync_dev', 'smtp_proxy_threshold', 'standalone_config_sync', + 'standalone_mgmt_vdom', 'sync_config', 'sync_packet_balance', + 'unicast_hb', 'unicast_hb_netmask', 'unicast_hb_peerip', + 'uninterruptible_upgrade', 'vcluster_id', 'vcluster2', + 'vdom', 'weight'] + dictionary = {} + + for attribute in option_list: + 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 system_ha(data, fos): + vdom = data['vdom'] + system_ha_data = data['system_ha'] + filtered_data = underscore_to_hyphen(filter_system_ha_data(system_ha_data)) + + return fos.set('system', + 'ha', + data=filtered_data, + vdom=vdom) + + +def is_successful_status(status): + return status['status'] == "success" or \ + status['http_method'] == "DELETE" and status['http_status'] == 404 + + +def fortios_system(data, fos): + + if data['system_ha']: + resp = system_ha(data, fos) + + return not is_successful_status(resp), \ + resp['status'] == "success", \ + resp + + +def main(): + fields = { + "host": {"required": False, "type": "str"}, + "username": {"required": False, "type": "str"}, + "password": {"required": False, "type": "str", "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}, + "system_ha": { + "required": False, "type": "dict", "default": None, + "options": { + "arps": {"required": False, "type": "int"}, + "arps_interval": {"required": False, "type": "int"}, + "authentication": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "cpu_threshold": {"required": False, "type": "str"}, + "encryption": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "ftp_proxy_threshold": {"required": False, "type": "str"}, + "gratuitous_arps": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "group_id": {"required": False, "type": "int"}, + "group_name": {"required": False, "type": "str"}, + "ha_direct": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "ha_eth_type": {"required": False, "type": "str"}, + "ha_mgmt_interfaces": {"required": False, "type": "list", + "options": { + "dst": {"required": False, "type": "str"}, + "gateway": {"required": False, "type": "str"}, + "gateway6": {"required": False, "type": "str"}, + "id": {"required": True, "type": "int"}, + "interface": {"required": False, "type": "str"} + }}, + "ha_mgmt_status": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "ha_uptime_diff_margin": {"required": False, "type": "int"}, + "hb_interval": {"required": False, "type": "int"}, + "hb_lost_threshold": {"required": False, "type": "int"}, + "hbdev": {"required": False, "type": "str"}, + "hc_eth_type": {"required": False, "type": "str"}, + "hello_holddown": {"required": False, "type": "int"}, + "http_proxy_threshold": {"required": False, "type": "str"}, + "imap_proxy_threshold": {"required": False, "type": "str"}, + "inter_cluster_session_sync": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "key": {"required": False, "type": "str"}, + "l2ep_eth_type": {"required": False, "type": "str"}, + "link_failed_signal": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "load_balance_all": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "memory_compatible_mode": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "memory_threshold": {"required": False, "type": "str"}, + "mode": {"required": False, "type": "str", + "choices": ["standalone", "a-a", "a-p"]}, + "monitor": {"required": False, "type": "str"}, + "multicast_ttl": {"required": False, "type": "int"}, + "nntp_proxy_threshold": {"required": False, "type": "str"}, + "override": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "override_wait_time": {"required": False, "type": "int"}, + "password": {"required": False, "type": "str"}, + "pingserver_failover_threshold": {"required": False, "type": "int"}, + "pingserver_flip_timeout": {"required": False, "type": "int"}, + "pingserver_monitor_interface": {"required": False, "type": "str"}, + "pingserver_slave_force_reset": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "pop3_proxy_threshold": {"required": False, "type": "str"}, + "priority": {"required": False, "type": "int"}, + "route_hold": {"required": False, "type": "int"}, + "route_ttl": {"required": False, "type": "int"}, + "route_wait": {"required": False, "type": "int"}, + "schedule": {"required": False, "type": "str", + "choices": ["none", "hub", "leastconnection", + "round-robin", "weight-round-robin", "random", + "ip", "ipport"]}, + "secondary_vcluster": {"required": False, "type": "dict", + "options": { + "monitor": {"required": False, "type": "str"}, + "override": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "override_wait_time": {"required": False, "type": "int"}, + "pingserver_failover_threshold": {"required": False, "type": "int"}, + "pingserver_monitor_interface": {"required": False, "type": "str"}, + "pingserver_slave_force_reset": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "priority": {"required": False, "type": "int"}, + "vcluster_id": {"required": False, "type": "int"}, + "vdom": {"required": False, "type": "str"} + }}, + "session_pickup": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "session_pickup_connectionless": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "session_pickup_delay": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "session_pickup_expectation": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "session_pickup_nat": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "session_sync_dev": {"required": False, "type": "str"}, + "smtp_proxy_threshold": {"required": False, "type": "str"}, + "standalone_config_sync": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "standalone_mgmt_vdom": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "sync_config": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "sync_packet_balance": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "unicast_hb": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "unicast_hb_netmask": {"required": False, "type": "str"}, + "unicast_hb_peerip": {"required": False, "type": "str"}, + "uninterruptible_upgrade": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "vcluster_id": {"required": False, "type": "int"}, + "vcluster2": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "vdom": {"required": False, "type": "str"}, + "weight": {"required": False, "type": "str"} + + } + } + } + + module = AnsibleModule(argument_spec=fields, + supports_check_mode=False) + + legacy_mode = 'host' in module.params and module.params['host'] is not None and \ + 'username' in module.params and module.params['username'] is not None and \ + 'password' in module.params and module.params['password'] is not None + + if not legacy_mode: + if module._socket_path: + connection = Connection(module._socket_path) + fos = FortiOSHandler(connection) + + is_error, has_changed, result = fortios_system(module.params, fos) + else: + module.fail_json(**FAIL_SOCKET_MSG) + else: + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + fos = FortiOSAPI() + + login(module.params, fos) + is_error, has_changed, result = fortios_system(module.params, fos) + fos.logout() + + if not is_error: + module.exit_json(changed=has_changed, meta=result) + else: + module.fail_json(msg="Error in repo", meta=result) + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/network/fortios/test_fortios_system_ha.py b/test/units/modules/network/fortios/test_fortios_system_ha.py new file mode 100644 index 00000000000..dc2fdfbfb1b --- /dev/null +++ b/test/units/modules/network/fortios/test_fortios_system_ha.py @@ -0,0 +1,647 @@ +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <https://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +import pytest +from mock import ANY +from ansible.module_utils.network.fortios.fortios import FortiOSHandler + +try: + from ansible.modules.network.fortios import fortios_system_ha +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + + +@pytest.fixture(autouse=True) +def connection_mock(mocker): + connection_class_mock = mocker.patch('ansible.modules.network.fortios.fortios_system_ha.Connection') + return connection_class_mock + + +fos_instance = FortiOSHandler(connection_mock) + + +def test_system_ha_creation(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_ha': { + 'arps': '3', + 'arps_interval': '4', + 'authentication': 'enable', + 'cpu_threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp_proxy_threshold': 'test_value_8', + 'gratuitous_arps': 'enable', + 'group_id': '10', + 'group_name': 'test_value_11', + 'ha_direct': 'enable', + 'ha_eth_type': 'test_value_13', + 'ha_mgmt_status': 'enable', + 'ha_uptime_diff_margin': '15', + 'hb_interval': '16', + 'hb_lost_threshold': '17', + 'hbdev': 'test_value_18', + 'hc_eth_type': 'test_value_19', + 'hello_holddown': '20', + 'http_proxy_threshold': 'test_value_21', + 'imap_proxy_threshold': 'test_value_22', + 'inter_cluster_session_sync': 'enable', + 'key': 'test_value_24', + 'l2ep_eth_type': 'test_value_25', + 'link_failed_signal': 'enable', + 'load_balance_all': 'enable', + 'memory_compatible_mode': 'enable', + 'memory_threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast_ttl': '32', + 'nntp_proxy_threshold': 'test_value_33', + 'override': 'enable', + 'override_wait_time': '35', + 'password': 'test_value_36', + 'pingserver_failover_threshold': '37', + 'pingserver_flip_timeout': '38', + 'pingserver_monitor_interface': 'test_value_39', + 'pingserver_slave_force_reset': 'enable', + 'pop3_proxy_threshold': 'test_value_41', + 'priority': '42', + 'route_hold': '43', + 'route_ttl': '44', + 'route_wait': '45', + 'schedule': 'none', + 'session_pickup': 'enable', + 'session_pickup_connectionless': 'enable', + 'session_pickup_delay': 'enable', + 'session_pickup_expectation': 'enable', + 'session_pickup_nat': 'enable', + 'session_sync_dev': 'test_value_52', + 'smtp_proxy_threshold': 'test_value_53', + 'standalone_config_sync': 'enable', + 'standalone_mgmt_vdom': 'enable', + 'sync_config': 'enable', + 'sync_packet_balance': 'enable', + 'unicast_hb': 'enable', + 'unicast_hb_netmask': 'test_value_59', + 'unicast_hb_peerip': 'test_value_60', + 'uninterruptible_upgrade': 'enable', + 'vcluster_id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_ha.fortios_system(input_data, fos_instance) + + expected_data = { + 'arps': '3', + 'arps-interval': '4', + 'authentication': 'enable', + 'cpu-threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp-proxy-threshold': 'test_value_8', + 'gratuitous-arps': 'enable', + 'group-id': '10', + 'group-name': 'test_value_11', + 'ha-direct': 'enable', + 'ha-eth-type': 'test_value_13', + 'ha-mgmt-status': 'enable', + 'ha-uptime-diff-margin': '15', + 'hb-interval': '16', + 'hb-lost-threshold': '17', + 'hbdev': 'test_value_18', + 'hc-eth-type': 'test_value_19', + 'hello-holddown': '20', + 'http-proxy-threshold': 'test_value_21', + 'imap-proxy-threshold': 'test_value_22', + 'inter-cluster-session-sync': 'enable', + 'key': 'test_value_24', + 'l2ep-eth-type': 'test_value_25', + 'link-failed-signal': 'enable', + 'load-balance-all': 'enable', + 'memory-compatible-mode': 'enable', + 'memory-threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast-ttl': '32', + 'nntp-proxy-threshold': 'test_value_33', + 'override': 'enable', + 'override-wait-time': '35', + 'password': 'test_value_36', + 'pingserver-failover-threshold': '37', + 'pingserver-flip-timeout': '38', + 'pingserver-monitor-interface': 'test_value_39', + 'pingserver-slave-force-reset': 'enable', + 'pop3-proxy-threshold': 'test_value_41', + 'priority': '42', + 'route-hold': '43', + 'route-ttl': '44', + 'route-wait': '45', + 'schedule': 'none', + 'session-pickup': 'enable', + 'session-pickup-connectionless': 'enable', + 'session-pickup-delay': 'enable', + 'session-pickup-expectation': 'enable', + 'session-pickup-nat': 'enable', + 'session-sync-dev': 'test_value_52', + 'smtp-proxy-threshold': 'test_value_53', + 'standalone-config-sync': 'enable', + 'standalone-mgmt-vdom': 'enable', + 'sync-config': 'enable', + 'sync-packet-balance': 'enable', + 'unicast-hb': 'enable', + 'unicast-hb-netmask': 'test_value_59', + 'unicast-hb-peerip': 'test_value_60', + 'uninterruptible-upgrade': 'enable', + 'vcluster-id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + } + + set_method_mock.assert_called_with('system', 'ha', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert changed + assert response['status'] == 'success' + assert response['http_status'] == 200 + + +def test_system_ha_creation_fails(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'POST', 'http_status': 500} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_ha': { + 'arps': '3', + 'arps_interval': '4', + 'authentication': 'enable', + 'cpu_threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp_proxy_threshold': 'test_value_8', + 'gratuitous_arps': 'enable', + 'group_id': '10', + 'group_name': 'test_value_11', + 'ha_direct': 'enable', + 'ha_eth_type': 'test_value_13', + 'ha_mgmt_status': 'enable', + 'ha_uptime_diff_margin': '15', + 'hb_interval': '16', + 'hb_lost_threshold': '17', + 'hbdev': 'test_value_18', + 'hc_eth_type': 'test_value_19', + 'hello_holddown': '20', + 'http_proxy_threshold': 'test_value_21', + 'imap_proxy_threshold': 'test_value_22', + 'inter_cluster_session_sync': 'enable', + 'key': 'test_value_24', + 'l2ep_eth_type': 'test_value_25', + 'link_failed_signal': 'enable', + 'load_balance_all': 'enable', + 'memory_compatible_mode': 'enable', + 'memory_threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast_ttl': '32', + 'nntp_proxy_threshold': 'test_value_33', + 'override': 'enable', + 'override_wait_time': '35', + 'password': 'test_value_36', + 'pingserver_failover_threshold': '37', + 'pingserver_flip_timeout': '38', + 'pingserver_monitor_interface': 'test_value_39', + 'pingserver_slave_force_reset': 'enable', + 'pop3_proxy_threshold': 'test_value_41', + 'priority': '42', + 'route_hold': '43', + 'route_ttl': '44', + 'route_wait': '45', + 'schedule': 'none', + 'session_pickup': 'enable', + 'session_pickup_connectionless': 'enable', + 'session_pickup_delay': 'enable', + 'session_pickup_expectation': 'enable', + 'session_pickup_nat': 'enable', + 'session_sync_dev': 'test_value_52', + 'smtp_proxy_threshold': 'test_value_53', + 'standalone_config_sync': 'enable', + 'standalone_mgmt_vdom': 'enable', + 'sync_config': 'enable', + 'sync_packet_balance': 'enable', + 'unicast_hb': 'enable', + 'unicast_hb_netmask': 'test_value_59', + 'unicast_hb_peerip': 'test_value_60', + 'uninterruptible_upgrade': 'enable', + 'vcluster_id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_ha.fortios_system(input_data, fos_instance) + + expected_data = { + 'arps': '3', + 'arps-interval': '4', + 'authentication': 'enable', + 'cpu-threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp-proxy-threshold': 'test_value_8', + 'gratuitous-arps': 'enable', + 'group-id': '10', + 'group-name': 'test_value_11', + 'ha-direct': 'enable', + 'ha-eth-type': 'test_value_13', + 'ha-mgmt-status': 'enable', + 'ha-uptime-diff-margin': '15', + 'hb-interval': '16', + 'hb-lost-threshold': '17', + 'hbdev': 'test_value_18', + 'hc-eth-type': 'test_value_19', + 'hello-holddown': '20', + 'http-proxy-threshold': 'test_value_21', + 'imap-proxy-threshold': 'test_value_22', + 'inter-cluster-session-sync': 'enable', + 'key': 'test_value_24', + 'l2ep-eth-type': 'test_value_25', + 'link-failed-signal': 'enable', + 'load-balance-all': 'enable', + 'memory-compatible-mode': 'enable', + 'memory-threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast-ttl': '32', + 'nntp-proxy-threshold': 'test_value_33', + 'override': 'enable', + 'override-wait-time': '35', + 'password': 'test_value_36', + 'pingserver-failover-threshold': '37', + 'pingserver-flip-timeout': '38', + 'pingserver-monitor-interface': 'test_value_39', + 'pingserver-slave-force-reset': 'enable', + 'pop3-proxy-threshold': 'test_value_41', + 'priority': '42', + 'route-hold': '43', + 'route-ttl': '44', + 'route-wait': '45', + 'schedule': 'none', + 'session-pickup': 'enable', + 'session-pickup-connectionless': 'enable', + 'session-pickup-delay': 'enable', + 'session-pickup-expectation': 'enable', + 'session-pickup-nat': 'enable', + 'session-sync-dev': 'test_value_52', + 'smtp-proxy-threshold': 'test_value_53', + 'standalone-config-sync': 'enable', + 'standalone-mgmt-vdom': 'enable', + 'sync-config': 'enable', + 'sync-packet-balance': 'enable', + 'unicast-hb': 'enable', + 'unicast-hb-netmask': 'test_value_59', + 'unicast-hb-peerip': 'test_value_60', + 'uninterruptible-upgrade': 'enable', + 'vcluster-id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + } + + set_method_mock.assert_called_with('system', 'ha', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 500 + + +def test_system_ha_idempotent(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'error', 'http_method': 'DELETE', 'http_status': 404} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_ha': { + 'arps': '3', + 'arps_interval': '4', + 'authentication': 'enable', + 'cpu_threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp_proxy_threshold': 'test_value_8', + 'gratuitous_arps': 'enable', + 'group_id': '10', + 'group_name': 'test_value_11', + 'ha_direct': 'enable', + 'ha_eth_type': 'test_value_13', + 'ha_mgmt_status': 'enable', + 'ha_uptime_diff_margin': '15', + 'hb_interval': '16', + 'hb_lost_threshold': '17', + 'hbdev': 'test_value_18', + 'hc_eth_type': 'test_value_19', + 'hello_holddown': '20', + 'http_proxy_threshold': 'test_value_21', + 'imap_proxy_threshold': 'test_value_22', + 'inter_cluster_session_sync': 'enable', + 'key': 'test_value_24', + 'l2ep_eth_type': 'test_value_25', + 'link_failed_signal': 'enable', + 'load_balance_all': 'enable', + 'memory_compatible_mode': 'enable', + 'memory_threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast_ttl': '32', + 'nntp_proxy_threshold': 'test_value_33', + 'override': 'enable', + 'override_wait_time': '35', + 'password': 'test_value_36', + 'pingserver_failover_threshold': '37', + 'pingserver_flip_timeout': '38', + 'pingserver_monitor_interface': 'test_value_39', + 'pingserver_slave_force_reset': 'enable', + 'pop3_proxy_threshold': 'test_value_41', + 'priority': '42', + 'route_hold': '43', + 'route_ttl': '44', + 'route_wait': '45', + 'schedule': 'none', + 'session_pickup': 'enable', + 'session_pickup_connectionless': 'enable', + 'session_pickup_delay': 'enable', + 'session_pickup_expectation': 'enable', + 'session_pickup_nat': 'enable', + 'session_sync_dev': 'test_value_52', + 'smtp_proxy_threshold': 'test_value_53', + 'standalone_config_sync': 'enable', + 'standalone_mgmt_vdom': 'enable', + 'sync_config': 'enable', + 'sync_packet_balance': 'enable', + 'unicast_hb': 'enable', + 'unicast_hb_netmask': 'test_value_59', + 'unicast_hb_peerip': 'test_value_60', + 'uninterruptible_upgrade': 'enable', + 'vcluster_id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_ha.fortios_system(input_data, fos_instance) + + expected_data = { + 'arps': '3', + 'arps-interval': '4', + 'authentication': 'enable', + 'cpu-threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp-proxy-threshold': 'test_value_8', + 'gratuitous-arps': 'enable', + 'group-id': '10', + 'group-name': 'test_value_11', + 'ha-direct': 'enable', + 'ha-eth-type': 'test_value_13', + 'ha-mgmt-status': 'enable', + 'ha-uptime-diff-margin': '15', + 'hb-interval': '16', + 'hb-lost-threshold': '17', + 'hbdev': 'test_value_18', + 'hc-eth-type': 'test_value_19', + 'hello-holddown': '20', + 'http-proxy-threshold': 'test_value_21', + 'imap-proxy-threshold': 'test_value_22', + 'inter-cluster-session-sync': 'enable', + 'key': 'test_value_24', + 'l2ep-eth-type': 'test_value_25', + 'link-failed-signal': 'enable', + 'load-balance-all': 'enable', + 'memory-compatible-mode': 'enable', + 'memory-threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast-ttl': '32', + 'nntp-proxy-threshold': 'test_value_33', + 'override': 'enable', + 'override-wait-time': '35', + 'password': 'test_value_36', + 'pingserver-failover-threshold': '37', + 'pingserver-flip-timeout': '38', + 'pingserver-monitor-interface': 'test_value_39', + 'pingserver-slave-force-reset': 'enable', + 'pop3-proxy-threshold': 'test_value_41', + 'priority': '42', + 'route-hold': '43', + 'route-ttl': '44', + 'route-wait': '45', + 'schedule': 'none', + 'session-pickup': 'enable', + 'session-pickup-connectionless': 'enable', + 'session-pickup-delay': 'enable', + 'session-pickup-expectation': 'enable', + 'session-pickup-nat': 'enable', + 'session-sync-dev': 'test_value_52', + 'smtp-proxy-threshold': 'test_value_53', + 'standalone-config-sync': 'enable', + 'standalone-mgmt-vdom': 'enable', + 'sync-config': 'enable', + 'sync-packet-balance': 'enable', + 'unicast-hb': 'enable', + 'unicast-hb-netmask': 'test_value_59', + 'unicast-hb-peerip': 'test_value_60', + 'uninterruptible-upgrade': 'enable', + 'vcluster-id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + } + + set_method_mock.assert_called_with('system', 'ha', data=expected_data, vdom='root') + schema_method_mock.assert_not_called() + assert not is_error + assert not changed + assert response['status'] == 'error' + assert response['http_status'] == 404 + + +def test_system_ha_filter_foreign_attributes(mocker): + schema_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.schema') + + set_method_result = {'status': 'success', 'http_method': 'POST', 'http_status': 200} + set_method_mock = mocker.patch('ansible.module_utils.network.fortios.fortios.FortiOSHandler.set', return_value=set_method_result) + + input_data = { + 'username': 'admin', + 'state': 'present', + 'system_ha': { + 'random_attribute_not_valid': 'tag', + 'arps': '3', + 'arps_interval': '4', + 'authentication': 'enable', + 'cpu_threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp_proxy_threshold': 'test_value_8', + 'gratuitous_arps': 'enable', + 'group_id': '10', + 'group_name': 'test_value_11', + 'ha_direct': 'enable', + 'ha_eth_type': 'test_value_13', + 'ha_mgmt_status': 'enable', + 'ha_uptime_diff_margin': '15', + 'hb_interval': '16', + 'hb_lost_threshold': '17', + 'hbdev': 'test_value_18', + 'hc_eth_type': 'test_value_19', + 'hello_holddown': '20', + 'http_proxy_threshold': 'test_value_21', + 'imap_proxy_threshold': 'test_value_22', + 'inter_cluster_session_sync': 'enable', + 'key': 'test_value_24', + 'l2ep_eth_type': 'test_value_25', + 'link_failed_signal': 'enable', + 'load_balance_all': 'enable', + 'memory_compatible_mode': 'enable', + 'memory_threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast_ttl': '32', + 'nntp_proxy_threshold': 'test_value_33', + 'override': 'enable', + 'override_wait_time': '35', + 'password': 'test_value_36', + 'pingserver_failover_threshold': '37', + 'pingserver_flip_timeout': '38', + 'pingserver_monitor_interface': 'test_value_39', + 'pingserver_slave_force_reset': 'enable', + 'pop3_proxy_threshold': 'test_value_41', + 'priority': '42', + 'route_hold': '43', + 'route_ttl': '44', + 'route_wait': '45', + 'schedule': 'none', + 'session_pickup': 'enable', + 'session_pickup_connectionless': 'enable', + 'session_pickup_delay': 'enable', + 'session_pickup_expectation': 'enable', + 'session_pickup_nat': 'enable', + 'session_sync_dev': 'test_value_52', + 'smtp_proxy_threshold': 'test_value_53', + 'standalone_config_sync': 'enable', + 'standalone_mgmt_vdom': 'enable', + 'sync_config': 'enable', + 'sync_packet_balance': 'enable', + 'unicast_hb': 'enable', + 'unicast_hb_netmask': 'test_value_59', + 'unicast_hb_peerip': 'test_value_60', + 'uninterruptible_upgrade': 'enable', + 'vcluster_id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + }, + 'vdom': 'root'} + + is_error, changed, response = fortios_system_ha.fortios_system(input_data, fos_instance) + + expected_data = { + 'arps': '3', + 'arps-interval': '4', + 'authentication': 'enable', + 'cpu-threshold': 'test_value_6', + 'encryption': 'enable', + 'ftp-proxy-threshold': 'test_value_8', + 'gratuitous-arps': 'enable', + 'group-id': '10', + 'group-name': 'test_value_11', + 'ha-direct': 'enable', + 'ha-eth-type': 'test_value_13', + 'ha-mgmt-status': 'enable', + 'ha-uptime-diff-margin': '15', + 'hb-interval': '16', + 'hb-lost-threshold': '17', + 'hbdev': 'test_value_18', + 'hc-eth-type': 'test_value_19', + 'hello-holddown': '20', + 'http-proxy-threshold': 'test_value_21', + 'imap-proxy-threshold': 'test_value_22', + 'inter-cluster-session-sync': 'enable', + 'key': 'test_value_24', + 'l2ep-eth-type': 'test_value_25', + 'link-failed-signal': 'enable', + 'load-balance-all': 'enable', + 'memory-compatible-mode': 'enable', + 'memory-threshold': 'test_value_29', + 'mode': 'standalone', + 'monitor': 'test_value_31', + 'multicast-ttl': '32', + 'nntp-proxy-threshold': 'test_value_33', + 'override': 'enable', + 'override-wait-time': '35', + 'password': 'test_value_36', + 'pingserver-failover-threshold': '37', + 'pingserver-flip-timeout': '38', + 'pingserver-monitor-interface': 'test_value_39', + 'pingserver-slave-force-reset': 'enable', + 'pop3-proxy-threshold': 'test_value_41', + 'priority': '42', + 'route-hold': '43', + 'route-ttl': '44', + 'route-wait': '45', + 'schedule': 'none', + 'session-pickup': 'enable', + 'session-pickup-connectionless': 'enable', + 'session-pickup-delay': 'enable', + 'session-pickup-expectation': 'enable', + 'session-pickup-nat': 'enable', + 'session-sync-dev': 'test_value_52', + 'smtp-proxy-threshold': 'test_value_53', + 'standalone-config-sync': 'enable', + 'standalone-mgmt-vdom': 'enable', + 'sync-config': 'enable', + 'sync-packet-balance': 'enable', + 'unicast-hb': 'enable', + 'unicast-hb-netmask': 'test_value_59', + 'unicast-hb-peerip': 'test_value_60', + 'uninterruptible-upgrade': 'enable', + 'vcluster-id': '62', + 'vcluster2': 'enable', + 'vdom': 'test_value_64', + 'weight': 'test_value_65' + } + + set_method_mock.assert_called_with('system', 'ha', 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